authorbors <bors@rust-lang.org> 2026-04-29 21:53:58 UTC
committerbors <bors@rust-lang.org> 2026-04-29 21:53:58 UTC
loga021a7796f66600f46013d6c8d1dfc9e8d7f4a92
tree4caaa57eb3529794ae3f4b3bf6403657930e47c2
parentc935696dd07ca51e6fba2f6579919eea2a50863b
parentd550bd5c1b87226d56dc3691e5e1d425d399b2bf

Auto merge of #155979 - JonathanBrouwer:rollup-fjLaCRP, r=JonathanBrouwer

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 = [
994994
995995[[package]]
996996name = "curl-sys"
997version = "0.4.84+curl-8.17.0"
997version = "0.4.87+curl-8.19.0"
998998source = "registry+https://github.com/rust-lang/crates.io-index"
999checksum = "abc4294dc41b882eaff37973c2ec3ae203d0091341ee68fbadd1d06e0c18a73b"
999checksum = "61a460380f0ef783703dcbe909107f39c162adeac050d73c850055118b5b6327"
10001000dependencies = [
10011001 "cc",
10021002 "libc",
......@@ -2728,9 +2728,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
27282728
27292729[[package]]
27302730name = "openssl-sys"
2731version = "0.9.111"
2731version = "0.9.114"
27322732source = "registry+https://github.com/rust-lang/crates.io-index"
2733checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
2733checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6"
27342734dependencies = [
27352735 "cc",
27362736 "libc",
compiler/rustc_ast_lowering/src/lib.rs+1-1
......@@ -765,7 +765,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
765765 let mut bodies = std::mem::take(&mut self.bodies);
766766 let define_opaque = std::mem::take(&mut self.define_opaque);
767767 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());
769769
770770 #[cfg(debug_assertions)]
771771 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(
113113 else {
114114 return Err(cx.adcx().expected_identifier(meta.path().span()));
115115 };
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)?
117117 }
118118 },
119119 MetaItemOrLitParser::Lit(lit) => match lit.kind {
......@@ -175,23 +175,16 @@ fn parse_cfg_entry_target(
175175 let mut result = ThinVec::new();
176176 for sub_item in list.mixed() {
177177 // 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 {
184179 continue;
185180 };
186181
187182 // 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 }
191186 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) {
195188 result.push(cfg);
196189 }
197190 }
compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs+1-5
......@@ -11,11 +11,7 @@ impl SingleAttributeParser for CfiEncodingParser {
1111 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
1212
1313 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))?;
1915
2016 let Some(value_str) = name_value.value_as_str() else {
2117 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 {
118118 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
119119
120120 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)?;
126122 let Some(name) = nv.value_as_str() else {
127123 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
128124 return None;
......@@ -146,11 +142,7 @@ impl SingleAttributeParser for RustcObjcClassParser {
146142 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
147143
148144 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)?;
154146 let Some(classname) = nv.value_as_str() else {
155147 // `#[rustc_objc_class = ...]` is expected to be used as an implementation detail
156148 // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
......@@ -177,11 +169,7 @@ impl SingleAttributeParser for RustcObjcSelectorParser {
177169 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
178170
179171 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)?;
185173 let Some(methname) = nv.value_as_str() else {
186174 // `#[rustc_objc_selector = ...]` is expected to be used as an implementation detail
187175 // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
......@@ -471,29 +459,20 @@ fn parse_tf_attribute(
471459 return features;
472460 }
473461 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 {
476464 return features;
477465 };
478466
479467 // 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]);
486470 return features;
487471 }
488472
489473 // 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()));
497476 return features;
498477 };
499478 for feature in value_str.as_str().split(",") {
......@@ -592,14 +571,7 @@ impl SingleAttributeParser for SanitizeParser {
592571 let mut rtsan = None;
593572
594573 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 {
603575 continue;
604576 };
605577
......@@ -628,20 +600,20 @@ impl SingleAttributeParser for SanitizeParser {
628600 }
629601 };
630602
631 match path {
632 Some(sym::address) | Some(sym::kernel_address) => {
603 match ident.name {
604 sym::address | sym::kernel_address => {
633605 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
634606 }
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 => {
642614 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
643615 }
644 Some(sym::realtime) => match value.value_as_str() {
616 sym::realtime => match value.value_as_str() {
645617 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
646618 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
647619 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
......@@ -654,7 +626,7 @@ impl SingleAttributeParser for SanitizeParser {
654626 },
655627 _ => {
656628 cx.adcx().expected_specific_argument_strings(
657 item.path().span(),
629 ident.span,
658630 &[
659631 sym::address,
660632 sym::kernel_address,
......@@ -725,33 +697,25 @@ impl SingleAttributeParser for PatchableFunctionEntryParser {
725697 let mut errored = false;
726698
727699 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 {
737701 continue;
738702 };
739703
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 => {
742706 // Duplicate prefixes are not allowed
743707 if prefix.is_some() {
744708 errored = true;
745 cx.adcx().duplicate_key(meta_item.path().span(), sym::prefix_nops);
709 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
746710 continue;
747711 }
748712 &mut prefix
749713 }
750 Some(sym::entry_nops) => {
714 sym::entry_nops => {
751715 // Duplicate entries are not allowed
752716 if entry.is_some() {
753717 errored = true;
754 cx.adcx().duplicate_key(meta_item.path().span(), sym::entry_nops);
718 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
755719 continue;
756720 }
757721 &mut entry
......@@ -759,23 +723,23 @@ impl SingleAttributeParser for PatchableFunctionEntryParser {
759723 _ => {
760724 errored = true;
761725 cx.adcx().expected_specific_argument(
762 meta_item.path().span(),
726 ident.span,
763727 &[sym::prefix_nops, sym::entry_nops],
764728 );
765729 continue;
766730 }
767731 };
768732
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 {
770734 errored = true;
771 cx.adcx().expected_integer_literal(name_value_lit.value_span);
735 cx.adcx().expected_integer_literal(value.value_span);
772736 continue;
773737 };
774738
775739 let Ok(val) = val.get().try_into() else {
776740 errored = true;
777741 cx.adcx().expected_integer_literal_in_range(
778 name_value_lit.value_span,
742 value.value_span,
779743 u8::MIN as isize,
780744 u8::MAX as isize,
781745 );
compiler/rustc_attr_parsing/src/attributes/crate_level.rs+7-38
......@@ -16,11 +16,7 @@ impl SingleAttributeParser for CrateNameParser {
1616 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
1717
1818 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)?;
2420
2521 let Some(name) = n.value_as_str() else {
2622 cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit()));
......@@ -47,11 +43,7 @@ impl CombineAttributeParser for CrateTypeParser {
4743 cx: &mut AcceptContext<'_, '_>,
4844 args: &ArgParser,
4945 ) -> 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)?;
5547
5648 let Some(crate_type) = n.value_as_str() else {
5749 cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit()));
......@@ -95,11 +87,7 @@ impl SingleAttributeParser for RecursionLimitParser {
9587 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
9688
9789 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)?;
10391
10492 Some(AttributeKind::RecursionLimit {
10593 limit: cx.parse_limit_int(nv)?,
......@@ -117,11 +105,7 @@ impl SingleAttributeParser for MoveSizeLimitParser {
117105 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
118106
119107 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)?;
125109
126110 Some(AttributeKind::MoveSizeLimit {
127111 limit: cx.parse_limit_int(nv)?,
......@@ -140,11 +124,7 @@ impl SingleAttributeParser for TypeLengthLimitParser {
140124 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
141125
142126 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)?;
148128
149129 Some(AttributeKind::TypeLengthLimit {
150130 limit: cx.parse_limit_int(nv)?,
......@@ -162,11 +142,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser {
162142 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
163143
164144 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)?;
170146
171147 Some(AttributeKind::PatternComplexityLimit {
172148 limit: cx.parse_limit_int(nv)?,
......@@ -219,14 +195,7 @@ impl SingleAttributeParser for WindowsSubsystemParser {
219195 const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
220196
221197 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))?;
230199
231200 let kind = match nv.value_as_str() {
232201 Some(sym::console) => WindowsSubsystemKind::Console,
compiler/rustc_attr_parsing/src/attributes/debugger.rs+8-17
......@@ -21,33 +21,24 @@ impl CombineAttributeParser for DebuggerViualizerParser {
2121 args: &ArgParser,
2222 ) -> impl IntoIterator<Item = Self::Item> {
2323 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,
3228 _ => {
3329 cx.adcx().expected_specific_argument(
34 mi.path().span(),
30 ident.span,
3531 &[sym::natvis_file, sym::gdb_script_file],
3632 );
3733 return None;
3834 }
3935 };
4036
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()));
4839 return None;
4940 };
5041
51 Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
42 Some(DebugVisualizer { span: ident.span.to(args.value_span), visualizer_type, path })
5243 }
5344}
compiler/rustc_attr_parsing/src/attributes/deprecation.rs+4-8
......@@ -18,15 +18,11 @@ fn get(
1818 cx.adcx().duplicate_key(param_span, name);
1919 return None;
2020 }
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)
2824 } 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()));
3026 None
3127 }
3228}
compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs+1-1
......@@ -270,7 +270,7 @@ fn parse_directive_items<'p>(
270270 // But we don't assert its presence yet because we don't want to mention it
271271 // if someone does something like `#[diagnostic::on_unimplemented(doesnt_exist)]`.
272272 // 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() {
274274 Some(nv) => Some(or_malformed!(nv.value_as_ident()?)),
275275 None => None,
276276 };
compiler/rustc_attr_parsing/src/attributes/doc.rs+5-5
......@@ -113,7 +113,7 @@ fn parse_keyword_and_attribute(
113113 attr_value: &mut Option<(Symbol, Span)>,
114114 attr_name: Symbol,
115115) {
116 let Some(nv) = args.name_value() else {
116 let Some(nv) = args.as_name_value() else {
117117 expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
118118 return;
119119 };
......@@ -397,7 +397,7 @@ impl DocParser {
397397 super::cfg::parse_name_value(
398398 name,
399399 sub_item.path().span(),
400 a.name_value(),
400 a.as_name_value(),
401401 sub_item.span(),
402402 cx,
403403 )
......@@ -408,7 +408,7 @@ impl DocParser {
408408 // If `value` is `Some`, `a.name_value()` will always return
409409 // `Some` as well.
410410 value: value
411 .map(|v| (v, a.name_value().unwrap().value_span)),
411 .map(|v| (v, a.as_name_value().unwrap().value_span)),
412412 })
413413 }
414414 }
......@@ -498,7 +498,7 @@ impl DocParser {
498498 }
499499 macro_rules! string_arg_and_crate_level {
500500 ($ident: ident) => {{
501 let Some(nv) = args.name_value() else {
501 let Some(nv) = args.as_name_value() else {
502502 expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
503503 return;
504504 };
......@@ -605,7 +605,7 @@ impl DocParser {
605605 span,
606606 );
607607 }
608 Some(sym::include) if let Some(nv) = args.name_value() => {
608 Some(sym::include) if let Some(nv) = args.as_name_value() => {
609609 let inner = match cx.attr_style {
610610 AttrStyle::Outer => "",
611611 AttrStyle::Inner => "!",
compiler/rustc_attr_parsing/src/attributes/link_attrs.rs+16-30
......@@ -36,11 +36,7 @@ impl SingleAttributeParser for LinkNameParser {
3636 );
3737
3838 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)?;
4440 let Some(name) = nv.value_as_str() else {
4541 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
4642 return None;
......@@ -261,12 +257,11 @@ impl LinkParser {
261257 cx.adcx().duplicate_key(item.span(), sym::name);
262258 return true;
263259 }
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 {
266261 return false;
267262 };
268263 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()));
270265 return false;
271266 };
272267
......@@ -288,12 +283,11 @@ impl LinkParser {
288283 cx.adcx().duplicate_key(item.span(), sym::kind);
289284 return true;
290285 }
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 {
293287 return true;
294288 };
295289 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()));
297291 return true;
298292 };
299293
......@@ -368,12 +362,11 @@ impl LinkParser {
368362 cx.adcx().duplicate_key(item.span(), sym::modifiers);
369363 return true;
370364 }
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 {
373366 return true;
374367 };
375368 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()));
377370 return true;
378371 };
379372 *modifiers = Some((link_modifiers, nv.value_span));
......@@ -410,12 +403,13 @@ impl LinkParser {
410403 cx.adcx().duplicate_key(item.span(), sym::wasm_import_module);
411404 return true;
412405 }
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 {
415409 return true;
416410 };
417411 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()));
419413 return true;
420414 };
421415 *wasm_import_module = Some((link_wasm_import_module, item.span()));
......@@ -431,12 +425,12 @@ impl LinkParser {
431425 cx.adcx().duplicate_key(item.span(), sym::import_name_type);
432426 return true;
433427 }
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 {
436430 return true;
437431 };
438432 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()));
440434 return true;
441435 };
442436 if cx.sess().target.arch != Arch::X86 {
......@@ -503,11 +497,7 @@ impl SingleAttributeParser for LinkSectionParser {
503497 );
504498
505499 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)?;
511501 let Some(name) = nv.value_as_str() else {
512502 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
513503 return None;
......@@ -638,11 +628,7 @@ impl SingleAttributeParser for LinkageParser {
638628 ]);
639629
640630 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))?;
646632
647633 let Some(value) = name_value.value_as_str() else {
648634 cx.adcx()
compiler/rustc_attr_parsing/src/attributes/path.rs+1-5
......@@ -13,11 +13,7 @@ impl SingleAttributeParser for PathParser {
1313 );
1414
1515 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)?;
2117 let Some(path) = nv.value_as_str() else {
2218 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
2319 return None;
compiler/rustc_attr_parsing/src/attributes/prototype.rs+15-21
......@@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol, sym};
77
88use crate::attributes::SingleAttributeParser;
99use crate::context::AcceptContext;
10use crate::parser::ArgParser;
10use crate::parser::{ArgParser, NameValueParser};
1111use crate::session_diagnostics;
1212use crate::target_checking::AllowedTargets;
1313use crate::target_checking::Policy::Allow;
......@@ -29,23 +29,23 @@ impl SingleAttributeParser for CustomMirParser {
2929 let mut failed = false;
3030
3131 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 {
3433 failed = true;
3534 break;
3635 };
3736
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 }
4949 }
5050
5151 let dialect = parse_dialect(cx, dialect, &mut failed);
......@@ -63,7 +63,7 @@ impl SingleAttributeParser for CustomMirParser {
6363fn extract_value(
6464 cx: &mut AcceptContext<'_, '_>,
6565 key: Symbol,
66 arg: &ArgParser,
66 val: &NameValueParser,
6767 span: Span,
6868 out_val: &mut Option<(Symbol, Span)>,
6969 failed: &mut bool,
......@@ -74,12 +74,6 @@ fn extract_value(
7474 return;
7575 }
7676
77 let Some(val) = arg.name_value() else {
78 cx.adcx().expected_name_value(span, Some(key));
79 *failed = true;
80 return;
81 };
82
8377 let Some(value_sym) = val.value_as_str() else {
8478 cx.adcx().expected_string_literal(val.value_span, Some(val.value_as_lit()));
8579 *failed = true;
compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs+3-3
......@@ -26,9 +26,9 @@ impl SingleAttributeParser for RustcAllocatorZeroedVariantParser {
2626 AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
2727 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
2828 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()));
3232 return None;
3333 };
3434
compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs+42-90
......@@ -209,18 +209,17 @@ fn parse_cgu_fields(
209209 let mut kind = None::<(Symbol, Span)>;
210210
211211 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 {
214213 continue;
215214 };
216215
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,
221220 _ => {
222221 cx.adcx().expected_specific_argument(
223 arg.path().span(),
222 ident.span,
224223 if accepts_kind {
225224 &[sym::cfg, sym::module, sym::kind]
226225 } else {
......@@ -231,22 +230,17 @@ fn parse_cgu_fields(
231230 }
232231 };
233232
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()));
241235 continue;
242236 };
243237
244238 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);
246240 continue;
247241 }
248242
249 *res = Some((str, i.value_span));
243 *res = Some((str, arg.value_span));
250244 }
251245
252246 let Some((cfg, _)) = cfg else {
......@@ -349,23 +343,15 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {
349343 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
350344 let single = cx.expect_single_element_list(args, cx.attr_span)?;
351345
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)?;
361347
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]);
364350 return None;
365351 };
366352
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()));
369355 return None;
370356 };
371357
......@@ -412,39 +398,33 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser {
412398 let mut diverging_block_default = None::<Ident>;
413399
414400 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 {
417402 continue;
418403 };
419404
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,
423408 _ => {
424409 cx.adcx().expected_specific_argument(
425 meta.path().span(),
410 ident.span,
426411 &[sym::fallback, sym::diverging_block_default],
427412 );
428413 continue;
429414 }
430415 };
431416
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()));
439419 continue;
440420 };
441421
442422 if res.is_some() {
443 cx.adcx().duplicate_key(meta.span(), meta.ident().unwrap().name);
423 cx.adcx().duplicate_key(ident.span, ident.name);
444424 continue;
445425 }
446426
447 *res = Some(Ident { name: field, span: nv.value_span });
427 *res = Some(Ident { name: field, span: arg.value_span });
448428 }
449429
450430 let fallback = match fallback {
......@@ -562,11 +542,7 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {
562542 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
563543
564544 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)?;
570546 Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
571547 }
572548}
......@@ -603,11 +579,7 @@ impl SingleAttributeParser for LangParser {
603579 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
604580
605581 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)?;
611583 let Some(name) = nv.value_as_str() else {
612584 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
613585 return None;
......@@ -701,13 +673,11 @@ impl CombineAttributeParser for RustcMirParser {
701673 sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),
702674 sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),
703675 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 )?;
711681 let Some(path) = nv.value_as_str() else {
712682 cx.adcx().expected_string_literal(nv.value_span, None);
713683 return None;
......@@ -721,13 +691,11 @@ impl CombineAttributeParser for RustcMirParser {
721691 }
722692 }
723693 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 )?;
731699 let Some(format) = nv.value_as_ident() else {
732700 cx.adcx().expected_identifier(nv.value_span);
733701 return None;
......@@ -814,10 +782,7 @@ impl CombineAttributeParser for RustcCleanParser {
814782 let mut cfg = None;
815783
816784 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 {
821786 continue;
822787 };
823788 let value_span = value.value_span;
......@@ -825,11 +790,10 @@ impl CombineAttributeParser for RustcCleanParser {
825790 cx.adcx().expected_string_literal(value_span, None);
826791 continue;
827792 };
828 match name.name {
793 match ident.name {
829794 sym::cfg if cfg.is_some() => {
830795 cx.adcx().duplicate_key(item.span(), sym::cfg);
831796 }
832
833797 sym::cfg => {
834798 cfg = Some(value);
835799 }
......@@ -851,7 +815,7 @@ impl CombineAttributeParser for RustcCleanParser {
851815 }
852816 _ => {
853817 cx.adcx().expected_specific_argument(
854 name.span,
818 ident.span,
855819 &[sym::cfg, sym::except, sym::loaded_from_disk],
856820 );
857821 }
......@@ -1047,11 +1011,7 @@ impl SingleAttributeParser for RustcDiagnosticItemParser {
10471011 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
10481012
10491013 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)?;
10551015 let Some(value) = nv.value_as_str() else {
10561016 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
10571017 return None;
......@@ -1106,11 +1066,7 @@ impl SingleAttributeParser for RustcReservationImplParser {
11061066 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message");
11071067
11081068 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)?;
11141070
11151071 let Some(value_str) = nv.value_as_str() else {
11161072 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
......@@ -1137,11 +1093,7 @@ impl SingleAttributeParser for RustcDocPrimitiveParser {
11371093 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
11381094
11391095 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)?;
11451097
11461098 let Some(value_str) = nv.value_as_str() else {
11471099 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 {
102102 template!(NameValueStr: "deprecation message"),
103103 |this, cx, args| {
104104 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 {
108106 return;
109107 };
110108 let Some(value_str) = nv.value_as_str() else {
......@@ -290,16 +288,19 @@ fn insert_value_into_option_or_error(
290288) -> Option<()> {
291289 if item.is_some() {
292290 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;
302292 }
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(())
303304}
304305
305306/// 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(
409410 session_diagnostics::InvalidIssueString {
410411 span: param.span(),
411412 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,
413414 err.kind(),
414415 ),
415416 },
compiler/rustc_attr_parsing/src/attributes/test_attrs.rs+11-24
......@@ -73,20 +73,14 @@ impl SingleAttributeParser for ShouldPanicParser {
7373 }
7474 ArgParser::List(list) => {
7575 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 {
8179 cx.adcx().expected_specific_argument_strings(list.span, &[sym::expected]);
8280 return None;
8381 }
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()));
9084 return None;
9185 };
9286 Some(expected)
......@@ -104,14 +98,11 @@ impl SingleAttributeParser for ReexportTestHarnessMainParser {
10498 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
10599
106100 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 )?;
115106
116107 let Some(name) = nv.value_as_str() else {
117108 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
......@@ -220,11 +211,7 @@ impl SingleAttributeParser for RustcTestMarkerParser {
220211 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path");
221212
222213 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))?;
228215
229216 let Some(value_str) = name_value.value_as_str() else {
230217 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 {
1414 template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
1515
1616 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)?;
2218 match nv.value_as_str() {
2319 Some(sym::transparent) => Some(Transparency::Transparent),
2420 Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
compiler/rustc_attr_parsing/src/context.rs+126-10
......@@ -14,7 +14,7 @@ use rustc_hir::attrs::AttributeKind;
1414use rustc_parse::parser::Recovery;
1515use rustc_session::Session;
1616use rustc_session::lint::{Lint, LintId};
17use rustc_span::{ErrorGuaranteed, Span, Symbol};
17use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
1818
1919// Glob imports to avoid big, bitrotty import lists
2020use crate::attributes::allow_unstable::*;
......@@ -59,7 +59,10 @@ use crate::attributes::test_attrs::*;
5959use crate::attributes::traits::*;
6060use crate::attributes::transparency::*;
6161use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
62use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, RefPathParser};
62use crate::parser::{
63 ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, NameValueParser,
64 RefPathParser,
65};
6366use crate::session_diagnostics::{
6467 AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
6568 ParsedDescription,
......@@ -490,7 +493,7 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> {
490493 /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list
491494 /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list
492495 ///
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
494497 /// allows using `?` when the attribute parsing function allows it. You may still want to use
495498 /// [`ArgParser::as_list`] for the following reasons:
496499 ///
......@@ -511,8 +514,8 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> {
511514 /// Asserts that a [`MetaItemListParser`] contains a single element and returns it, or emits an
512515 /// error and returns `None`.
513516 ///
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
516519 /// [`MetaItemListParser::as_single`] for the following reasons:
517520 ///
518521 /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]).
......@@ -527,6 +530,123 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> {
527530 }
528531 single
529532 }
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
575pub(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
588impl 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
606impl 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
634impl 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 }
530650}
531651
532652impl<'f, 'sess> Deref for AcceptContext<'f, 'sess> {
......@@ -751,11 +871,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> {
751871
752872 /// Emit an error that a `name = value` pair was expected at this span. The symbol can be given for
753873 /// 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 {
759875 self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name))
760876 }
761877
compiler/rustc_attr_parsing/src/parser.rs+4-3
......@@ -192,7 +192,7 @@ impl ArgParser {
192192 /// to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is
193193 /// there
194194 /// - `#[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> {
196196 match self {
197197 Self::NameValue(n) => Some(n),
198198 Self::List(_) | Self::NoArgs => None,
......@@ -264,8 +264,9 @@ impl MetaItemOrLitParser {
264264/// MetaItems consist of some path, and some args. The args could be empty. In other words:
265265///
266266/// - `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
269270/// `= value` part
270271///
271272/// 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;
44use hir::{ExprKind, Param};
55use rustc_abi::FieldIdx;
66use rustc_errors::{Applicability, Diag};
7use rustc_hir::def_id::DefId;
78use rustc_hir::intravisit::Visitor;
89use rustc_hir::{self as hir, BindingMode, ByRef, Node};
910use rustc_middle::bug;
......@@ -1092,42 +1093,65 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10921093 let mut look_at_return = true;
10931094
10941095 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 })
11001117 };
11011118
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 };
11031126
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 }
11121139 }
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,
11131147 }
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 };
11201149
11211150 // If we can detect the expression to be a function or method call where the closure was
11221151 // 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 {
11311155 let arg = match tcx.hir_get_if_local(callee_def_id) {
11321156 Some(
11331157 hir::Node::Item(hir::Item {
......@@ -1144,16 +1168,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11441168 ..
11451169 }),
11461170 ) => 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 )
11571177 .map(|arg| arg.span)
11581178 .unwrap_or(ident.span),
11591179 ),
......@@ -1163,6 +1183,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11631183 err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
11641184 err.span_label(call_span, "expects `Fn` instead of `FnMut`");
11651185 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;
11661193 }
11671194 }
11681195
compiler/rustc_borrowck/src/diagnostics/region_errors.rs+3-2
......@@ -1085,8 +1085,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
10851085 }
10861086
10871087 // 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());
10901091 let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr(
10911092 tcx,
10921093 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> {
23132313 self.vector_extremum(a, b, ExtremumOperation::Min)
23142314 }
23152315
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
23442316 pub fn vector_maximum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
23452317 self.vector_extremum(a, b, ExtremumOperation::Max)
23462318 }
23472319
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
23772320 pub fn vector_select(
23782321 &mut self,
23792322 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>(
14221422 );
14231423
14241424 macro_rules! minmax_red {
1425 ($name:ident: $int_red:ident, $float_red:ident) => {
1425 ($name:ident: $int_red:ident) => {
14261426 if name == sym::$name {
14271427 require!(
14281428 ret_ty == in_elem,
......@@ -1430,7 +1430,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
14301430 );
14311431 return match *in_elem.kind() {
14321432 ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())),
1433 ty::Float(_) => Ok(bx.$float_red(args[0].immediate())),
14341433 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
14351434 span,
14361435 name,
......@@ -1444,8 +1443,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
14441443 };
14451444 }
14461445
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);
14491448
14501449 macro_rules! bitwise_red {
14511450 ($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> {
16681668 pub(crate) fn vector_reduce_xor(&mut self, src: &'ll Value) -> &'ll Value {
16691669 self.call_intrinsic("llvm.vector.reduce.xor", &[self.val_ty(src)], &[src])
16701670 }
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 }
16771671 pub(crate) fn vector_reduce_min(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value {
16781672 self.call_intrinsic(
16791673 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>(
29222922 );
29232923
29242924 macro_rules! minmax_red {
2925 ($name:ident: $int_red:ident, $float_red:ident) => {
2925 ($name:ident: $int_red:ident) => {
29262926 if name == sym::$name {
29272927 require!(
29282928 ret_ty == in_elem,
......@@ -2931,7 +2931,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
29312931 return match in_elem.kind() {
29322932 ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
29332933 ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
2934 ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
29352934 _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
29362935 span,
29372936 name,
......@@ -2945,8 +2944,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
29452944 };
29462945 }
29472946
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);
29502950
29512951 macro_rules! bitwise_red {
29522952 ($name:ident : $red:ident, $boolean:expr) => {
compiler/rustc_codegen_ssa/src/back/archive.rs+82-11
......@@ -9,7 +9,7 @@ use ar_archive_writer::{
99 ArchiveKind, COFFShortExport, MachineTypes, NewArchiveMember, write_archive_to_stream,
1010};
1111pub use ar_archive_writer::{DEFAULT_OBJECT_READER, ObjectReader};
12use object::read::archive::ArchiveFile;
12use object::read::archive::{ArchiveFile, ArchiveKind as ObjectArchiveKind};
1313use object::read::macho::FatArch;
1414use rustc_data_structures::fx::FxIndexSet;
1515use rustc_data_structures::memmap::Mmap;
......@@ -217,12 +217,10 @@ fn create_mingw_dll_import_lib(
217217 // able to control the *exact* spelling of each of the symbols that are being imported:
218218 // hence we don't want `dlltool` adding leading underscores automatically.
219219 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;
226224 // dlltool target architecture args from:
227225 // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
228226 let (dlltool_target_arch, dlltool_target_bitness) = match &sess.target.arch {
......@@ -246,7 +244,8 @@ fn create_mingw_dll_import_lib(
246244 .arg(dlltool_target_bitness)
247245 .arg("--no-leading-underscore")
248246 .arg("--temp-prefix")
249 .arg(temp_prefix);
247 .arg(temp_prefix)
248 .current_dir(cwd);
250249
251250 match dlltool_cmd.output() {
252251 Err(e) => {
......@@ -320,6 +319,50 @@ pub trait ArchiveBuilder {
320319 fn build(self: Box<Self>, output: &Path) -> bool;
321320}
322321
322fn 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
333fn 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
355fn 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
323366pub struct ArArchiveBuilderBuilder;
324367
325368impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
......@@ -420,6 +463,19 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
420463 .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
421464 let archive_index = self.src_archives.len();
422465
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
423479 for entry in archive.members() {
424480 let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
425481 let file_name = String::from_utf8(entry.name().to_vec())
......@@ -482,9 +538,24 @@ impl<'a> ArArchiveBuilder<'a> {
482538 match entry {
483539 ArchiveEntry::FromArchive { archive_index, file_range } => {
484540 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 };
488559
489560 Box::new(data) as Box<dyn AsRef<[u8]>>
490561 }
compiler/rustc_codegen_ssa/src/errors.rs+12
......@@ -677,6 +677,18 @@ pub(crate) struct UnknownArchiveKind<'a> {
677677 pub kind: &'a str,
678678}
679679
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)]
686pub(crate) struct IncompatibleArchiveFormat {
687 pub path: PathBuf,
688 pub actual: String,
689 pub expected: String,
690}
691
680692#[derive(Diagnostic)]
681693#[diag("linking static libraries is not supported for BPF")]
682694pub(crate) struct BpfStaticlibNotSupported;
compiler/rustc_const_eval/src/interpret/intrinsics.rs+150-14
......@@ -8,6 +8,7 @@ use std::assert_matches;
88
99use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx};
1010use rustc_apfloat::ieee::{Double, Half, Quad, Single};
11use rustc_ast::{IntTy, UintTy};
1112use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
1213use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
1314use rustc_middle::ty::layout::TyAndLayout;
......@@ -21,9 +22,9 @@ use super::util::ensure_monomorphic_enough;
2122use super::{
2223 AllocId, CheckInAllocMsg, ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Pointer,
2324 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,
2526};
26use crate::interpret::Writeable;
27use crate::interpret::{MPlaceTy, Writeable};
2728
2829#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2930enum MulAddType {
......@@ -56,6 +57,22 @@ pub(crate) enum MinMax {
5657 MaximumNumberNsz,
5758}
5859
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`.
62enum 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
5976/// Directly returns an `Allocation` containing an absolute path representation of the given type.
6077pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) {
6178 let path = crate::util::type_name(tcx, ty);
......@@ -739,18 +756,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
739756 throw_ub!(VaArgOutOfBounds);
740757 };
741758
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)?;
754766
755767 // Update the VaList pointer.
756768 let new_key = self.va_list_ptr(varargs);
......@@ -766,6 +778,130 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
766778 interp_ok(true)
767779 }
768780
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
769905 pub(super) fn eval_nondiverging_intrinsic(
770906 &mut self,
771907 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 {
6767 }
6868}
6969
70// A vec-like type must implement these operations to support `flat_map_in_place`.
71pub 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.
76pub unsafe trait FlatMapInPlaceVec {
7277 type Elem;
7378
7479 fn len(&self) -> usize;
......@@ -78,7 +83,7 @@ pub trait FlatMapInPlaceVec {
7883 fn insert(&mut self, idx: usize, elem: Self::Elem);
7984}
8085
81impl<T> FlatMapInPlaceVec for Vec<T> {
86unsafe impl<T> FlatMapInPlaceVec for Vec<T> {
8287 type Elem = T;
8388
8489 fn len(&self) -> usize {
......@@ -104,7 +109,7 @@ impl<T> FlatMapInPlaceVec for Vec<T> {
104109 }
105110}
106111
107impl<T> FlatMapInPlaceVec for ThinVec<T> {
112unsafe impl<T> FlatMapInPlaceVec for ThinVec<T> {
108113 type Elem = T;
109114
110115 fn len(&self) -> usize {
......@@ -130,7 +135,7 @@ impl<T> FlatMapInPlaceVec for ThinVec<T> {
130135 }
131136}
132137
133impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> {
138unsafe impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> {
134139 type Elem = T;
135140
136141 fn len(&self) -> usize {
compiler/rustc_hir/src/hir.rs+2-1
......@@ -18,6 +18,7 @@ pub use rustc_ast::{
1818};
1919use rustc_data_structures::fingerprint::Fingerprint;
2020use rustc_data_structures::sorted_map::SortedMap;
21use rustc_data_structures::steal::Steal;
2122use rustc_data_structures::tagged_ptr::TaggedRef;
2223use rustc_error_messages::{DiagArgValue, IntoDiagArg};
2324use rustc_index::IndexVec;
......@@ -1636,7 +1637,7 @@ pub struct OwnerInfo<'hir> {
16361637 /// WARNING: The delayed lints are not hashed as a part of the `OwnerInfo`, and therefore
16371638 /// should only be accessed in `eval_always` queries.
16381639 #[stable_hasher(ignore)]
1639 pub delayed_lints: DelayedLints,
1640 pub delayed_lints: Steal<DelayedLints>,
16401641}
16411642
16421643impl<'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>(
217217 unreachable!()
218218 };
219219 let field_ty = eff.trait_ref.self_ty();
220 let diag = struct_span_code_err!(
220 let mut diag = struct_span_code_err!(
221221 tcx.dcx(),
222222 error.root_obligation.cause.span,
223223 E0367,
224224 "`{field_ty}` does not implement `[const] Destruct`",
225225 )
226226 .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 );
230240 }
231241 Err(diag.emit())
232242 })
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+1-1
......@@ -3590,7 +3590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
35903590
35913591 let fn_sig_kind = FnSigKind::default()
35923592 .set_abi(abi)
3593 .set_safe(safety.is_safe())
3593 .set_safety(safety)
35943594 .set_c_variadic(decl.fn_decl_kind.c_variadic());
35953595 let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, fn_sig_kind);
35963596 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> {
723723 let bound_sig = expected_sig.sig.map_bound(|sig| {
724724 let fn_sig_kind = FnSigKind::default()
725725 .set_abi(ExternAbi::RustCall)
726 .set_safe(true)
726 .set_safety(hir::Safety::Safe)
727727 .set_c_variadic(sig.c_variadic());
728728 self.tcx.mk_fn_sig(sig.inputs().iter().cloned(), sig.output(), fn_sig_kind)
729729 });
......@@ -860,7 +860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
860860
861861 let fn_sig_kind = FnSigKind::default()
862862 .set_abi(ExternAbi::RustCall)
863 .set_safe(true)
863 .set_safety(hir::Safety::Safe)
864864 .set_c_variadic(expected_sigs.liberated_sig.c_variadic());
865865 expected_sigs.liberated_sig =
866866 self.tcx.mk_fn_sig(inputs, supplied_output_ty, fn_sig_kind);
......@@ -935,7 +935,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
935935
936936 let fn_sig_kind = FnSigKind::default()
937937 .set_abi(ExternAbi::RustCall)
938 .set_safe(true)
938 .set_safety(hir::Safety::Safe)
939939 .set_c_variadic(decl.c_variadic());
940940 let result = ty::Binder::bind_with_vars(
941941 self.tcx.mk_fn_sig(supplied_arguments, supplied_return, fn_sig_kind),
......@@ -1098,7 +1098,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10981098
10991099 let fn_sig_kind = FnSigKind::default()
11001100 .set_abi(ExternAbi::RustCall)
1101 .set_safe(true)
1101 .set_safety(hir::Safety::Safe)
11021102 .set_c_variadic(decl.c_variadic());
11031103 let result = ty::Binder::dummy(self.tcx.mk_fn_sig(supplied_arguments, err_ty, fn_sig_kind));
11041104
compiler/rustc_interface/src/passes.rs+2-2
......@@ -1041,7 +1041,7 @@ impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for DiagCallback<'b, 'tcx> {
10411041pub fn emit_delayed_lints(tcx: TyCtxt<'_>) {
10421042 for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
10431043 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() {
10451045 tcx.emit_node_span_lint(
10461046 lint.lint_id.lint,
10471047 lint.id,
......@@ -1117,7 +1117,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
11171117 let hir_items = tcx.hir_crate_items(());
11181118 for owner_id in hir_items.owners() {
11191119 if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id)
1120 && !delayed_lints.is_empty()
1120 && !delayed_lints.borrow().is_empty()
11211121 {
11221122 // Assert that delayed_lint_items also picked up this item to have lints.
11231123 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;
88use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
99use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1010use rustc_hir::def::DefKind;
11use rustc_hir::{ItemKind, Node, UseKind};
1112use rustc_macros::HashStable;
1213use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
1314
......@@ -185,13 +186,20 @@ impl EffectiveVisibilities {
185186 if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() {
186187 let nominal_vis = tcx.visibility(def_id);
187188 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 }
195203 }
196204 }
197205 }
......@@ -207,12 +215,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
207215 self.map.get(&id)
208216 }
209217
210 // FIXME: Share code with `fn update`.
211218 pub fn effective_vis_or_private(
212219 &mut self,
213220 id: Id,
214221 lazy_private_vis: impl FnOnce() -> Visibility,
215 ) -> &EffectiveVisibility {
222 ) -> &mut EffectiveVisibility {
216223 self.map.entry(id).or_insert_with(|| EffectiveVisibility::from_vis(lazy_private_vis()))
217224 }
218225
......@@ -226,11 +233,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
226233 tcx: TyCtxt<'_>,
227234 ) -> bool {
228235 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);
234237
235238 let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.at_level(level);
236239 let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
......@@ -268,7 +271,6 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
268271 }
269272 }
270273
271 self.map.insert(id, current_effective_vis);
272274 changed
273275 }
274276}
compiler/rustc_middle/src/queries.rs+1-1
......@@ -274,7 +274,7 @@ rustc_queries! {
274274 ///
275275 /// This can be conveniently accessed by `tcx.hir_*` methods.
276276 /// 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>> {
278278 desc { "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) }
279279 // This query has to be `no_hash` and `eval_always`,
280280 // 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};
4646use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
4747use rustc_type_ir::TyKind::*;
4848pub use rustc_type_ir::lift::Lift;
49use rustc_type_ir::{CollectAndApply, FnSigKind, WithCachedTypeInfo, elaborate, search_graph};
49use rustc_type_ir::{CollectAndApply, WithCachedTypeInfo, elaborate, search_graph};
5050use tracing::{debug, instrument};
5151
5252use crate::arena::Arena;
......@@ -66,11 +66,11 @@ use crate::traits;
6666use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData, PredefinedOpaques};
6767use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
6868use 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,
7474};
7575
7676impl<'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 {
8383 }
8484}
8585
86impl<'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
108impl<'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
13086impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
13187 fn safe() -> Self {
13288 hir::Safety::Safe
......@@ -1335,7 +1291,7 @@ impl<'tcx> TyCtxt<'tcx> {
13351291 let caller_features = &self.body_codegen_attrs(caller).target_features;
13361292 if self.is_target_feature_call_safe(&fun_features, &caller_features) {
13371293 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),
13391295 ..sig
13401296 }));
13411297 }
......@@ -2104,7 +2060,10 @@ impl<'tcx> TyCtxt<'tcx> {
21042060 assert!(sig.safety().is_safe());
21052061 Ty::new_fn_ptr(
21062062 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 }),
21082067 )
21092068 }
21102069
......@@ -2113,7 +2072,10 @@ impl<'tcx> TyCtxt<'tcx> {
21132072 /// unsafe.
21142073 pub fn safe_to_unsafe_sig(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> {
21152074 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 })
21172079 }
21182080
21192081 /// 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> {
21582120 self.mk_fn_sig(
21592121 params,
21602122 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),
21622124 )
21632125 })
21642126 }
......@@ -2417,7 +2379,12 @@ impl<'tcx> TyCtxt<'tcx> {
24172379 // IntoIterator` instead of `I: Iterator`, and it doesn't have a slice
24182380 // variant, because of the need to combine `inputs` and `output`. This
24192381 // 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
24212388 where
24222389 I: IntoIterator<Item = T>,
24232390 T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>,
......@@ -2439,7 +2406,7 @@ impl<'tcx> TyCtxt<'tcx> {
24392406 I: IntoIterator<Item = T>,
24402407 T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>,
24412408 {
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))
24432410 }
24442411
24452412 /// `mk_fn_sig`, but with a safe Rust ABI, and no C-variadic argument.
......@@ -2448,7 +2415,7 @@ impl<'tcx> TyCtxt<'tcx> {
24482415 I: IntoIterator<Item = T>,
24492416 T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>,
24502417 {
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))
24522419 }
24532420
24542421 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 @@
22
33use std::{debug_assert_matches, fmt};
44
5use rustc_abi::ExternAbi;
65use rustc_errors::ErrorGuaranteed;
76use rustc_hir as hir;
87use rustc_hir::def::{CtorKind, CtorOf, DefKind};
......@@ -10,9 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
109use rustc_hir::lang_items::LangItem;
1110use rustc_span::{DUMMY_SP, Span, Symbol};
1211use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
13use rustc_type_ir::{
14 CollectAndApply, FnSigKind, Interner, TypeFoldable, Unnormalized, search_graph,
15};
12use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, Unnormalized, search_graph};
1613
1714use crate::dep_graph::{DepKind, DepNodeIndex};
1815use crate::infer::canonical::CanonicalVarKinds;
......@@ -92,9 +89,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
9289 type AllocId = crate::mir::interpret::AllocId;
9390 type Pat = Pattern<'tcx>;
9491 type PatList = &'tcx List<Pattern<'tcx>>;
95 type FSigKind = FnSigKind;
9692 type Safety = hir::Safety;
97 type Abi = ExternAbi;
9893 type Const = ty::Const<'tcx>;
9994 type Consts = &'tcx List<Self::Const>;
10095
compiler/rustc_middle/src/ty/mod.rs+30-17
......@@ -338,18 +338,39 @@ impl TyCtxt<'_> {
338338 self.parent(id.into().to_def_id()).expect_local()
339339 }
340340
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;
344348 }
345349
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 }
350359 }
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),
351366 }
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 )
353374 }
354375}
355376
......@@ -391,15 +412,7 @@ impl<Id: Into<DefId>> Visibility<Id> {
391412 (Visibility::Restricted(_), Visibility::Public) => Some(Ordering::Less),
392413 (Visibility::Restricted(lhs_id), Visibility::Restricted(rhs_id)) => {
393414 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)
403416 }
404417 }
405418 }
compiler/rustc_middle/src/ty/print/pretty.rs+1-1
......@@ -751,7 +751,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
751751 if self.tcx().codegen_fn_attrs(def_id).safe_target_features {
752752 write!(self, "#[target_features] ")?;
753753 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);
755755 sig
756756 });
757757 }
compiler/rustc_middle/src/ty/structural_impls.rs-1
......@@ -198,7 +198,6 @@ TrivialLiftImpls! {
198198 rustc_hir::Safety,
199199 rustc_middle::mir::ConstValue,
200200 rustc_type_ir::BoundConstness,
201 rustc_type_ir::FnSigKind,
202201 rustc_type_ir::PredicatePolarity,
203202 // tidy-alphabetical-end
204203}
compiler/rustc_middle/src/ty/sty.rs+1-1
......@@ -37,7 +37,7 @@ pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
3737pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
3838pub type AliasTyKind<'tcx> = ir::AliasTyKind<TyCtxt<'tcx>>;
3939pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
40pub type FnSigKind = ir::FnSigKind;
40pub type FnSigKind<'tcx> = ir::FnSigKind<TyCtxt<'tcx>>;
4141pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
4242pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
4343pub 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 {
314314 ) -> Self::T<'tcx> {
315315 let fn_sig_kind = rustc_ty::FnSigKind::default()
316316 .set_abi(self.abi.internal(tables, tcx))
317 .set_safe(self.safety == Safety::Safe)
317 .set_safety(self.safety.internal(tables, tcx))
318318 .set_c_variadic(self.c_variadic);
319319 tcx.lift(rustc_ty::FnSig {
320320 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
257257
258258// This internal type isn't publicly exposed, because it is an implementation detail.
259259// But it's a public field of FnSig (which has a public mirror type), so allow conversions.
260impl<'tcx> Stable<'tcx> for ty::FnSigKind {
260impl<'tcx> Stable<'tcx> for ty::FnSigKind<'tcx> {
261261 type T = (bool /*c_variadic*/, crate::mir::Safety, crate::ty::Abi);
262262 fn stable<'cx>(
263263 &self,
compiler/rustc_resolve/src/build_reduced_graph.rs+3-1
......@@ -93,7 +93,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
9393 ambiguity: CmCell::new(ambiguity),
9494 // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment.
9595 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),
9799 span,
98100 expansion,
99101 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> {
182182 parent_id.level(),
183183 tcx,
184184 );
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 }
185189 }
186190
187191 fn update_def(
compiler/rustc_resolve/src/ident.rs+30
......@@ -490,6 +490,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
490490 }
491491 Some(Finalize { import, .. }) => import,
492492 };
493 this.get_mut().maybe_push_glob_vs_glob_vis_ambiguity(
494 ident,
495 orig_ident_span,
496 decl,
497 import,
498 );
493499
494500 if let Some(&(innermost_decl, _)) = innermost_results.first() {
495501 // Found another solution, if the first one was "weak", report an error.
......@@ -779,6 +785,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
779785 ret.map_err(ControlFlow::Continue)
780786 }
781787
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
782812 fn maybe_push_ambiguity(
783813 &mut self,
784814 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
370370
371371impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
372372 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 {
373382 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() };
375384 if decl_vis.partial_cmp(import.vis, self.tcx) == Some(Ordering::Less)
376385 && decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx)
377386 && pub_use_of_private_extern_crate_hack(import, decl).is_none()
......@@ -409,7 +418,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
409418 ambiguity: CmCell::new(None),
410419 warn_ambiguity: CmCell::new(false),
411420 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),
413424 expansion: import.parent_scope.expansion,
414425 parent_module: Some(import.parent_scope.module),
415426 })
......@@ -434,8 +445,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
434445 // - A glob decl is overwritten by its clone after setting ambiguity in it.
435446 // FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
436447 // 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.
439448 // - A glob decl is overwritten by a glob decl re-fetching an
440449 // overwritten decl from other module (the recursive case).
441450 // Here we are detecting all such re-fetches and overwrite old decls
......@@ -449,8 +458,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
449458 // FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
450459 // assert_ne!(old_deep_decl, deep_decl);
451460 // 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());
454462 if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
455463 // Do not lose glob ambiguities when re-fetching the glob.
456464 glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
......@@ -470,12 +478,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
470478 // FIXME: remove this when `warn_ambiguity` is removed (#149195).
471479 self.arenas.alloc_decl((*old_glob_decl).clone())
472480 }
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.
475486 // 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
479496 } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() {
480497 // Overwriting a non-ambiguous glob import with an ambiguous glob import.
481498 old_glob_decl.ambiguity.set_unchecked(Some(glob_decl));
......@@ -498,6 +515,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
498515 ) -> Result<(), Decl<'ra>> {
499516 assert!(!decl.warn_ambiguity.get());
500517 assert!(decl.ambiguity.get().is_none());
518 assert!(decl.ambiguity_vis_max.get().is_none());
519 assert!(decl.ambiguity_vis_min.get().is_none());
501520 let module = decl.parent_module.unwrap().expect_local();
502521 assert!(self.is_accessible_from(decl.vis(), module.to_module()));
503522 let res = decl.res();
......@@ -556,11 +575,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
556575 .resolution_or_default(module.to_module(), key, orig_ident_span)
557576 .borrow_mut_unchecked();
558577 let old_decl = resolution.determined_decl();
578 let old_vis = old_decl.map(|d| d.vis());
559579
560580 let t = f(self, resolution);
561581
562582 if let Some(binding) = resolution.determined_decl()
563 && old_decl != Some(binding)
583 && (old_decl != Some(binding) || old_vis != Some(binding.vis()))
564584 {
565585 (binding, t, warn_ambiguity || old_decl.is_some())
566586 } else {
compiler/rustc_resolve/src/lib.rs+17-3
......@@ -929,7 +929,13 @@ struct DeclData<'ra> {
929929 warn_ambiguity: CmCell<bool>,
930930 expansion: LocalExpnId,
931931 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>>>,
933939 parent_module: Option<Module<'ra>>,
934940}
935941
......@@ -1049,7 +1055,13 @@ struct AmbiguityError<'ra> {
10491055
10501056impl<'ra> DeclData<'ra> {
10511057 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)
10531065 }
10541066
10551067 fn res(&self) -> Res {
......@@ -1505,7 +1517,9 @@ impl<'ra> ResolverArenas<'ra> {
15051517 kind: DeclKind::Def(res),
15061518 ambiguity: CmCell::new(None),
15071519 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),
15091523 span,
15101524 expansion,
15111525 parent_module,
compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs+2-2
......@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
1313 options.add_pre_link_args(
1414 LinkerFlavor::WasmLld(Cc::Yes),
1515 &[
16 "--target=wasm32-wasi-threads",
16 "--target=wasm32-linux-muslwali",
1717 "-Wl,--export-memory,",
1818 "-Wl,--shared-memory",
1919 "-Wl,--max-memory=1073741824",
......@@ -21,7 +21,7 @@ pub(crate) fn target() -> Target {
2121 );
2222
2323 Target {
24 llvm_target: "wasm32-wasi".into(),
24 llvm_target: "wasm32-linux-muslwali".into(),
2525 metadata: TargetMetadata {
2626 description: Some("WebAssembly Linux Interface with musl-libc".into()),
2727 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;
2525use rustc_middle::ty::abstract_const::NotConstEvaluatable;
2626use rustc_middle::ty::error::{ExpectedFound, TypeError};
2727use 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,
3030};
3131use rustc_middle::ty::{
3232 self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
......@@ -886,6 +886,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
886886 );
887887 }
888888 }
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 );
889906 }
890907 diag
891908 }
......@@ -2708,7 +2725,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
27082725 fn predicate_can_apply(
27092726 &self,
27102727 param_env: ty::ParamEnv<'tcx>,
2711 pred: ty::PolyTraitPredicate<'tcx>,
2728 pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + TypeFoldable<TyCtxt<'tcx>>,
27122729 ) -> bool {
27132730 struct ParamToVarFolder<'a, 'tcx> {
27142731 infcx: &'a InferCtxt<'tcx>,
compiler/rustc_type_ir/src/error.rs+2-1
......@@ -1,4 +1,5 @@
11use derive_where::derive_where;
2use rustc_abi::ExternAbi;
23use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
34
45use crate::solve::NoSolution;
......@@ -25,7 +26,7 @@ pub enum TypeError<I: Interner> {
2526 Mismatch,
2627 PolarityMismatch(#[type_visitable(ignore)] ExpectedFound<ty::PredicatePolarity>),
2728 SafetyMismatch(#[type_visitable(ignore)] ExpectedFound<I::Safety>),
28 AbiMismatch(#[type_visitable(ignore)] ExpectedFound<I::Abi>),
29 AbiMismatch(#[type_visitable(ignore)] ExpectedFound<ExternAbi>),
2930 Mutability,
3031 ArgumentMutability(usize),
3132 TupleSize(ExpectedFound<usize>),
compiler/rustc_type_ir/src/generic_visit.rs+7
......@@ -15,6 +15,8 @@ use rustc_index::{Idx, IndexVec};
1515use smallvec::SmallVec;
1616use thin_vec::ThinVec;
1717
18use crate::Interner;
19
1820/// This trait is implemented for every type that can be visited,
1921/// providing the skeleton of the traversal.
2022///
......@@ -210,4 +212,9 @@ trivial_impls!(
210212 rustc_hash::FxBuildHasher,
211213 crate::TypeFlags,
212214 crate::solve::GoalSource,
215 rustc_abi::ExternAbi,
213216);
217
218impl<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>>:
205205 fn output(self) -> I::Ty;
206206}
207207
208#[rust_analyzer::prefer_underscore_import]
209pub 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]
227pub 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
244208#[rust_analyzer::prefer_underscore_import]
245209pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
246210 /// The `safe` safety mode.
compiler/rustc_type_ir/src/interner.rs-2
......@@ -145,9 +145,7 @@ pub trait Interner:
145145 + Eq
146146 + TypeVisitable<Self>
147147 + SliceLike<Item = Self::Pat>;
148 type FSigKind: FSigKind<Self>;
149148 type Safety: Safety<Self>;
150 type Abi: Abi<Self>;
151149
152150 // Kinds of consts
153151 type Const: Const<Self>;
compiler/rustc_type_ir/src/ty_kind.rs+52-32
......@@ -1,4 +1,5 @@
11use std::fmt;
2use std::marker::PhantomData;
23use std::ops::Deref;
34
45use derive_where::derive_where;
......@@ -762,18 +763,31 @@ impl<I: Interner> Eq for TypeAndMut<I> {}
762763
763764/// Contains the packed non-type fields of a function signature.
764765// 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)]
766768#[cfg_attr(
767769 feature = "nightly",
768770 derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
769771)]
770pub struct FnSigKind {
772pub struct FnSigKind<I: Interner> {
771773 /// Holds the c_variadic and safety bitflags, and 6 bits for the `ExternAbi` variant and unwind
772774 /// flag.
775 #[type_visitable(ignore)]
776 #[type_foldable(identity)]
773777 flags: u8,
778 #[type_visitable(ignore)]
779 #[type_foldable(identity)]
780 _marker: PhantomData<fn() -> I>,
774781}
775782
776impl fmt::Debug for FnSigKind {
783impl<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
790impl<I: Interner> fmt::Debug for FnSigKind<I> {
777791 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778792 let mut f = f.debug_tuple("FnSigKind");
779793
......@@ -793,7 +807,7 @@ impl fmt::Debug for FnSigKind {
793807 }
794808}
795809
796impl FnSigKind {
810impl<I: Interner> FnSigKind<I> {
797811 /// Mask for the `ExternAbi` variant, including the unwind flag.
798812 const EXTERN_ABI_MASK: u8 = 0b111111;
799813
......@@ -806,13 +820,21 @@ impl FnSigKind {
806820 /// Create a new FnSigKind with the "Rust" ABI, "Unsafe" safety, and no C-style variadic argument.
807821 /// To modify these flags, use the `set_*` methods, for readability.
808822 // 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)
811833 }
812834
813835 /// Set the ABI, including the unwind flag.
814836 #[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 {
816838 let abi_index = abi.as_packed();
817839 assert!(abi_index <= Self::EXTERN_ABI_MASK);
818840
......@@ -824,8 +846,8 @@ impl FnSigKind {
824846
825847 /// Set the safety flag, `true` is `Safe`.
826848 #[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() {
829851 self.flags |= Self::SAFE_FLAG;
830852 } else {
831853 self.flags &= !Self::SAFE_FLAG;
......@@ -836,7 +858,7 @@ impl FnSigKind {
836858
837859 /// Set the C-style variadic argument flag.
838860 #[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 {
840862 if c_variadic {
841863 self.flags |= Self::C_VARIADIC_FLAG;
842864 } else {
......@@ -847,18 +869,23 @@ impl FnSigKind {
847869 }
848870
849871 /// Get the ABI, including the unwind flag.
850 pub const fn abi(self) -> ExternAbi {
872 pub fn abi(self) -> ExternAbi {
851873 let abi_index = self.flags & Self::EXTERN_ABI_MASK;
852874 ExternAbi::from_packed(abi_index)
853875 }
854876
855877 /// Get the safety flag.
856 pub const fn is_safe(self) -> bool {
878 pub fn is_safe(self) -> bool {
857879 self.flags & Self::SAFE_FLAG != 0
858880 }
859881
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
860887 /// 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 {
862889 self.flags & Self::C_VARIADIC_FLAG != 0
863890 }
864891}
......@@ -873,7 +900,7 @@ pub struct FnSig<I: Interner> {
873900 pub inputs_and_output: I::Tys,
874901 #[type_visitable(ignore)]
875902 #[type_foldable(identity)]
876 pub fn_sig_kind: I::FSigKind,
903 pub fn_sig_kind: FnSigKind<I>,
877904}
878905
879906impl<I: Interner> Eq for FnSig<I> {}
......@@ -888,25 +915,18 @@ impl<I: Interner> FnSig<I> {
888915 }
889916
890917 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
892919 }
893920
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 }
903923 }
904924
905925 pub fn safety(self) -> I::Safety {
906926 self.fn_sig_kind.safety()
907927 }
908928
909 pub fn abi(self) -> I::Abi {
929 pub fn abi(self) -> ExternAbi {
910930 self.fn_sig_kind.abi()
911931 }
912932
......@@ -917,7 +937,7 @@ impl<I: Interner> FnSig<I> {
917937 pub fn dummy() -> Self {
918938 Self {
919939 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),
921941 }
922942 }
923943}
......@@ -943,7 +963,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
943963 self.map_bound(|fn_sig| fn_sig.output())
944964 }
945965
946 pub fn fn_sig_kind(self) -> I::FSigKind {
966 pub fn fn_sig_kind(self) -> FnSigKind<I> {
947967 self.skip_binder().fn_sig_kind
948968 }
949969
......@@ -955,7 +975,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> {
955975 self.skip_binder().safety()
956976 }
957977
958 pub fn abi(self) -> I::Abi {
978 pub fn abi(self) -> ExternAbi {
959979 self.skip_binder().abi()
960980 }
961981
......@@ -976,7 +996,7 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
976996 let FnSig { inputs_and_output: _, fn_sig_kind } = sig;
977997
978998 write!(f, "{}", fn_sig_kind.safety().prefix_str())?;
979 if !fn_sig_kind.abi().is_rust() {
999 if fn_sig_kind.abi() != ExternAbi::Rust {
9801000 write!(f, "extern \"{:?}\" ", fn_sig_kind.abi())?;
9811001 }
9821002
......@@ -1131,7 +1151,7 @@ impl<I: Interner> ty::Binder<I, FnSigTys<I>> {
11311151pub struct FnHeader<I: Interner> {
11321152 #[type_visitable(ignore)]
11331153 #[type_foldable(identity)]
1134 pub fn_sig_kind: I::FSigKind,
1154 pub fn_sig_kind: FnSigKind<I>,
11351155}
11361156
11371157impl<I: Interner> FnHeader<I> {
......@@ -1143,12 +1163,12 @@ impl<I: Interner> FnHeader<I> {
11431163 self.fn_sig_kind.safety()
11441164 }
11451165
1146 pub fn abi(self) -> I::Abi {
1166 pub fn abi(self) -> ExternAbi {
11471167 self.fn_sig_kind.abi()
11481168 }
11491169
11501170 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) }
11521172 }
11531173}
11541174
compiler/rustc_type_ir/src/ty_kind/closure.rs+2-2
......@@ -9,7 +9,7 @@ use crate::data_structures::DelayedMap;
99use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
1010use crate::inherent::*;
1111use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
12use crate::{self as ty, Interner};
12use crate::{self as ty, FnSigKind, Interner};
1313
1414/// A closure can be modeled as a struct that looks like:
1515/// ```ignore (illustrative)
......@@ -367,7 +367,7 @@ pub struct CoroutineClosureSignature<I: Interner> {
367367 /// Always safe, RustCall, non-c-variadic
368368 #[type_visitable(ignore)]
369369 #[type_foldable(identity)]
370 pub fn_sig_kind: I::FSigKind,
370 pub fn_sig_kind: FnSigKind<I>,
371371}
372372
373373impl<I: Interner> Eq for CoroutineClosureSignature<I> {}
library/core/src/ffi/va_list.rs+14-4
......@@ -390,11 +390,21 @@ impl<'f> VaList<'f> {
390390 ///
391391 /// # Safety
392392 ///
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:
395394 ///
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
398408 #[inline] // Avoid codegen when not used to help backends that don't support VaList.
399409 #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
400410 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;
520520
521521/// Checks if all mask values are true.
522522///
523/// `T` must be a vector of integer primitive types.
523/// `T` must be a vector of integers.
524524///
525525/// # Safety
526526/// `x` must contain only `0` or `!0`.
......@@ -530,7 +530,7 @@ pub const unsafe fn simd_reduce_all<T>(x: T) -> bool;
530530
531531/// Checks if any mask value is true.
532532///
533/// `T` must be a vector of integer primitive types.
533/// `T` must be a vector of integers.
534534///
535535/// # Safety
536536/// `x` must contain only `0` or `!0`.
......@@ -540,29 +540,25 @@ pub const unsafe fn simd_reduce_any<T>(x: T) -> bool;
540540
541541/// Returns the maximum element of a vector.
542542///
543/// `T` must be a vector of integers or floats.
543/// `T` must be a vector of integers.
544544///
545545/// `U` must be the element type of `T`.
546///
547/// For floating-point values, uses IEEE-754 `maxNum`.
548546#[rustc_intrinsic]
549547#[rustc_nounwind]
550548pub const unsafe fn simd_reduce_max<T, U>(x: T) -> U;
551549
552550/// Returns the minimum element of a vector.
553551///
554/// `T` must be a vector of integers or floats.
552/// `T` must be a vector of integers.
555553///
556554/// `U` must be the element type of `T`.
557///
558/// For floating-point values, uses IEEE-754 `minNum`.
559555#[rustc_intrinsic]
560556#[rustc_nounwind]
561557pub const unsafe fn simd_reduce_min<T, U>(x: T) -> U;
562558
563559/// Logical "and"s all elements together.
564560///
565/// `T` must be a vector of integers or floats.
561/// `T` must be a vector of integers.
566562///
567563/// `U` must be the element type of `T`.
568564#[rustc_intrinsic]
......@@ -571,7 +567,7 @@ pub const unsafe fn simd_reduce_and<T, U>(x: T) -> U;
571567
572568/// Logical "ors" all elements together.
573569///
574/// `T` must be a vector of integers or floats.
570/// `T` must be a vector of integers.
575571///
576572/// `U` must be the element type of `T`.
577573#[rustc_intrinsic]
......@@ -580,7 +576,7 @@ pub const unsafe fn simd_reduce_or<T, U>(x: T) -> U;
580576
581577/// Logical "exclusive ors" all elements together.
582578///
583/// `T` must be a vector of integers or floats.
579/// `T` must be a vector of integers.
584580///
585581/// `U` must be the element type of `T`.
586582#[rustc_intrinsic]
library/std_detect/src/detect/os/windows/aarch64.rs+53-5
......@@ -31,8 +31,14 @@ pub(crate) fn detect_features() -> cache::Initializer {
3131 const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55;
3232 const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56;
3333 // 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;
3642
3743 unsafe extern "system" {
3844 fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL;
......@@ -46,9 +52,11 @@ pub(crate) fn detect_features() -> cache::Initializer {
4652 }
4753 };
4854
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.
5260 unsafe {
5361 enable_feature(
5462 Feature::fp,
......@@ -112,6 +120,46 @@ pub(crate) fn detect_features() -> cache::Initializer {
112120 Feature::sve2_sm4,
113121 IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE,
114122 );
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 );
115163 // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and
116164 // pmull support
117165 let crypto =
library/std_detect/tests/cpu-detection.rs+8
......@@ -150,14 +150,22 @@ fn aarch64_linux() {
150150fn aarch64_windows() {
151151 println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
152152 println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
153 println!("fp16: {:?}", is_aarch64_feature_detected!("fp16"));
153154 println!("crc: {:?}", is_aarch64_feature_detected!("crc"));
154155 println!("lse: {:?}", is_aarch64_feature_detected!("lse"));
156 println!("lse2: {:?}", is_aarch64_feature_detected!("lse2"));
157 println!("rdm: {:?}", is_aarch64_feature_detected!("rdm"));
155158 println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod"));
159 println!("i8mm: {:?}", is_aarch64_feature_detected!("i8mm"));
160 println!("bf16: {:?}", is_aarch64_feature_detected!("bf16"));
156161 println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv"));
157162 println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc"));
158163 println!("aes: {:?}", is_aarch64_feature_detected!("aes"));
159164 println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
160165 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"));
161169}
162170
163171#[test]
src/bootstrap/src/core/builder/cargo.rs+4
......@@ -1073,6 +1073,8 @@ impl Builder<'_> {
10731073 // rustc creates absolute paths (in part bc of the `rust-src` unremap
10741074 // and for working directory) so let's remap the build directory as well.
10751075 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()),
10761078 ]
10771079 .join("\t");
10781080 cargo.env("RUSTC_DEBUGINFO_MAP", map);
......@@ -1093,6 +1095,8 @@ impl Builder<'_> {
10931095 // rustc creates absolute paths (in part bc of the `rust-src` unremap
10941096 // and for working directory) so let's remap the build directory as well.
10951097 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()),
10961100 ]
10971101 .join("\t");
10981102 cargo.env("RUSTC_DEBUGINFO_MAP", map);
src/ci/scripts/free-disk-space-linux.sh+85-24
......@@ -96,15 +96,11 @@ removeUnusedFilesAndDirs() {
9696 )
9797
9898 if isGitHubRunner; then
99 # Paths common to all runners (both x86 and ARM)
99100 to_remove+=(
100101 "/usr/local/aws-sam-cli"
101102 "/usr/local/doc/cmake"
102 "/usr/local/julia"*
103 "/usr/local/lib/android"
104 "/usr/local/share/chromedriver-"*
105 "/usr/local/share/chromium"
106103 "/usr/local/share/cmake-"*
107 "/usr/local/share/edge_driver"
108104 "/usr/local/share/emacs"
109105 "/usr/local/share/gecko_driver"
110106 "/usr/local/share/icons"
......@@ -112,16 +108,13 @@ removeUnusedFilesAndDirs() {
112108 "/usr/local/share/vcpkg"
113109 "/usr/local/share/vim"
114110 "/usr/share/apache-maven-"*
115 "/usr/share/gradle-"*
116111 "/usr/share/kotlinc"
117 "/usr/share/miniconda"
118112 "/usr/share/php"
119113 "/usr/share/ri"
120114 "/usr/share/swift"
121115
122116 # binaries
123117 "/usr/local/bin/azcopy"
124 "/usr/local/bin/bicep"
125118 "/usr/local/bin/ccmake"
126119 "/usr/local/bin/cmake-"*
127120 "/usr/local/bin/cmake"
......@@ -135,16 +128,53 @@ removeUnusedFilesAndDirs() {
135128 "/usr/local/bin/phpunit"
136129 "/usr/local/bin/pulumi-"*
137130 "/usr/local/bin/pulumi"
138 "/usr/local/bin/stack"
139
140 # Haskell runtime
141 "/usr/local/.ghcup"
142131
143132 # Azure
144133 "/opt/az"
145134 "/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"
146159 )
147160
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
148178 if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then
149179 # Environment variable set by GitHub Actions
150180 to_remove+=(
......@@ -201,10 +231,22 @@ cleanPackages() {
201231 '^dotnet-.*'
202232 '^llvm-.*'
203233 '^mongodb-.*'
234 '^temurin-.*-jdk'
235 'buildah'
204236 'firefox'
237 'google-cloud-cli'
238 'google-cloud-sdk'
239 'kubectl'
205240 'libgl1-mesa-dri'
206241 'mono-devel'
207242 'php.*'
243 'podman'
244 'skopeo'
245 )
246 local x86_only_packages=(
247 'google-chrome-stable'
248 'microsoft-edge-stable'
249 'powershell'
208250 )
209251
210252 if isGitHubRunner; then
......@@ -213,12 +255,20 @@ cleanPackages() {
213255 )
214256
215257 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
222272 fi
223273 else
224274 packages+=(
......@@ -235,11 +285,19 @@ cleanPackages() {
235285 || echo "::warning::The command [sudo apt-get clean] failed"
236286}
237287
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.
241289cleanDocker() {
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
242298 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.
243301 sudo docker image ls
244302 echo "=> Removing docker images..."
245303 sudo docker image prune --all --force || true
......@@ -253,7 +311,8 @@ cleanSwap() {
253311}
254312
255313sufficientSpaceEarlyExit() {
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)
257316
258317 if [ "$available_space_kb" -ge "$space_target_kb" ]; then
259318 echo "Sufficient disk space available (${available_space_kb}KB >= ${space_target_kb}KB). Skipping cleanup."
......@@ -267,7 +326,8 @@ sufficientSpaceEarlyExit() {
267326checkAlternative() {
268327 local gha_alt_disk="/mnt"
269328
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)
271331
272332 # mount options that trade durability for performance
273333 # ignore-tidy-linelength
......@@ -276,7 +336,8 @@ checkAlternative() {
276336 # GHA has a 2nd disk mounted at /mnt that is almost empty.
277337 # Check if it's a valid mountpoint and it has enough available space.
278338 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)
280341 echo "Sufficient space available on $blkdev mounted at $gha_alt_disk"
281342 # see cleanSwap(), swapfile may be mounted under /mnt
282343 sudo swapoff -a || true
src/librustdoc/clean/mod.rs+10-2
......@@ -3260,14 +3260,22 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
32603260 hir::ForeignItemKind::Type => ForeignTypeItem,
32613261 };
32623262
3263 generate_item_with_correct_attrs(
3263 let mut clean_item = generate_item_with_correct_attrs(
32643264 cx,
32653265 kind,
32663266 item.owner_id.def_id.to_def_id(),
32673267 item.ident.name,
32683268 import_id.as_slice(),
32693269 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
32713279 })
32723280}
32733281
src/librustdoc/clean/types.rs+6
......@@ -1093,6 +1093,12 @@ impl Attributes {
10931093 }
10941094 aliases.into_iter().collect::<Vec<_>>().into()
10951095 }
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 }
10961102}
10971103
10981104#[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.
511511 of Rust will be stricter than Tree Borrows. In other words, if you use Tree Borrows,
512512 even if your code is accepted today, it might be declared UB in the future.
513513 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.
514516* `-Zmiri-tree-borrows-no-precise-interior-mut` makes Tree Borrows
515517 track interior mutable data on the level of references instead of on the
516518 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 {
515515 miri_config.borrow_tracker =
516516 Some(BorrowTrackerMethod::TreeBorrows(TreeBorrowsParams {
517517 precise_interior_mut: true,
518 implicit_writes: false,
518519 }));
519520 } else if arg == "-Zmiri-tree-borrows-no-precise-interior-mut" {
520521 match &mut miri_config.borrow_tracker {
......@@ -526,6 +527,16 @@ fn main() -> ExitCode {
526527 "`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-no-precise-interior-mut`"
527528 ),
528529 };
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 };
529540 } else if arg == "-Zmiri-disable-data-race-detector" {
530541 miri_config.data_race_detector = false;
531542 miri_config.weak_memory_emulation = false;
src/tools/miri/src/borrow_tracker/mod.rs+2
......@@ -224,6 +224,8 @@ pub enum BorrowTrackerMethod {
224224#[derive(Debug, Copy, Clone, PartialEq, Eq)]
225225pub struct TreeBorrowsParams {
226226 pub precise_interior_mut: bool,
227 /// Controls whether `&mut` function arguments are immediately activated with an implicit write.
228 pub implicit_writes: bool,
227229}
228230
229231impl BorrowTrackerMethod {
src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs+3-3
......@@ -15,7 +15,7 @@ use crate::*;
1515#[derive(Clone, Copy, Debug)]
1616pub enum AccessCause {
1717 Explicit(AccessKind),
18 Reborrow,
18 Reborrow(AccessKind),
1919 Dealloc,
2020 FnExit(AccessKind),
2121}
......@@ -24,7 +24,7 @@ impl fmt::Display for AccessCause {
2424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2525 match self {
2626 Self::Explicit(kind) => write!(f, "{kind}"),
27 Self::Reborrow => write!(f, "reborrow"),
27 Self::Reborrow(_) => write!(f, "reborrow"),
2828 Self::Dealloc => write!(f, "deallocation"),
2929 // This is dead code, since the protector release access itself can never
3030 // cause UB (while the protector is active, if some other access invalidates
......@@ -40,7 +40,7 @@ impl AccessCause {
4040 let rel = if is_foreign { "foreign" } else { "child" };
4141 match self {
4242 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})"),
4444 Self::Dealloc => format!("deallocation (acting as a {rel} write access)"),
4545 Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"),
4646 }
src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs+102-51
......@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty};
66use self::foreign_access_skipping::IdempotentForeignAccess;
77use self::tree::LocationState;
88use crate::borrow_tracker::{AccessKind, GlobalState, GlobalStateInner, ProtectorKind};
9use crate::concurrency::data_race::NaReadType;
9use crate::concurrency::data_race::{NaReadType, NaWriteType};
1010use crate::*;
1111
1212pub mod diagnostics;
......@@ -109,13 +109,8 @@ impl<'tcx> Tree {
109109pub struct NewPermission {
110110 /// Permission for the frozen part of the range.
111111 freeze_perm: Permission,
112 /// Whether a read access should be performed on the frozen part on a retag.
113 freeze_access: bool,
114112 /// Permission for the non-frozen part of the range.
115113 nonfreeze_perm: Permission,
116 /// Whether a read access should be performed on the non-frozen
117 /// part on a retag.
118 nonfreeze_access: bool,
119114 /// Permission for memory outside the range.
120115 outside_perm: Permission,
121116 /// Whether this pointer is part of the arguments of a function call.
......@@ -138,36 +133,78 @@ impl<'tcx> NewPermission {
138133 let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
139134 let is_protected = retag_kind == RetagKind::FnEntry;
140135
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
141147 if matches!(ref_mutability, Some(Mutability::Mut) | None if !ty_is_unpin) {
142148 // Mutable reference / Box to pinning type: retagging is a NOP.
143149 // FIXME: with `UnsafePinned`, this should do proper per-byte tracking.
144150 return None;
145151 }
146152
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 }
160202 };
161203
162 // Everything except for `Cell` gets an initial access.
163 let initial_access = |perm: &Permission| !perm.is_cell();
164
165204 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),
171208 protector: is_protected.then_some(if ref_mutability.is_some() {
172209 // Strong protector for references
173210 ProtectorKind::StrongProtector
......@@ -288,13 +325,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
288325
289326 // Compute initial "inside" permissions.
290327 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 };
296329 let sifa = perm.strongest_idempotent_foreign_access(protected);
297 if access {
330
331 if perm.associated_access().is_some() {
298332 LocationState::new_accessed(perm, sifa)
299333 } else {
300334 LocationState::new_non_accessed(perm, sifa)
......@@ -303,11 +337,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
303337 let inside_perms = if !precise_interior_mut {
304338 // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`.
305339 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))
308341 } else {
309342 // 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(
311344 ptr_size,
312345 LocationState::new_accessed(
313346 Permission::new_disabled(),
......@@ -327,9 +360,18 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
327360 let alloc_extra = this.get_alloc_extra(alloc_id)?;
328361 let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
329362
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
333375 // Adjust range to be relative to allocation start (rather than to `place`).
334376 let range_in_alloc = AllocRange {
335377 start: Size::from_bytes(perm_range.start) + base_offset,
......@@ -339,8 +381,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
339381 tree_borrows.perform_access(
340382 parent_prov,
341383 range_in_alloc,
342 AccessKind::Read,
343 diagnostics::AccessCause::Reborrow,
384 access,
385 diagnostics::AccessCause::Reborrow(access),
344386 this.machine.borrow_tracker.as_ref().unwrap(),
345387 alloc_id,
346388 this.machine.current_user_relevant_span(),
......@@ -349,17 +391,29 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
349391 // Also inform the data race model (but only if any bytes are actually affected).
350392 if range_in_alloc.size.bytes() > 0 {
351393 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 };
359412 }
360413 }
361414 }
362415 }
416
363417 // Record the parent-child pair in the tree.
364418 tree_borrows.new_child(
365419 base_offset,
......@@ -370,7 +424,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
370424 protected,
371425 this.machine.current_user_relevant_span(),
372426 )?;
373 drop(tree_borrows);
374427
375428 interp_ok(Some(new_prov))
376429 }
......@@ -550,9 +603,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
550603 // argument doesn't matter
551604 // (`ty_is_freeze || true` in `new_reserved` will always be `true`).
552605 freeze_perm: Permission::new_reserved_frz(),
553 freeze_access: true,
554606 nonfreeze_perm: Permission::new_reserved_frz(),
555 nonfreeze_access: true,
556607 outside_perm: Permission::new_reserved_frz(),
557608 protector: Some(ProtectorKind::StrongProtector),
558609 };
src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs+10-7
......@@ -91,7 +91,7 @@ impl PartialOrd for PermissionPriv {
9191impl PermissionPriv {
9292 /// Check if `self` can be the initial state of a pointer.
9393 fn is_initial(&self) -> bool {
94 matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell)
94 matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell | Unique)
9595 }
9696
9797 /// Reject `ReservedIM` that cannot exist in the presence of a protector.
......@@ -265,14 +265,17 @@ impl Permission {
265265 self.inner == Cell
266266 }
267267
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`
270274 pub fn new_unique() -> Self {
271275 Self { inner: Unique }
272276 }
273277
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
276279 pub fn new_reserved_frz() -> Self {
277280 Self { inner: ReservedFrz { conflicted: false } }
278281 }
......@@ -304,8 +307,8 @@ impl Permission {
304307 self.inner.compatible_with_protector()
305308 }
306309
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> {
309312 match self.inner {
310313 // Do not do perform access if it is a `Cell`, as this
311314 // 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 {
6363 /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
6464 pub fn new_non_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
6565 assert!(permission.is_initial() || permission.is_disabled());
66 assert!(!permission.is_unique());
6667 Self { permission, accessed: false, idempotent_foreign_access: sifa }
6768 }
6869
......@@ -73,6 +74,12 @@ impl LocationState {
7374 Self { permission, accessed: true, idempotent_foreign_access: sifa }
7475 }
7576
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
7683 /// Check if the location has been accessed, i.e. if it has
7784 /// ever been accessed through a child pointer.
7885 pub fn accessed(&self) -> bool {
......@@ -150,6 +157,7 @@ impl LocationState {
150157 if protected && self.accessed && transition.produces_disabled() {
151158 return Err(TransitionError::ProtectedDisabled(old_perm));
152159 }
160 debug_assert!(self.possible());
153161 Ok(transition)
154162 }
155163
......@@ -397,6 +405,7 @@ impl<'tcx> Tree {
397405 ProvenanceExtra::Wildcard => None,
398406 };
399407 assert!(outside_perm.is_initial());
408 assert!(!outside_perm.is_unique());
400409
401410 let default_strongest_idempotent =
402411 outside_perm.strongest_idempotent_foreign_access(protected);
......@@ -690,7 +699,7 @@ impl<'tcx> Tree {
690699 for (loc_range, loc) in self.locations.iter_mut_all() {
691700 // Only visit accessed permissions
692701 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()
694703 && p.accessed
695704 {
696705 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};
99impl Exhaustive for LocationState {
1010 fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
1111 // 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 )
1923 }
2024}
2125
......@@ -438,17 +442,19 @@ mod spurious_read {
438442 /// Perform a read on the given pointer if its state is `accessed`.
439443 /// Must be called just after reborrowing a pointer, and just after
440444 /// removing a protector.
441 fn read_if_accessed(self, ptr: PtrSelector) -> Result<Self, ()> {
445 fn retag_dependent_access(self, ptr: PtrSelector) -> Result<Self, ()> {
442446 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),
445451 PtrSelector::Other =>
446452 panic!(
447453 "the `accessed` status of `PtrSelector::Other` is unknown, do not pass it to `read_if_accessed`"
448454 ),
449455 };
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 })
452458 } else {
453459 Ok(self)
454460 }
......@@ -457,13 +463,13 @@ mod spurious_read {
457463 /// Remove the protector of `x`, including the implicit read on function exit.
458464 fn end_protector_x(self) -> Result<Self, ()> {
459465 let x = self.x.end_protector();
460 Self { x, ..self }.read_if_accessed(PtrSelector::X)
466 Self { x, ..self }.retag_dependent_access(PtrSelector::X)
461467 }
462468
463469 /// Remove the protector of `y`, including the implicit read on function exit.
464470 fn end_protector_y(self) -> Result<Self, ()> {
465471 let y = self.y.end_protector();
466 Self { y, ..self }.read_if_accessed(PtrSelector::Y)
472 Self { y, ..self }.retag_dependent_access(PtrSelector::Y)
467473 }
468474
469475 fn retag_y(self, new_y: LocStateProt) -> Result<Self, ()> {
......@@ -473,7 +479,7 @@ mod spurious_read {
473479 }
474480 // `xy_rel` changes to "mutually foreign" now: `y` can no longer be a parent of `x`.
475481 Self { y: new_y, xy_rel: RelPosXY::MutuallyForeign, ..self }
476 .read_if_accessed(PtrSelector::Y)
482 .retag_dependent_access(PtrSelector::Y)
477483 }
478484
479485 fn perform_test_event<RetX, RetY>(self, evt: &TestEvent<RetX, RetY>) -> Result<Self, ()> {
......@@ -696,7 +702,7 @@ mod spurious_read {
696702 fn initial_state(&self) -> Result<LocStateProtPair, ()> {
697703 let (x, y) = self.retag_permissions();
698704 let state = LocStateProtPair { xy_rel: self.xy_rel, x, y };
699 state.read_if_accessed(PtrSelector::X)
705 state.retag_dependent_access(PtrSelector::X)
700706 }
701707 }
702708
src/tools/miri/src/concurrency/data_race.rs+4-4
......@@ -1243,21 +1243,21 @@ impl VClockAlloc {
12431243 /// operation. The `ty` parameter is used for diagnostics, letting
12441244 /// the user know which type was written.
12451245 pub fn write_non_atomic<'tcx>(
1246 &mut self,
1246 &self,
12471247 alloc_id: AllocId,
12481248 access_range: AllocRange,
12491249 write_type: NaWriteType,
12501250 ty: Option<Ty<'_>>,
1251 machine: &mut MiriMachine<'_>,
1251 machine: &MiriMachine<'_>,
12521252 ) -> InterpResult<'tcx> {
12531253 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();
12551255 if !global.race_detecting() {
12561256 return interp_ok(());
12571257 }
12581258 let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads);
12591259 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)
12611261 {
12621262 if let Err(DataRace) =
12631263 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> {
407407 let sig = this.tcx.mk_fn_sig(
408408 args.iter().map(|a| a.layout.ty),
409409 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),
411411 );
412412 let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
413413
src/tools/miri/src/shims/sig.rs+3-1
......@@ -275,7 +275,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
275275 let fn_sig_binder = Binder::dummy(FnSig {
276276 inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
277277 // 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),
279281 });
280282 let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
281283
src/tools/miri/src/shims/unix/foreign_items.rs+10
......@@ -350,6 +350,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
350350 let result = this.fstat(fd, buf)?;
351351 this.write_scalar(result, dest)?;
352352 }
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 }
353363 "rename" => {
354364 // FIXME: This does not have a direct test (#3179).
355365 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> {
136136 }
137137
138138 // 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" => {
143140 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
144141 let result = this.stat(path, buf)?;
145142 this.write_scalar(result, dest)?;
146143 }
147 "lstat" | "lstat@FBSD_1.0" => {
148 // FIXME: This does not have a direct test (#3179).
144 "lstat@FBSD_1.0" => {
149145 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
150146 let result = this.lstat(path, buf)?;
151147 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> {
243243
244244 this.write_int_fields_named(
245245 &[
246 ("st_dev", metadata.dev.into()),
246 ("st_dev", metadata.dev.unwrap_or(0).into()),
247247 ("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()),
252252 ("st_rdev", 0),
253253 ("st_atime", access_sec.into()),
254254 ("st_atime_nsec", access_nsec.into()),
......@@ -257,8 +257,8 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
257257 ("st_ctime", 0),
258258 ("st_ctime_nsec", 0),
259259 ("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()),
262262 ],
263263 &buf,
264264 )?;
......@@ -586,9 +586,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
586586
587587 if !matches!(
588588 &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
590590 ) {
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);
592592 }
593593
594594 let path_scalar = this.read_pointer(path_op)?;
......@@ -615,12 +615,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
615615
616616 if !matches!(
617617 &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
619619 ) {
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);
624621 }
625622
626623 let path_scalar = this.read_pointer(path_op)?;
......@@ -730,12 +727,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
730727 return this.set_last_error_and_return_i32(ecode);
731728 }
732729
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
739730 // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following
740731 // symbolic links.
741732 let follow_symlink = flags & this.eval_libc_i32("AT_SYMLINK_NOFOLLOW") == 0;
......@@ -752,6 +743,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
752743 Err(err) => return this.set_last_error_and_return_i32(err),
753744 };
754745
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
755769 // `statx.stx_mode` is `__u16`. `libc::S_IF*` are of type `mode_t`, which varies in
756770 // width across targets (`u16` on macOS, `u32` on Linux). Read using `mode_t`'s size.
757771 let mode_t_size = this.libc_ty_layout("mode_t").size;
......@@ -791,15 +805,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
791805 this.write_int_fields_named(
792806 &[
793807 ("stx_mask", mask.into()),
794 ("stx_blksize", 0),
808 ("stx_blksize", metadata.blksize.unwrap_or(0).into()),
795809 ("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()),
799813 ("stx_mode", mode.into()),
800 ("stx_ino", 0),
814 ("stx_ino", metadata.ino.unwrap_or(0).into()),
801815 ("stx_size", metadata.size.into()),
802 ("stx_blocks", 0),
816 ("stx_blocks", metadata.blocks.unwrap_or(0).into()),
803817 ("stx_attributes_mask", 0),
804818 ("stx_rdev_major", 0),
805819 ("stx_rdev_minor", 0),
......@@ -1664,15 +1678,24 @@ fn file_type_to_mode_name(file_type: std::fs::FileType) -> &'static str {
16641678
16651679/// Stores a file's metadata in order to avoid code duplication in the different metadata related
16661680/// 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.
16671686struct FileMetadata {
16681687 mode: Scalar,
16691688 size: u64,
16701689 created: Option<(u64, u32)>,
16711690 accessed: Option<(u64, u32)>,
16721691 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>,
16761699}
16771700
16781701impl FileMetadata {
......@@ -1711,9 +1734,13 @@ impl FileMetadata {
17111734 created: None,
17121735 accessed: None,
17131736 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,
17171744 }))
17181745 }
17191746
......@@ -1743,16 +1770,42 @@ impl FileMetadata {
17431770 unix => {
17441771 use std::os::unix::fs::MetadataExt;
17451772 let dev = metadata.dev();
1773 let ino = metadata.ino();
1774 let nlink = metadata.nlink();
17461775 let uid = metadata.uid();
17471776 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 }))
17481794 }
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 })),
17541809 }
1755
1756 interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified, dev, uid, gid }))
17571810 }
17581811}
src/tools/miri/src/shims/unix/linux/foreign_items.rs-1
......@@ -124,7 +124,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
124124 this.write_scalar(result, dest)?;
125125 }
126126 "statx" => {
127 // FIXME: This does not have a direct test (#3179).
128127 let [dirfd, pathname, flags, mask, statxbuf] =
129128 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
130129 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> {
4646 let result = this.close(result)?;
4747 this.write_scalar(result, dest)?;
4848 }
49 "stat" | "stat$INODE64" => {
50 // FIXME: This does not have a direct test (#3179).
49 "stat$INODE64" => {
5150 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
5251 let result = this.stat(path, buf)?;
5352 this.write_scalar(result, dest)?;
5453 }
55 "lstat" | "lstat$INODE64" => {
56 // FIXME: This does not have a direct test (#3179).
54 "lstat$INODE64" => {
5755 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
5856 let result = this.lstat(path, buf)?;
5957 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> {
316316 flags
317317 );
318318 }
319 if protocol != 0 {
319 if protocol != 0 && protocol != this.eval_libc_i32("IPPROTO_TCP") {
320320 throw_unsup_format!(
321321 "socket: socket protocol {protocol} is unsupported, \
322 only 0 is allowed"
322 only IPPROTO_TCP and 0 are allowed"
323323 );
324324 }
325325
src/tools/miri/src/shims/x86/avx512.rs+10-1
......@@ -3,7 +3,9 @@ use rustc_middle::ty::Ty;
33use rustc_span::Symbol;
44use rustc_target::callconv::FnAbi;
55
6use super::{packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, pmaddwd, psadbw, pshufb};
6use super::{
7 packssdw, packsswb, packusdw, packuswb, permute, permute2, pmaddbw, pmaddwd, psadbw, pshufb,
8};
79use crate::*;
810
911impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
......@@ -111,6 +113,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
111113
112114 permute(this, left, right, dest)?;
113115 }
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 }
114123 // Used to implement the _mm512_shuffle_epi8 intrinsic.
115124 "pshuf.b.512" => {
116125 let [left, right] =
src/tools/miri/src/shims/x86/mod.rs+48
......@@ -1107,6 +1107,54 @@ fn permute<'tcx>(
11071107 interp_ok(())
11081108}
11091109
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>
1121fn 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
11101158/// Multiplies packed 16-bit signed integer values, truncates the 32-bit
11111159/// product to the 18 most significant bits by right-shifting, and then
11121160/// 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
22//@[tree]compile-flags: -Zmiri-tree-borrows
3//@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes
34use std::mem;
45
56fn safe(x: &mut i32, y: &mut i32) {
67 //~[stack]^ ERROR: protect
8 //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/
79 *x = 1; //~[tree] ERROR: /write access through .* is forbidden/
810 *y = 2;
911}
src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree_iwrites.stderr created+31
......@@ -0,0 +1,31 @@
1error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC
3 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC
14 |
15LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) };
16 | ^^^^^^
17help: the protected tag <TAG> was created here, in the initial state Reserved
18 --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC
19 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: 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
22//@[tree]compile-flags: -Zmiri-tree-borrows
3//@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes
34use std::mem;
45
56fn safe(x: &i32, y: &mut i32) {
67 //~[stack]^ ERROR: protect
8 //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/
79 let _v = *x;
810 *y = 2; //~[tree] ERROR: /write access through .* is forbidden/
911}
src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree_iwrites.stderr created+31
......@@ -0,0 +1,31 @@
1error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC
3 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC
14 |
15LL | let xref = &mut x;
16 | ^^^^^^
17help: the protected tag <TAG> was created here, in the initial state Frozen
18 --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC
19 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: 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
22//@[tree]compile-flags: -Zmiri-tree-borrows
3//@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes
34use std::mem;
45
56fn safe(x: &mut i32, y: &i32) {
67 //~[stack]^ ERROR: borrow stack
8 //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/
79 *x = 1; //~[tree] ERROR: /write access through .* is forbidden/
810 let _v = *y;
911}
src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree_iwrites.stderr created+30
......@@ -0,0 +1,30 @@
1error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC
3 |
4LL | 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)
10help: the accessed tag <TAG> was created here, in the initial state Frozen
11 --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC
12 |
13LL | let xshr = &*xref;
14 | ^^^^^^
15help: 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 |
18LL | 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
27note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
28
29error: 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
22//@[tree]compile-flags: -Zmiri-tree-borrows
33//@[tree]error-in-other-file: /write access through .* is forbidden/
4//@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes
45use std::cell::Cell;
56use std::mem;
67
78// Make sure &mut UnsafeCell also is exclusive
89fn safe(x: &i32, y: &mut Cell<i32>) {
910 //~[stack]^ ERROR: protect
11 //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/
1012 y.set(1);
1113 let _load = *x;
1214}
src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree_iwrites.stderr created+31
......@@ -0,0 +1,31 @@
1error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC
3 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC
14 |
15LL | let xref = &mut x;
16 | ^^^^^^
17help: the protected tag <TAG> was created here, in the initial state Frozen
18 --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC
19 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: aborting due to 1 previous error
31
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs+2
......@@ -1,4 +1,6 @@
11//! 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
24//@compile-flags: -Zmiri-tree-borrows
35#[path = "../../utils/mod.rs"]
46#[macro_use]
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr deleted-25
......@@ -1,25 +0,0 @@
1──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 4.. 8
4| Act | Act | └─┬──<TAG=root of the allocation>
5| Frz |?Cel | └────<TAG=a>
6──────────────────────────────────────────────────
7error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden
8 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
9 |
10LL | (*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
16help: the accessed tag <TAG> was created here, in the initial state Cell
17 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
18 |
19LL | let a = &root;
20 | ^^^^^
21
22note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
23
24error: 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 4.. 8
4| Act | Act | └─┬──<TAG=root of the allocation>
5| Frz |?Cel | └────<TAG=a>
6──────────────────────────────────────────────────
7error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden
8 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
9 |
10LL | (*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
16help: the accessed tag <TAG> was created here, in the initial state Cell
17 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
18 |
19LL | let a = &root;
20 | ^^^^^
21
22note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
23
24error: 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 4.. 8
4| Act | Act | └─┬──<TAG=root of the allocation>
5| Frz |?Cel | └────<TAG=a>
6──────────────────────────────────────────────────
7error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden
8 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
9 |
10LL | (*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
16help: the accessed tag <TAG> was created here, in the initial state Cell
17 --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
18 |
19LL | let a = &root;
20 | ^^^^^
21
22note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
23
24error: 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
5fn 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
16pub 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 @@
1error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs:LL:CC
3 |
4LL | 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)
10help: 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 |
13LL | let b = unsafe { &mut *ptr };
14 | ^^^^^^^^^
15help: 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 |
18LL | 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
22note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
23
24error: 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
5fn 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
14trait Bad {
15 fn do_bad(&mut self) {
16 // who knows
17 }
18}
19
20impl Bad for i32 {}
src/tools/miri/tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.stderr created+25
......@@ -0,0 +1,25 @@
1error: Undefined Behavior: read access through <TAG> at ALLOC[0x0] is forbidden
2 --> tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.rs:LL:CC
3 |
4LL | 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
10help: 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 |
13LL | let z = &mut x as *mut i32;
14 | ^^^^^^
15help: 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 |
18LL | fn do_bad(&mut self) {
19 | ^^^^^^^^^
20 = help: this transition corresponds to a loss of read and write permissions
21
22note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
23
24error: 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
4fn 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
11fn 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 @@
1error: 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 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC
14 |
15LL | let ptr = &raw mut x;
16 | ^^^^^^^^^^
17help: 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 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: 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
4fn 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
11fn 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 @@
1error: 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 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC
14 |
15LL | let mut x: Box<u8> = Box::new(0u8);
16 | ^^^^^^^^^^^^^
17help: 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 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: 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
4use std::cell::UnsafeCell;
5
6fn 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
13fn 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 @@
1error: 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 |
4LL | 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
12help: the accessed tag <TAG> was created here
13 --> tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC
14 |
15LL | let ptr = x.get();
16 | ^^^^^^^
17help: 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 |
20LL | 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
28note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
29
30error: 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
5use std::ptr::addr_of_mut;
6use std::sync::{Arc, Barrier};
7use std::thread;
8
9#[derive(Copy, Clone)]
10struct SendPtr(*mut u8);
11
12unsafe impl Send for SendPtr {}
13
14fn 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
23fn 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
36fn 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 @@
1error: 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 |
4LL | fn write(y: &mut u8, v: u8, barrier: &Arc<Barrier>) {
5 | ^ (2) just happened here
6 |
7help: and (1) occurred earlier here
8 --> tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC
9 |
10LL | 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
25note: 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 |
28LL | let h2 = thread::spawn(move || thread_2(p, b2));
29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30
31note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
32
33error: 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
3static X: usize = 5;
4
5#[allow(mutable_transmutes)]
6fn main() {
7 let x = unsafe { std::mem::transmute::<&usize, &mut usize>(&X) };
8 foo(x);
9}
10
11fn 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 @@
1error: Undefined Behavior: writing to ALLOC which is read-only
2 --> tests/fail/tree_borrows/implicit_writes/static_memory_modification.rs:LL:CC
3 |
4LL | 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
15note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
16
17error: 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() {
4343 #[cfg(target_os = "linux")]
4444 test_sync_file_range();
4545 test_fstat();
46 test_stat();
47 test_lstat();
4648 test_isatty();
4749 test_read_and_uninit();
4850 test_nofollow_not_symlink();
......@@ -50,6 +52,147 @@ fn main() {
5052 test_ioctl();
5153 test_opendir_closedir();
5254 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]
65fn 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")]
99fn 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")]
127fn 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")]
154fn 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 }
53196}
54197
55198fn test_file_open_unix_allow_two_args() {
......@@ -464,24 +607,55 @@ fn test_fstat() {
464607 assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG);
465608
466609 // 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
615fn 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);
481631
482632 remove_file(&path).unwrap();
483633}
484634
635fn 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
485659fn test_isatty() {
486660 // Testing whether our isatty shim returns the right value would require controlling whether
487661 // these streams are actually TTYs, which is hard.
......@@ -651,3 +825,21 @@ fn test_readdir() {
651825 remove_file(&file2).unwrap();
652826 remove_dir(&dir_path).unwrap();
653827}
828
829/// Check that all common fields of a `stat` struct are initialized.
830pub 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!";
1616
1717fn main() {
1818 test_create_close();
19 test_create_close_tcp();
1920 test_bind_ipv4();
2021 test_bind_ipv4_reuseaddr();
2122 test_set_reuseaddr_invalid_len();
......@@ -59,6 +60,21 @@ fn test_create_close() {
5960 unsafe { errno_check(libc::close(sockfd)) };
6061}
6162
63/// Test creating a socket and then closing it afterwards but we explicitly
64/// specify that the TCP protocol should be used.
65fn 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
6278fn test_bind_ipv4() {
6379 let sockfd =
6480 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34trait Foo {
45 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34fn main() {
45 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
23//@compile-flags: -Zmiri-strict-provenance
34//@[tree]compile-flags: -Zmiri-tree-borrows
45
src/tools/miri/tests/pass/async-drop.tree_implicit_writes.stdout created+23
......@@ -0,0 +1,23 @@
1AsyncInt::async_drop: 0
2AsyncInt::async_drop: 1
3AsyncInt::async_drop: 2
4AsyncInt::async_drop: 3
5AsyncInt::async_drop: 4
6AsyncStruct::async_drop: 6
7AsyncInt::async_drop: 7
8AsyncInt::async_drop: 8
9AsyncReference::async_drop: 10
10AsyncInt::async_drop: 11
11AsyncEnum(A)::async_drop: 12
12SyncInt::drop: 12
13AsyncEnum(B)::async_drop: 13
14AsyncInt::async_drop: 13
15SyncInt::drop: 14
16SyncThenAsync::drop: 15
17AsyncInt::async_drop: 16
18SyncInt::drop: 17
19AsyncInt::async_drop: 18
20AsyncInt::async_drop: 19
21AsyncInt::async_drop: 20
22AsyncUnion::async_drop: 21, 21
23AsyncInt::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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-strict-provenance
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34
45trait 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(allocator_api)]
45use 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
23//@compile-flags: -Zmiri-permissive-provenance
34//@[tree]compile-flags: -Zmiri-tree-borrows
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![allow(dangerous_implicit_autorefs)]
45
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
23//@compile-flags: -Zmiri-permissive-provenance
34//@[tree]compile-flags: -Zmiri-tree-borrows
45use std::cell::Cell;
src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs+2-1
......@@ -1,7 +1,8 @@
11// Check that `MaybeDangling` actually prevents UB when it wraps dangling
22// boxes and references
33//
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
56//@[tree]compile-flags: -Zmiri-tree-borrows
67#![feature(maybe_dangling)]
78
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(unsafe_pinned)]
45
src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs+2-1
......@@ -2,7 +2,8 @@
22//! If `Box` has a local allocator, then it can't be `noalias` as the allocator
33//! may want to access allocator state based on the data pointer.
44
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
67//@[tree]compile-flags: -Zmiri-tree-borrows
78#![feature(allocator_api)]
89
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-strict-provenance
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34// Check that you can cast between different pointers to trait objects
45// 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-strict-provenance
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34// We use `yield` to test specific interleavings, so disable automatic preemption.
45//@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 @@
1before wait
2before wait
3before wait
4before wait
5before wait
6before wait
7before wait
8before wait
9before wait
10before wait
11after wait
12after wait
13after wait
14after wait
15after wait
16after wait
17after wait
18after wait
19after wait
20after 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)]
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=no
45
src/tools/miri/tests/pass/disjoint-array-accesses.rs+2-1
......@@ -2,7 +2,8 @@
22// unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no
33// tests. This is a collection of a few code samples from that issue.
44
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
67//@[tree]compile-flags: -Zmiri-tree-borrows
78
89struct 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(arbitrary_self_types_pointers, unsize, coerce_unsized, dispatch_from_dyn)]
45#![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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(extern_types)]
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34use std::cell::UnsafeCell;
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(linked_list_cursors)]
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34// Make sure validation can handle many overlapping shared borrows for different parts of a data structure
45use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-ignore-leaks
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34// This tests that the size of Option<Box<i32>> is the same as *const i32.
45fn 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34use std::{mem, ptr};
45
src/tools/miri/tests/pass/ptr_int_casts.rs+2-1
......@@ -1,5 +1,6 @@
11//@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
34//@[tree]compile-flags: -Zmiri-tree-borrows
45use std::{mem, ptr};
56
src/tools/miri/tests/pass/ptr_int_from_exposed.rs+2-1
......@@ -1,5 +1,6 @@
11//@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
34//@[tree]compile-flags: -Zmiri-tree-borrows
45
56use 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34// Test what happens when we read parts of a pointer.
45// 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-strict-provenance
45#![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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34use std::sync::Mutex;
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34fn main() {
45 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() {
243243 }
244244 test_mm512_permutexvar_epi64();
245245
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
246273 #[target_feature(enable = "avx512bw")]
247274 unsafe fn test_mm512_shuffle_epi8() {
248275 #[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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34
45// 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-ignore-leaks
45
src/tools/miri/tests/pass/threadleak_ignored.tree_implicit_writes.stderr created+1
......@@ -0,0 +1 @@
1Dropping 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34
45use std::cell::RefCell;
src/tools/miri/tests/pass/tls/tls_macro_drop.tree_implicit_writes.stdout created+8
......@@ -0,0 +1,8 @@
1Dropping: 8 (should be before 'Continue main 1').
2Dropping: 8 (should be before 'Continue main 1').
3Continue main 1.
4Joining: 7 (should be before 'Continue main 2').
5Continue main 2.
6Foo dtor (should be before `Bar dtor`).
7Bar dtor (should be before `Continue main 3`).
8Continue 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34//@compile-flags: -Zmiri-strict-provenance
45
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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34use std::mem;
45
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs+2
......@@ -1,4 +1,6 @@
11// 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
24//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
35#[path = "../../utils/mod.rs"]
46#[macro_use]
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr deleted-16
......@@ -1,16 +0,0 @@
1──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| ReIM| └─┬──<TAG=data>
6|?Cel | ├────<TAG=x>
7|?Cel | └────<TAG=y>
8──────────────────────────────────────────────────
9──────────────────────────────────────────────────
10Warning: this tree is indicative only. Some tags may have been hidden.
110.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| ReIM| └─┬──<TAG=data>
6|?Cel | ├────<TAG=x>
7|?Cel | └────<TAG=y>
8──────────────────────────────────────────────────
9──────────────────────────────────────────────────
10Warning: this tree is indicative only. Some tags may have been hidden.
110.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| ReIM| └─┬──<TAG=data>
6|?Cel | ├────<TAG=x>
7|?Cel | └────<TAG=y>
8──────────────────────────────────────────────────
9──────────────────────────────────────────────────
10Warning: this tree is indicative only. Some tags may have been hidden.
110.. 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
13//@compile-flags: -Zmiri-tree-borrows
24#![feature(box_as_ptr)]
35#[path = "../../utils/mod.rs"]
src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr deleted-7
......@@ -1,7 +0,0 @@
1──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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 @@
11//! The same as `tests/fail/tree-borrows/cell-inside-struct` but with
22//! precise tracking of interior mutability disabled.
3//@revisions: tree tree_implicit_writes
4//@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes
35//@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-no-precise-interior-mut
46#[path = "../../utils/mod.rs"]
57#[macro_use]
src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr deleted-6
......@@ -1,6 +0,0 @@
1──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 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
13//@compile-flags: -Zmiri-tree-borrows
24
35use std::cell::Cell;
src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs+2
......@@ -1,4 +1,6 @@
11// 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
24//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
35
46// 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Res | └─┬──<TAG=data>
6| Res | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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──────────────────────────────────────────────────
18Warning: this tree is indicative only. Some tags may have been hidden.
190.. 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──────────────────────────────────────────────────
28Warning: this tree is indicative only. Some tags may have been hidden.
290.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Res | └─┬──<TAG=data>
6| Res | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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──────────────────────────────────────────────────
18Warning: this tree is indicative only. Some tags may have been hidden.
190.. 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──────────────────────────────────────────────────
28Warning: this tree is indicative only. Some tags may have been hidden.
290.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Res | └─┬──<TAG=data>
6| Res | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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──────────────────────────────────────────────────
18Warning: this tree is indicative only. Some tags may have been hidden.
190.. 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──────────────────────────────────────────────────
28Warning: this tree is indicative only. Some tags may have been hidden.
290.. 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
5unsafe 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
10fn bar(x: &mut u8) {
11 miri_print_borrow_state(miri_get_alloc_id(x), true);
12}
13
14fn 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──────────────────────────────────────────────
20.. 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
4use std::cell::UnsafeCell;
5
6fn main() {
7 normal();
8 unsafe_cell();
9 box_test();
10 as_mut_ptr_test()
11}
12
13fn 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
20fn 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
27fn 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
34fn 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
41fn 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
53const 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
6use std::ptr::addr_of_mut;
7use std::sync::{Arc, Barrier};
8use std::thread;
9
10#[derive(Copy, Clone)]
11struct SendPtr(*mut u8);
12
13unsafe 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
53type 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.
61macro_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
69fn 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
82fn 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
103fn 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 @@
1Thread 1 executing: spawn
2Thread 2 executing: spawn
3Thread 2 executing: read x || retag y
4Thread 1 executing: read x || retag y
5Thread 1 executing: write y
6Thread 2 executing: write y
7Thread 2 executing: exit
8Thread 1 executing: exit
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs+2
......@@ -1,4 +1,6 @@
11// 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
24//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
35
46#[path = "../../utils/mod.rs"]
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr deleted-15
......@@ -1,15 +0,0 @@
1──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Act | └─┬──<TAG=parent>
6| Act | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Act | └─┬──<TAG=parent>
6| Act | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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──────────────────────────────────────────────────
2Warning: this tree is indicative only. Some tags may have been hidden.
30.. 1
4| Act | └─┬──<TAG=root of the allocation>
5| Act | └─┬──<TAG=parent>
6| Act | └────<TAG=x>
7──────────────────────────────────────────────────
8──────────────────────────────────────────────────
9Warning: this tree is indicative only. Some tags may have been hidden.
100.. 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
6use std::ptr::addr_of_mut;
7use std::sync::{Arc, Barrier};
8use std::thread;
9
10#[derive(Copy, Clone)]
11struct SendPtr(*mut u8);
12
13unsafe 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
53type 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.
61macro_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
69fn 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
82fn 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
103fn 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 @@
1Thread 1 executing: spawn
2Thread 2 executing: spawn
3Thread 2 executing: read x || retag y
4Thread 1 executing: read x || retag y
5Thread 1 executing: write y
6Thread 2 executing: write y
7Thread 2 executing: exit
8Thread 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
13//@compile-flags: -Zmiri-tree-borrows
24
35//! 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
13//@compile-flags: -Zmiri-tree-borrows
24#![feature(allocator_api)]
35
......@@ -12,6 +14,7 @@ fn main() {
1214 direct_mut_to_const_raw();
1315 local_addr_of_mut();
1416 returned_mut_is_usable();
17 array_pointer_access();
1518}
1619
1720#[allow(unused_assignments)]
......@@ -102,3 +105,33 @@ fn direct_mut_to_const_raw() {
102105 }
103106 assert_eq!(*x, 1);
104107}
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.
114fn 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
121fn 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
130fn 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
13//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance
24
35pub 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
23//@[tree]compile-flags: -Zmiri-tree-borrows
34#![feature(unsized_fn_params)]
45#![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
23//@compile-flags: -Zmiri-strict-provenance
34//@[tree]compile-flags: -Zmiri-tree-borrows
45use std::collections::VecDeque;
tests/codegen-llvm/cffi/c-variadic-naked.rs+1-1
......@@ -1,5 +1,5 @@
11//@ needs-asm-support
2//@ only-x86_64
2//@ needs-asm-mnemonic: ret
33
44// tests that `va_start` is not injected into naked functions
55
tests/codegen-llvm/naked-fn/aligned.rs+1-1
......@@ -1,6 +1,6 @@
11//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
22//@ needs-asm-support
3//@ ignore-arm no "ret" mnemonic
3//@ needs-asm-mnemonic: ret
44//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
55
66#![crate_type = "lib"]
tests/codegen-llvm/naked-fn/min-function-alignment.rs+1-1
......@@ -1,6 +1,6 @@
11//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16
22//@ needs-asm-support
3//@ ignore-arm no "ret" mnemonic
3//@ needs-asm-mnemonic: ret
44//@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368)
55
66// 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>
2corrupt.o/ 0 0 0 100644 10000 `
3small_data
tests/run-make/archive-corrupt-error/lib.rs created+3
......@@ -0,0 +1,3 @@
1extern "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
7use run_make_support::{path, rfs, rustc, static_lib_name};
8
9fn 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 @@
1extern "C" {
2 fn foo() -> i32;
3}
tests/run-make/archive-format-error/native.c created+1
......@@ -0,0 +1 @@
1int 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
7use run_make_support::{cc, llvm_ar, path, rfs, rustc, static_lib_name};
8
9fn 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 @@
1echo Called dlltool via script.cmd> actual.txt
1echo Called dlltool via script.cmd> %~dp0\actual.txt
22dlltool.exe %*
tests/run-make/raw-dylib-whitespace/main.rs created+18
......@@ -0,0 +1,18 @@
1type 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"))]
8extern "system" {
9 fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
10}
11
12fn 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
9use run_make_support::{rfs, rustc};
10
11fn 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
18unsafe extern "C" {
19 #[cfg(not(feature = "banana"))]
20 pub fn doc_cfg_works();
21}
22
23#[cfg(not(feature = "banana"))]
24unsafe extern "C" {
25 pub fn doc_cfg_doesnt_work();
26}
tests/ui/cfg/cfg-target-compact-errors.rs+13
......@@ -4,22 +4,35 @@
44
55#[cfg(target(o::o))]
66//~^ 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
712fn one() {}
813
914#[cfg(target(os = 8))]
1015//~^ ERROR malformed `cfg` attribute input
16//~| NOTE expected a string literal here
17//~| NOTE for more information, visit
1118fn two() {}
1219
1320#[cfg(target(os = "linux", pointer(width = "64")))]
1421//~^ ERROR malformed `cfg` attribute input
22//~| NOTE expected this to be of the form `... = "..."`
23//~| NOTE for more information, visit
1524fn three() {}
1625
1726#[cfg(target(true))]
1827//~^ ERROR malformed `cfg` attribute input
28//~| NOTE expected this to be of the form `... = "..."`
29//~| NOTE for more information, visit
1930fn four() {}
2031
2132#[cfg(target(clippy::os = "linux"))]
2233//~^ ERROR malformed `cfg` attribute input
34//~| NOTE for more information, visit
35//~| NOTE expected a valid identifier here
2336fn five() {}
2437
2538fn main() {}
tests/ui/cfg/cfg-target-compact-errors.stderr+20-5
......@@ -1,3 +1,18 @@
1error[E0539]: malformed `cfg` attribute input
2 --> $DIR/cfg-target-compact-errors.rs:5:1
3 |
4LL | #[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>
10help: must be of the form
11 |
12LL - #[cfg(target(o::o))]
13LL + #[cfg(predicate)]
14 |
15
116error[E0539]: malformed `cfg` attribute input
217 --> $DIR/cfg-target-compact-errors.rs:5:1
318 |
......@@ -14,7 +29,7 @@ LL + #[cfg(predicate)]
1429 |
1530
1631error[E0539]: malformed `cfg` attribute input
17 --> $DIR/cfg-target-compact-errors.rs:9:1
32 --> $DIR/cfg-target-compact-errors.rs:14:1
1833 |
1934LL | #[cfg(target(os = 8))]
2035 | ^^^^^^^^^^^^^^^^^^-^^^
......@@ -29,7 +44,7 @@ LL + #[cfg(predicate)]
2944 |
3045
3146error[E0539]: malformed `cfg` attribute input
32 --> $DIR/cfg-target-compact-errors.rs:13:1
47 --> $DIR/cfg-target-compact-errors.rs:20:1
3348 |
3449LL | #[cfg(target(os = "linux", pointer(width = "64")))]
3550 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^^^
......@@ -44,7 +59,7 @@ LL + #[cfg(predicate)]
4459 |
4560
4661error[E0539]: malformed `cfg` attribute input
47 --> $DIR/cfg-target-compact-errors.rs:17:1
62 --> $DIR/cfg-target-compact-errors.rs:26:1
4863 |
4964LL | #[cfg(target(true))]
5065 | ^^^^^^^^^^^^^----^^^
......@@ -59,7 +74,7 @@ LL + #[cfg(predicate)]
5974 |
6075
6176error[E0539]: malformed `cfg` attribute input
62 --> $DIR/cfg-target-compact-errors.rs:21:1
77 --> $DIR/cfg-target-compact-errors.rs:32:1
6378 |
6479LL | #[cfg(target(clippy::os = "linux"))]
6580 | ^^^^^^^^^^^^^----------^^^^^^^^^^^^^
......@@ -73,6 +88,6 @@ LL - #[cfg(target(clippy::os = "linux"))]
7388LL + #[cfg(predicate)]
7489 |
7590
76error: aborting due to 5 previous errors
91error: aborting due to 6 previous errors
7792
7893For 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 @@
1pub struct P;
2pub struct Map<F>(pub F);
3
4pub 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
14impl 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
29pub fn to_fn<F>(f: F) -> Map<F>
30where
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
13// Regression test for #125325
24
35// Tests that we suggest changing an `impl Fn` param
......@@ -6,6 +8,10 @@
68// Ensures that it works that way for both
79// functions and methods
810
11extern crate wrong_closure_arg_suggestion_aux as aux;
12
13use aux::{P, PIter, to_fn};
14
915struct S;
1016
1117impl S {
......@@ -26,4 +32,37 @@ fn test_func(s: &S) -> usize {
2632 //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure
2733}
2834
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.
40struct Counter {
41 counter: i32,
42}
43
44impl 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
62fn take<F, U>(_: F)
63where
64 F: Fn(i32) -> U,
65{
66}
67
2968fn main() {}
tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr+74-4
......@@ -1,5 +1,5 @@
11error[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
33 |
44LL | fn assoc_func(&self, _f: impl Fn()) -> usize {
55 | --------- change this to accept `FnMut` instead of `Fn`
......@@ -14,7 +14,7 @@ LL | s.assoc_func(|| x = ());
1414 | expects `Fn` instead of `FnMut`
1515
1616error[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
1818 |
1919LL | fn func(_f: impl Fn()) -> usize {
2020 | --------- change this to accept `FnMut` instead of `Fn`
......@@ -28,6 +28,76 @@ LL | func(|| x = ())
2828 | | in this closure
2929 | expects `Fn` instead of `FnMut`
3030
31error: aborting due to 2 previous errors
31error[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 |
34LL | take(|_| to_fn(|_| self.counter += 1));
35 | ----- --- ^^^^^^^^^^^^^^^^^ cannot assign
36 | | |
37 | | in this closure
38 | expects `Fn` instead of `FnMut`
39
40error: lifetime may not live long enough
41 --> $DIR/wrong-closure-arg-suggestion-125325.rs:46:18
42 |
43LL | 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
51error[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 |
54LL | 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...
61LL | fn take<F, U>(_: F)
62 | - change this to accept `FnMut` instead of `Fn`
63
64error[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 |
67LL | P.flat_map(|_| P.map(|_| self.counter += 1));
68 | --------^^^^^^^^^^^^^^^^^-
69 | | | |
70 | | | cannot assign
71 | | in this closure
72 | expects `Fn` instead of `FnMut`
73
74error: lifetime may not live long enough
75 --> $DIR/wrong-closure-arg-suggestion-125325.rs:54:24
76 |
77LL | 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
84help: consider adding 'move' keyword before the nested closure
85 |
86LL | P.flat_map(|_| P.map(move |_| self.counter += 1));
87 | ++++
88
89error[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 |
92LL | 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
100error: aborting due to 8 previous errors
32101
33For more information about this error, try `rustc --explain E0594`.
102Some errors have detailed explanations: E0594, E0596.
103For more information about an error, try `rustc --explain E0594`.
tests/ui/consts/const-eval/c-variadic-fail.rs+67-10
......@@ -6,7 +6,7 @@
66#![feature(const_destruct)]
77#![feature(const_clone)]
88
9use std::ffi::VaList;
9use std::ffi::{VaList, c_char, c_void};
1010use std::mem::MaybeUninit;
1111
1212const 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 {
3737 ap.next_arg::<T>()
3838}
3939
40unsafe fn read_cast() {
40unsafe fn read_cast_numeric() {
4141 const { read_as::<i32>(1i32) };
4242 const { read_as::<u32>(1u32) };
4343
......@@ -47,20 +47,76 @@ unsafe fn read_cast() {
4747 const { read_as::<i64>(1i64) };
4848 const { read_as::<u64>(1u64) };
4949
50 // A cast between signed and unsigned is OK so long as both types can represent the value.
5051 const { read_as::<u32>(1i32) };
51 //~^ ERROR va_arg type mismatch: requested `u32`, but next argument is `i32`
52
5352 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`
5584
5685 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`
5887
5988 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}
6191
62 const { read_as::<*const u8>(1i32) };
63 //~^ ERROR va_arg type mismatch: requested `*const u8`, but next argument is `i32`
92unsafe 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`
64120}
65121
66122fn use_after_free() {
......@@ -138,7 +194,8 @@ fn drop_of_invalid() {
138194fn main() {
139195 unsafe {
140196 read_too_many();
141 read_cast();
197 read_cast_numeric();
198 read_cast_pointer();
142199 manual_copy_read();
143200 manual_copy_drop();
144201 manual_copy_forget();
tests/ui/consts/const-eval/c-variadic-fail.stderr+255-59
......@@ -54,11 +54,11 @@ LL | const { read_n::<2>(1) }
5454 |
5555 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
5656
57error[E0080]: va_arg type mismatch: requested `u32`, but next argument is `i32`
58 --> $DIR/c-variadic-fail.rs:50:13
57error[E0080]: va_arg value mismatch: value `-1_i32` cannot be represented by type `u32`
58 --> $DIR/c-variadic-fail.rs:72:13
5959 |
60LL | const { read_as::<u32>(1i32) };
61 | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#6}` failed inside this call
60LL | const { read_as::<u32>(-1i32) };
61 | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#12}` failed inside this call
6262 |
6363note: inside `read_as::<u32>`
6464 --> $DIR/c-variadic-fail.rs:37:5
......@@ -69,24 +69,52 @@ note: inside `VaList::<'_>::next_arg::<u32>`
6969 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
7070
7171note: erroneous constant encountered
72 --> $DIR/c-variadic-fail.rs:50:5
72 --> $DIR/c-variadic-fail.rs:72:5
7373 |
74LL | const { read_as::<u32>(1i32) };
75 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
74LL | const { read_as::<u32>(-1i32) };
75 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7676
7777note: erroneous constant encountered
78 --> $DIR/c-variadic-fail.rs:50:5
78 --> $DIR/c-variadic-fail.rs:72:5
7979 |
80LL | const { read_as::<u32>(1i32) };
81 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
80LL | const { read_as::<u32>(-1i32) };
81 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82 |
83 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
84
85error[E0080]: va_arg value mismatch: value `-2147483648_i32` cannot be represented by type `u32`
86 --> $DIR/c-variadic-fail.rs:74:13
87 |
88LL | const { read_as::<u32>(i32::MIN) };
89 | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#13}` failed inside this call
90 |
91note: inside `read_as::<u32>`
92 --> $DIR/c-variadic-fail.rs:37:5
93 |
94LL | ap.next_arg::<T>()
95 | ^^^^^^^^^^^^^^^^^^
96note: inside `VaList::<'_>::next_arg::<u32>`
97 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
98
99note: erroneous constant encountered
100 --> $DIR/c-variadic-fail.rs:74:5
101 |
102LL | const { read_as::<u32>(i32::MIN) };
103 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
104
105note: erroneous constant encountered
106 --> $DIR/c-variadic-fail.rs:74:5
107 |
108LL | const { read_as::<u32>(i32::MIN) };
109 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82110 |
83111 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
84112
85error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u32`
86 --> $DIR/c-variadic-fail.rs:53:13
113error[E0080]: va_arg value mismatch: value `4294967295_u32` cannot be represented by type `i32`
114 --> $DIR/c-variadic-fail.rs:76:13
87115 |
88LL | const { read_as::<i32>(1u32) };
89 | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#7}` failed inside this call
116LL | const { read_as::<i32>(u32::MAX) };
117 | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#14}` failed inside this call
90118 |
91119note: inside `read_as::<i32>`
92120 --> $DIR/c-variadic-fail.rs:37:5
......@@ -97,24 +125,108 @@ note: inside `VaList::<'_>::next_arg::<i32>`
97125 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
98126
99127note: erroneous constant encountered
100 --> $DIR/c-variadic-fail.rs:53:5
128 --> $DIR/c-variadic-fail.rs:76:5
101129 |
102LL | const { read_as::<i32>(1u32) };
103 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
130LL | const { read_as::<i32>(u32::MAX) };
131 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
104132
105133note: erroneous constant encountered
106 --> $DIR/c-variadic-fail.rs:53:5
134 --> $DIR/c-variadic-fail.rs:76:5
107135 |
108LL | const { read_as::<i32>(1u32) };
109 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
136LL | const { read_as::<i32>(u32::MAX) };
137 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138 |
139 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
140
141error[E0080]: va_arg value mismatch: value `2147483648_u32` cannot be represented by type `i32`
142 --> $DIR/c-variadic-fail.rs:78:13
143 |
144LL | const { read_as::<i32>(i32::MAX as u32 + 1) };
145 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#15}` failed inside this call
146 |
147note: inside `read_as::<i32>`
148 --> $DIR/c-variadic-fail.rs:37:5
149 |
150LL | ap.next_arg::<T>()
151 | ^^^^^^^^^^^^^^^^^^
152note: inside `VaList::<'_>::next_arg::<i32>`
153 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
154
155note: erroneous constant encountered
156 --> $DIR/c-variadic-fail.rs:78:5
157 |
158LL | const { read_as::<i32>(i32::MAX as u32 + 1) };
159 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160
161note: erroneous constant encountered
162 --> $DIR/c-variadic-fail.rs:78:5
163 |
164LL | const { read_as::<i32>(i32::MAX as u32 + 1) };
165 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
166 |
167 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
168
169error[E0080]: va_arg value mismatch: value `18446744073709551615_u64` cannot be represented by type `i64`
170 --> $DIR/c-variadic-fail.rs:80:13
171 |
172LL | const { read_as::<i64>(u64::MAX) };
173 | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#16}` failed inside this call
174 |
175note: inside `read_as::<i64>`
176 --> $DIR/c-variadic-fail.rs:37:5
177 |
178LL | ap.next_arg::<T>()
179 | ^^^^^^^^^^^^^^^^^^
180note: inside `VaList::<'_>::next_arg::<i64>`
181 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
182
183note: erroneous constant encountered
184 --> $DIR/c-variadic-fail.rs:80:5
185 |
186LL | const { read_as::<i64>(u64::MAX) };
187 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
188
189note: erroneous constant encountered
190 --> $DIR/c-variadic-fail.rs:80:5
191 |
192LL | const { read_as::<i64>(u64::MAX) };
193 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
194 |
195 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
196
197error[E0080]: va_arg value mismatch: value `9223372036854775808_u64` cannot be represented by type `i64`
198 --> $DIR/c-variadic-fail.rs:82:13
199 |
200LL | const { read_as::<i64>(i64::MAX as u64 + 1) };
201 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#17}` failed inside this call
202 |
203note: inside `read_as::<i64>`
204 --> $DIR/c-variadic-fail.rs:37:5
205 |
206LL | ap.next_arg::<T>()
207 | ^^^^^^^^^^^^^^^^^^
208note: inside `VaList::<'_>::next_arg::<i64>`
209 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
210
211note: erroneous constant encountered
212 --> $DIR/c-variadic-fail.rs:82:5
213 |
214LL | const { read_as::<i64>(i64::MAX as u64 + 1) };
215 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
216
217note: erroneous constant encountered
218 --> $DIR/c-variadic-fail.rs:82:5
219 |
220LL | const { read_as::<i64>(i64::MAX as u64 + 1) };
221 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
110222 |
111223 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
112224
113error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u64`
114 --> $DIR/c-variadic-fail.rs:56:13
225error[E0080]: va_arg type mismatch: requested `i32` is incompatible with next argument of type `u64`
226 --> $DIR/c-variadic-fail.rs:85:13
115227 |
116228LL | 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
118230 |
119231note: inside `read_as::<i32>`
120232 --> $DIR/c-variadic-fail.rs:37:5
......@@ -125,24 +237,24 @@ note: inside `VaList::<'_>::next_arg::<i32>`
125237 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
126238
127239note: erroneous constant encountered
128 --> $DIR/c-variadic-fail.rs:56:5
240 --> $DIR/c-variadic-fail.rs:85:5
129241 |
130242LL | const { read_as::<i32>(1u64) };
131243 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
132244
133245note: erroneous constant encountered
134 --> $DIR/c-variadic-fail.rs:56:5
246 --> $DIR/c-variadic-fail.rs:85:5
135247 |
136248LL | const { read_as::<i32>(1u64) };
137249 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
138250 |
139251 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
140252
141error[E0080]: va_arg type mismatch: requested `f64`, but next argument is `i32`
142 --> $DIR/c-variadic-fail.rs:59:13
253error[E0080]: va_arg type mismatch: requested `f64` is incompatible with next argument of type `i32`
254 --> $DIR/c-variadic-fail.rs:88:13
143255 |
144256LL | 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
146258 |
147259note: inside `read_as::<f64>`
148260 --> $DIR/c-variadic-fail.rs:37:5
......@@ -153,24 +265,108 @@ note: inside `VaList::<'_>::next_arg::<f64>`
153265 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
154266
155267note: erroneous constant encountered
156 --> $DIR/c-variadic-fail.rs:59:5
268 --> $DIR/c-variadic-fail.rs:88:5
157269 |
158270LL | const { read_as::<f64>(1i32) };
159271 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160272
161273note: erroneous constant encountered
162 --> $DIR/c-variadic-fail.rs:59:5
274 --> $DIR/c-variadic-fail.rs:88:5
163275 |
164276LL | const { read_as::<f64>(1i32) };
165277 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
166278 |
167279 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
168280
169error[E0080]: va_arg type mismatch: requested `*const u8`, but next argument is `i32`
170 --> $DIR/c-variadic-fail.rs:62:13
281error[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 |
284LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) };
285 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#12}` failed inside this call
286 |
287note: inside `read_as::<*const u16>`
288 --> $DIR/c-variadic-fail.rs:37:5
289 |
290LL | ap.next_arg::<T>()
291 | ^^^^^^^^^^^^^^^^^^
292note: inside `VaList::<'_>::next_arg::<*const u16>`
293 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
294
295note: erroneous constant encountered
296 --> $DIR/c-variadic-fail.rs:111:5
297 |
298LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) };
299 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
300
301note: erroneous constant encountered
302 --> $DIR/c-variadic-fail.rs:111:5
303 |
304LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) };
305 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
306 |
307 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
308
309error[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 |
312LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) };
313 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#13}` failed inside this call
171314 |
172LL | const { read_as::<*const u8>(1i32) };
173 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#10}` failed inside this call
315note: inside `read_as::<*const c_void>`
316 --> $DIR/c-variadic-fail.rs:37:5
317 |
318LL | ap.next_arg::<T>()
319 | ^^^^^^^^^^^^^^^^^^
320note: inside `VaList::<'_>::next_arg::<*const c_void>`
321 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
322
323note: erroneous constant encountered
324 --> $DIR/c-variadic-fail.rs:113:5
325 |
326LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) };
327 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
328
329note: erroneous constant encountered
330 --> $DIR/c-variadic-fail.rs:113:5
331 |
332LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) };
333 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
334 |
335 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
336
337error[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 |
340LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) };
341 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#14}` failed inside this call
342 |
343note: inside `read_as::<*const u16>`
344 --> $DIR/c-variadic-fail.rs:37:5
345 |
346LL | ap.next_arg::<T>()
347 | ^^^^^^^^^^^^^^^^^^
348note: inside `VaList::<'_>::next_arg::<*const u16>`
349 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
350
351note: erroneous constant encountered
352 --> $DIR/c-variadic-fail.rs:115:5
353 |
354LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) };
355 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
356
357note: erroneous constant encountered
358 --> $DIR/c-variadic-fail.rs:115:5
359 |
360LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) };
361 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
362 |
363 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
364
365error[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 |
368LL | const { read_as::<*const u8>(1usize) };
369 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#15}` failed inside this call
174370 |
175371note: inside `read_as::<*const u8>`
176372 --> $DIR/c-variadic-fail.rs:37:5
......@@ -181,21 +377,21 @@ note: inside `VaList::<'_>::next_arg::<*const u8>`
181377 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
182378
183379note: erroneous constant encountered
184 --> $DIR/c-variadic-fail.rs:62:5
380 --> $DIR/c-variadic-fail.rs:118:5
185381 |
186LL | const { read_as::<*const u8>(1i32) };
187 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
382LL | const { read_as::<*const u8>(1usize) };
383 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
188384
189385note: erroneous constant encountered
190 --> $DIR/c-variadic-fail.rs:62:5
386 --> $DIR/c-variadic-fail.rs:118:5
191387 |
192LL | const { read_as::<*const u8>(1i32) };
193 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
388LL | const { read_as::<*const u8>(1usize) };
389 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
194390 |
195391 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
196392
197393error[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
199395 |
200396LL | ap.next_arg::<i32>();
201397 | ^^^^^^^^^^^^^^^^^^^^ evaluation of `use_after_free::{constant#0}` failed inside this call
......@@ -204,7 +400,7 @@ note: inside `VaList::<'_>::next_arg::<i32>`
204400 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
205401
206402note: erroneous constant encountered
207 --> $DIR/c-variadic-fail.rs:71:5
403 --> $DIR/c-variadic-fail.rs:127:5
208404 |
209405LL | / const {
210406LL | | unsafe {
......@@ -215,7 +411,7 @@ LL | | };
215411 | |_____^
216412
217413note: erroneous constant encountered
218 --> $DIR/c-variadic-fail.rs:71:5
414 --> $DIR/c-variadic-fail.rs:127:5
219415 |
220416LL | / const {
221417LL | | unsafe {
......@@ -228,13 +424,13 @@ LL | | };
228424 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
229425
230426error[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
232428 |
233429LL | const { unsafe { helper(1, 2, 3) } };
234430 | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_drop::{constant#0}` failed inside this call
235431 |
236432note: inside `manual_copy_drop::helper`
237 --> $DIR/c-variadic-fail.rs:94:9
433 --> $DIR/c-variadic-fail.rs:150:9
238434 |
239435LL | drop(ap);
240436 | ^^^^^^^^
......@@ -246,13 +442,13 @@ note: inside `<VaList<'_> as Drop>::drop`
246442 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
247443
248444note: erroneous constant encountered
249 --> $DIR/c-variadic-fail.rs:97:5
445 --> $DIR/c-variadic-fail.rs:153:5
250446 |
251447LL | const { unsafe { helper(1, 2, 3) } };
252448 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
253449
254450note: erroneous constant encountered
255 --> $DIR/c-variadic-fail.rs:97:5
451 --> $DIR/c-variadic-fail.rs:153:5
256452 |
257453LL | const { unsafe { helper(1, 2, 3) } };
258454 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -260,13 +456,13 @@ LL | const { unsafe { helper(1, 2, 3) } };
260456 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
261457
262458error[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
264460 |
265461LL | const { unsafe { helper(1, 2, 3) } };
266462 | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_forget::{constant#0}` failed inside this call
267463 |
268464note: inside `manual_copy_forget::helper`
269 --> $DIR/c-variadic-fail.rs:110:9
465 --> $DIR/c-variadic-fail.rs:166:9
270466 |
271467LL | drop(ap);
272468 | ^^^^^^^^
......@@ -278,13 +474,13 @@ note: inside `<VaList<'_> as Drop>::drop`
278474 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
279475
280476note: erroneous constant encountered
281 --> $DIR/c-variadic-fail.rs:113:5
477 --> $DIR/c-variadic-fail.rs:169:5
282478 |
283479LL | const { unsafe { helper(1, 2, 3) } };
284480 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
285481
286482note: erroneous constant encountered
287 --> $DIR/c-variadic-fail.rs:113:5
483 --> $DIR/c-variadic-fail.rs:169:5
288484 |
289485LL | const { unsafe { helper(1, 2, 3) } };
290486 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -292,13 +488,13 @@ LL | const { unsafe { helper(1, 2, 3) } };
292488 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
293489
294490error[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
296492 |
297493LL | const { unsafe { helper(1, 2, 3) } };
298494 | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_read::{constant#0}` failed inside this call
299495 |
300496note: inside `manual_copy_read::helper`
301 --> $DIR/c-variadic-fail.rs:123:17
497 --> $DIR/c-variadic-fail.rs:179:17
302498 |
303499LL | let _ = ap.next_arg::<i32>();
304500 | ^^^^^^^^^^^^^^^^^^^^
......@@ -306,13 +502,13 @@ note: inside `VaList::<'_>::next_arg::<i32>`
306502 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
307503
308504note: erroneous constant encountered
309 --> $DIR/c-variadic-fail.rs:126:5
505 --> $DIR/c-variadic-fail.rs:182:5
310506 |
311507LL | const { unsafe { helper(1, 2, 3) } };
312508 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
313509
314510note: erroneous constant encountered
315 --> $DIR/c-variadic-fail.rs:126:5
511 --> $DIR/c-variadic-fail.rs:182:5
316512 |
317513LL | const { unsafe { helper(1, 2, 3) } };
318514 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......@@ -320,7 +516,7 @@ LL | const { unsafe { helper(1, 2, 3) } };
320516 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
321517
322518error[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
324520 |
325521LL | }
326522 | ^ evaluation of `drop_of_invalid::{constant#0}` failed inside this call
......@@ -331,7 +527,7 @@ note: inside `<VaList<'_> as Drop>::drop`
331527 --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL
332528
333529note: erroneous constant encountered
334 --> $DIR/c-variadic-fail.rs:131:5
530 --> $DIR/c-variadic-fail.rs:187:5
335531 |
336532LL | / const {
337533LL | | let mut invalid: MaybeUninit<VaList> = MaybeUninit::zeroed();
......@@ -340,7 +536,7 @@ LL | | }
340536 | |_____^
341537
342538note: erroneous constant encountered
343 --> $DIR/c-variadic-fail.rs:131:5
539 --> $DIR/c-variadic-fail.rs:187:5
344540 |
345541LL | / const {
346542LL | | let mut invalid: MaybeUninit<VaList> = MaybeUninit::zeroed();
......@@ -350,6 +546,6 @@ LL | | }
350546 |
351547 = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
352548
353error: aborting due to 12 previous errors
549error: aborting due to 19 previous errors
354550
355551For 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
2121 |
2222LL | impl<T> const Drop for ConstDrop2<T> {
2323 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24help: consider restricting type parameter `T` with unstable trait `Destruct`
25 |
26LL | impl<T: [const] Destruct> const Drop for ConstDrop2<T> {
27 | ++++++++++++++++++
2428
2529error: aborting due to 2 previous errors
2630
tests/ui/consts/trait_alias.fail.stderr+5
......@@ -3,6 +3,11 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied
33 |
44LL | x.baz();
55 | ^^^
6 |
7help: consider further restricting type parameter `T` with trait `Baz`
8 |
9LL | const fn foo<T: [const] Foo + [const] Baz>(x: &T) {
10 | +++++++++++++
611
712error: aborting due to 1 previous error
813
tests/ui/consts/trait_alias.next_fail.stderr+5
......@@ -3,6 +3,11 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied
33 |
44LL | x.baz();
55 | ^^^
6 |
7help: consider further restricting type parameter `T` with trait `Baz`
8 |
9LL | const fn foo<T: [const] Foo + [const] Baz>(x: &T) {
10 | +++++++++++++
611
712error: aborting due to 1 previous error
813
tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr+6-6
......@@ -5,10 +5,10 @@ LL | use crate::both::private::S;
55 | ^ private struct import
66 |
77note: 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
99 |
10LL | pub(super) use crate::m::*;
11 | ^^^^^^^^^^^
10LL | use crate::m::*;
11 | ^^^^^^^^^^^
1212note: ...and refers to the struct `S` which is defined here
1313 --> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
1414 |
......@@ -27,10 +27,10 @@ LL | use crate::both::private::S;
2727 | ^ private struct import
2828 |
2929note: 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
3131 |
32LL | pub(super) use crate::m::*;
33 | ^^^^^^^^^^^
32LL | use crate::m::*;
33 | ^^^^^^^^^^^
3434note: ...and refers to the struct `S` which is defined here
3535 --> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
3636 |
tests/ui/imports/ambiguous-import-visibility-globglob.rs+12-2
......@@ -1,7 +1,5 @@
11//@ check-pass
22
3// FIXME: should report "ambiguous import visibility" in all the cases below.
4
53mod m {
64 pub struct S {}
75}
......@@ -12,7 +10,11 @@ mod min_vis_first {
1210 pub use crate::m::*;
1311
1412 pub use self::S as S1;
13 //~^ WARN ambiguous import visibility
14 //~| WARN this was previously accepted
1515 pub(crate) use self::S as S2;
16 //~^ WARN ambiguous import visibility
17 //~| WARN this was previously accepted
1618 use self::S as S3; // OK
1719}
1820
......@@ -22,7 +24,11 @@ mod mid_vis_first {
2224 pub use crate::m::*;
2325
2426 pub use self::S as S1;
27 //~^ WARN ambiguous import visibility
28 //~| WARN this was previously accepted
2529 pub(crate) use self::S as S2;
30 //~^ WARN ambiguous import visibility
31 //~| WARN this was previously accepted
2632 use self::S as S3; // OK
2733}
2834
......@@ -32,7 +38,11 @@ mod max_vis_first {
3238 pub(crate) use crate::m::*;
3339
3440 pub use self::S as S1;
41 //~^ WARN ambiguous import visibility
42 //~| WARN this was previously accepted
3543 pub(crate) use self::S as S2;
44 //~^ WARN ambiguous import visibility
45 //~| WARN this was previously accepted
3646 use self::S as S3; // OK
3747}
3848
tests/ui/imports/ambiguous-import-visibility-globglob.stderr created+135
......@@ -0,0 +1,135 @@
1warning: ambiguous import visibility: pub or pub(in crate::min_vis_first)
2 --> $DIR/ambiguous-import-visibility-globglob.rs:12:19
3 |
4LL | pub use self::S as S1;
5 | ^
6 |
7 = note: ambiguous because of multiple glob imports of a name in the same module
8note: `S` could refer to the struct imported here
9 --> $DIR/ambiguous-import-visibility-globglob.rs:10:13
10 |
11LL | pub use crate::m::*;
12 | ^^^^^^^^^^^
13 = help: consider adding an explicit import of `S` to disambiguate
14note: `S` could also refer to the struct imported here
15 --> $DIR/ambiguous-import-visibility-globglob.rs:8:9
16 |
17LL | 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
24warning: ambiguous import visibility: pub(crate) or pub(in crate::min_vis_first)
25 --> $DIR/ambiguous-import-visibility-globglob.rs:15:26
26 |
27LL | pub(crate) use self::S as S2;
28 | ^
29 |
30 = note: ambiguous because of multiple glob imports of a name in the same module
31note: `S` could refer to the struct imported here
32 --> $DIR/ambiguous-import-visibility-globglob.rs:10:13
33 |
34LL | pub use crate::m::*;
35 | ^^^^^^^^^^^
36 = help: consider adding an explicit import of `S` to disambiguate
37note: `S` could also refer to the struct imported here
38 --> $DIR/ambiguous-import-visibility-globglob.rs:8:9
39 |
40LL | 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
46warning: ambiguous import visibility: pub or pub(in crate::mid_vis_first)
47 --> $DIR/ambiguous-import-visibility-globglob.rs:26:19
48 |
49LL | pub use self::S as S1;
50 | ^
51 |
52 = note: ambiguous because of multiple glob imports of a name in the same module
53note: `S` could refer to the struct imported here
54 --> $DIR/ambiguous-import-visibility-globglob.rs:24:13
55 |
56LL | pub use crate::m::*;
57 | ^^^^^^^^^^^
58 = help: consider adding an explicit import of `S` to disambiguate
59note: `S` could also refer to the struct imported here
60 --> $DIR/ambiguous-import-visibility-globglob.rs:23:9
61 |
62LL | 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
68warning: ambiguous import visibility: pub(crate) or pub(in crate::mid_vis_first)
69 --> $DIR/ambiguous-import-visibility-globglob.rs:29:26
70 |
71LL | pub(crate) use self::S as S2;
72 | ^
73 |
74 = note: ambiguous because of multiple glob imports of a name in the same module
75note: `S` could refer to the struct imported here
76 --> $DIR/ambiguous-import-visibility-globglob.rs:24:13
77 |
78LL | pub use crate::m::*;
79 | ^^^^^^^^^^^
80 = help: consider adding an explicit import of `S` to disambiguate
81note: `S` could also refer to the struct imported here
82 --> $DIR/ambiguous-import-visibility-globglob.rs:23:9
83 |
84LL | 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
90warning: ambiguous import visibility: pub or pub(in crate::max_vis_first)
91 --> $DIR/ambiguous-import-visibility-globglob.rs:40:19
92 |
93LL | pub use self::S as S1;
94 | ^
95 |
96 = note: ambiguous because of multiple glob imports of a name in the same module
97note: `S` could refer to the struct imported here
98 --> $DIR/ambiguous-import-visibility-globglob.rs:36:13
99 |
100LL | pub use crate::m::*;
101 | ^^^^^^^^^^^
102 = help: consider adding an explicit import of `S` to disambiguate
103note: `S` could also refer to the struct imported here
104 --> $DIR/ambiguous-import-visibility-globglob.rs:37:9
105 |
106LL | 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
112warning: ambiguous import visibility: pub(crate) or pub(in crate::max_vis_first)
113 --> $DIR/ambiguous-import-visibility-globglob.rs:43:26
114 |
115LL | pub(crate) use self::S as S2;
116 | ^
117 |
118 = note: ambiguous because of multiple glob imports of a name in the same module
119note: `S` could refer to the struct imported here
120 --> $DIR/ambiguous-import-visibility-globglob.rs:36:13
121 |
122LL | pub use crate::m::*;
123 | ^^^^^^^^^^^
124 = help: consider adding an explicit import of `S` to disambiguate
125note: `S` could also refer to the struct imported here
126 --> $DIR/ambiguous-import-visibility-globglob.rs:37:9
127 |
128LL | 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
134warning: 6 warnings emitted
135
tests/ui/imports/overwrite-vis-unused.rs+2-2
......@@ -1,12 +1,12 @@
11// Regression test for issues #152004 and #151124.
2
2//@ check-pass
33#![deny(unused)]
44
55mod m {
66 pub struct S {}
77}
88
9use m::*; //~ ERROR unused import: `m::*`
9use m::*;
1010pub use m::*;
1111
1212fn main() {}
tests/ui/imports/overwrite-vis-unused.stderr deleted-15
......@@ -1,15 +0,0 @@
1error: unused import: `m::*`
2 --> $DIR/overwrite-vis-unused.rs:9:5
3 |
4LL | use m::*;
5 | ^^^^
6 |
7note: the lint level is defined here
8 --> $DIR/overwrite-vis-unused.rs:3:9
9 |
10LL | #![deny(unused)]
11 | ^^^^^^
12 = note: `#[deny(unused_imports)]` implied by `#[deny(unused)]`
13
14error: aborting due to 1 previous error
15
tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs-1
......@@ -7,7 +7,6 @@
77//@ normalize-stderr: "[^ ]*/foo.dll_imports.lib" -> "$$LIB_FILE"
88//@ normalize-stderr: "-m [^ ]*" -> "$$TARGET_MACHINE"
99//@ normalize-stderr: "-f [^ ]*" -> "$$ASM_FLAGS"
10//@ normalize-stderr: "--temp-prefix [^ ]*/foo.dll" -> "$$TEMP_PREFIX"
1110#[link(name = "foo", kind = "raw-dylib")]
1211extern "C" {
1312 // `@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 @@
1error: 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:
1error: 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:
22
33 $DLLTOOL: Syntax error in def file $DEF_FILE:1␍
44
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
22 --> $DIR/import-name-type-invalid-format.rs:9:1
33 |
44LL | #[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
88 |
99 = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
1010
tests/ui/simd/intrinsic/generic-reduction-pass.rs+5-4
......@@ -109,10 +109,11 @@ const fn ordered() {
109109 let r: f32 = simd_reduce_mul_ordered(x, 2.);
110110 assert_eq!(r, -48_f32);
111111
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);
116117 }
117118
118119 unsafe {
tests/ui/target-feature/invalid-attribute.rs+1-1
......@@ -31,7 +31,7 @@ extern "Rust" {}
3131//~| NOTE expected this to be of the form `enable = "..."`
3232#[target_feature(disable = "baz")]
3333//~^ ERROR malformed `target_feature` attribute
34//~| NOTE expected this to be of the form `enable = "..."`
34//~| NOTE the only valid argument here is `enable`
3535unsafe fn foo() {}
3636
3737#[target_feature(enable = "sse2")]
tests/ui/target-feature/invalid-attribute.stderr+1-1
......@@ -56,7 +56,7 @@ error[E0539]: malformed `target_feature` attribute input
5656LL | #[target_feature(disable = "baz")]
5757 | ^^^^^^^^^^^^^^^^^-------^^^^^^^^^^
5858 | |
59 | expected this to be of the form `enable = "..."`
59 | the only valid argument here is `enable`
6060 |
6161help: must be of the form
6262 |
tests/ui/test-attrs/test-should-panic-attr.rs+1-1
......@@ -19,7 +19,7 @@ fn test2() {
1919#[test]
2020#[should_panic(expect)]
2121//~^ 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 = "..."`
2323//~| NOTE for more information, visit
2424fn test3() {
2525 panic!();
tests/ui/test-attrs/test-should-panic-attr.stderr+3-3
......@@ -22,9 +22,9 @@ error[E0539]: malformed `should_panic` attribute input
2222 --> $DIR/test-should-panic-attr.rs:20:1
2323 |
2424LL | #[should_panic(expect)]
25 | ^^^^^^^^^^^^^^--------^
26 | |
27 | the only valid argument here is "expected"
25 | ^^^^^^^^^^^^^^^------^^
26 | |
27 | expected this to be of the form `expected = "..."`
2828 |
2929 = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute>
3030help: 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
1515 |
1616LL | x.a();
1717 | ^
18 |
19help: consider further restricting type parameter `T` with trait `Foo`
20 |
21LL | const fn foo<T: Bar + [const] Foo>(x: &T) {
22 | +++++++++++++
1823
1924error: aborting due to 2 previous errors
2025
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
33 |
44LL | x.a();
55 | ^
6 |
7help: consider further restricting type parameter `T` with trait `Foo`
8 |
9LL | const fn foo<T: Bar + [const] Foo>(x: &T) {
10 | +++++++++++++
611
712error: aborting due to 1 previous error
813
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
3838 |
3939LL | x.a();
4040 | ^
41 |
42help: consider further restricting type parameter `T` with trait `Foo`
43 |
44LL | const fn foo<T: [const] Bar + [const] Foo>(x: &T) {
45 | +++++++++++++
4146
4247error: aborting due to 4 previous errors
4348