From 0246245420bbbb378db020c0492561cf701165cd Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Fri, 8 Aug 2025 21:59:51 +0800 Subject: rustc_target: Add the `32s` target feature for LoongArch --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 + compiler/rustc_target/src/target_features.rs | 1 + 2 files changed, 2 insertions(+) (limited to 'compiler') diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 3b290e5a129..5c463555406 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -277,6 +277,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // Filter out features that are not supported by the current LLVM version ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, ( diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 297d9ed84c5..bff8e4d37e9 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -763,6 +763,7 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start + ("32s", Unstable(sym::loongarch_target_feature), &[]), ("d", Stable, &["f"]), ("div32", Unstable(sym::loongarch_target_feature), &[]), ("f", Stable, &[]), -- cgit 1.4.1-3-g733a5 From 0c8485f02332f18a41f93ecd1cc3e9611040238b Mon Sep 17 00:00:00 2001 From: Makai Date: Wed, 13 Aug 2025 20:22:18 +0800 Subject: suggest using `pub(crate)` for E0364 --- compiler/rustc_resolve/messages.ftl | 3 +++ compiler/rustc_resolve/src/build_reduced_graph.rs | 4 ++++ compiler/rustc_resolve/src/errors.rs | 11 +++++++++++ compiler/rustc_resolve/src/imports.rs | 8 +++++++- tests/ui/privacy/macro-private-reexport.stderr | 4 ++++ tests/ui/rust-2018/uniform-paths/macro-rules.stderr | 4 ++++ 6 files changed, 33 insertions(+), 1 deletion(-) (limited to 'compiler') diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index ceef558c0cf..293471df1c1 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -93,6 +93,9 @@ resolve_consider_adding_a_derive = resolve_consider_adding_macro_export = consider adding a `#[macro_export]` to the macro in the imported module +resolve_consider_marking_as_pub_crate = + in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)` + resolve_consider_declaring_with_pub = consider declaring type or module `{$ident}` with `pub` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d18d0fc16a8..185749ba8a0 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -474,6 +474,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span, root_id, vis, + vis_span: item.vis.span, }); self.r.indeterminate_imports.push(import); @@ -966,6 +967,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, module_path: Vec::new(), vis, + vis_span: item.vis.span, }); if used { self.r.import_use_map.insert(import, Used::Other); @@ -1105,6 +1107,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span, module_path: Vec::new(), vis: Visibility::Restricted(CRATE_DEF_ID), + vis_span: item.vis.span, }) }; @@ -1274,6 +1277,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span, module_path: Vec::new(), vis, + vis_span: item.vis.span, }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 2747ba135ed..6f81724f140 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -769,6 +769,17 @@ pub(crate) struct ConsiderAddingMacroExport { pub(crate) span: Span, } +#[derive(Subdiagnostic)] +#[suggestion( + resolve_consider_marking_as_pub_crate, + code = "pub(crate)", + applicability = "maybe-incorrect" +)] +pub(crate) struct ConsiderMarkingAsPubCrate { + #[primary_span] + pub(crate) vis_span: Span, +} + #[derive(Subdiagnostic)] #[note(resolve_consider_marking_as_pub)] pub(crate) struct ConsiderMarkingAsPub { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 403d440bee7..be4771dcb31 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -30,7 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, - ConsiderAddingMacroExport, ConsiderMarkingAsPub, + ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion, @@ -188,6 +188,9 @@ pub(crate) struct ImportData<'ra> { /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell>>, pub vis: Visibility, + + /// Span of the visibility. + pub vis_span: Span, } /// All imports are unique and allocated on a same arena, @@ -1373,6 +1376,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic( ConsiderAddingMacroExport { span: binding.span, }); + err.subdiagnostic( ConsiderMarkingAsPubCrate { + vis_span: import.vis_span, + }); } _ => { err.subdiagnostic( ConsiderMarkingAsPub { diff --git a/tests/ui/privacy/macro-private-reexport.stderr b/tests/ui/privacy/macro-private-reexport.stderr index b8768f3612e..aa02715c202 100644 --- a/tests/ui/privacy/macro-private-reexport.stderr +++ b/tests/ui/privacy/macro-private-reexport.stderr @@ -11,6 +11,10 @@ LL | / macro_rules! bar { LL | | () => {}; LL | | } | |_____^ +help: in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)` + | +LL | pub(crate) use bar as _; + | +++++++ error[E0364]: `baz` is private, and cannot be re-exported --> $DIR/macro-private-reexport.rs:14:13 diff --git a/tests/ui/rust-2018/uniform-paths/macro-rules.stderr b/tests/ui/rust-2018/uniform-paths/macro-rules.stderr index 661d667eb9a..43eacd5413f 100644 --- a/tests/ui/rust-2018/uniform-paths/macro-rules.stderr +++ b/tests/ui/rust-2018/uniform-paths/macro-rules.stderr @@ -9,6 +9,10 @@ help: consider adding a `#[macro_export]` to the macro in the imported module | LL | macro_rules! legacy_macro { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: in case you want to use the macro within this crate only, reduce the visibility to `pub(crate)` + | +LL | pub(crate) use legacy_macro as _; + | +++++++ error: aborting due to 1 previous error -- cgit 1.4.1-3-g733a5 From c3c2c23e0d96c76f11a307cf3c4cf14a86fd158b Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Thu, 3 Apr 2025 20:59:05 -0400 Subject: Extend `QueryStability` to handle `IntoIterator` implementations Fix adjacent code Fix duplicate warning; merge test into `tests/ui-fulldeps/internal-lints` Use `rustc_middle::ty::FnSig::inputs` Address two review comments - https://github.com/rust-lang/rust/pull/139345#discussion_r2109006991 - https://github.com/rust-lang/rust/pull/139345#discussion_r2109058588 Use `Instance::try_resolve` Import `rustc_middle::ty::Ty` as `Ty` rather than `MiddleTy` Simplify predicate handling Add more `#[allow(rustc::potential_query_instability)]` following rebase Remove two `#[allow(rustc::potential_query_instability)]` following rebase Address review comment Update compiler/rustc_lint/src/internal.rs Co-authored-by: lcnr --- compiler/rustc_codegen_ssa/src/target_features.rs | 1 + compiler/rustc_errors/src/emitter.rs | 4 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 1 + compiler/rustc_interface/src/interface.rs | 4 +- compiler/rustc_lint/src/internal.rs | 132 +++++++++++++-------- src/librustdoc/formats/cache.rs | 2 +- .../ui-fulldeps/internal-lints/query_stability.rs | 12 ++ .../internal-lints/query_stability.stderr | 18 ++- 8 files changed, 122 insertions(+), 52 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 7e4341a8236..b5aa50f4851 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -180,6 +180,7 @@ fn parse_rust_feature_flag<'a>( while let Some(new_feature) = new_features.pop() { if features.insert(new_feature) { if let Some(implied_features) = inverse_implied_features.get(&new_feature) { + #[allow(rustc::potential_query_instability)] new_features.extend(implied_features) } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 97c47fa9b9a..749bba5de12 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -17,7 +17,7 @@ use std::path::Path; use std::sync::Arc; use derive_setters::Setters; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_lexer; @@ -1853,7 +1853,7 @@ impl HumanEmitter { && line_idx + 1 == annotated_file.lines.len(), ); - let mut to_add = FxHashMap::default(); + let mut to_add = FxIndexMap::default(); for (depth, style) in depths { // FIXME(#120456) - is `swap_remove` correct? diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 334f57f9d62..6b57ced56eb 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -522,6 +522,7 @@ pub(super) fn try_match_macro_attr<'matcher, T: Tracker<'matcher>>( match result { Success(body_named_matches) => { psess.gated_spans.merge(gated_spans_snapshot); + #[allow(rustc::potential_query_instability)] named_matches.extend(body_named_matches); return Ok((i, rule, named_matches)); } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c46e879b976..8f131f45bbd 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -285,7 +285,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch .expecteds .entry(name.name) .and_modify(|v| match v { - ExpectedValues::Some(v) if !values_any_specified => { + ExpectedValues::Some(v) if !values_any_specified => + { + #[allow(rustc::potential_query_instability)] v.extend(values.clone()) } ExpectedValues::Some(_) => *v = ExpectedValues::Any, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 016ff17f5d7..e1fbe39222b 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -1,10 +1,10 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use rustc_hir::HirId; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy}; +use rustc_hir::{Expr, ExprKind, HirId}; +use rustc_middle::ty::{self, ClauseKind, GenericArgsRef, PredicatePolarity, TraitPredicate, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::{Span, sym}; @@ -56,25 +56,6 @@ impl LateLintPass<'_> for DefaultHashTypes { } } -/// Helper function for lints that check for expressions with calls and use typeck results to -/// get the `DefId` and `GenericArgsRef` of the function. -fn typeck_results_of_method_fn<'tcx>( - cx: &LateContext<'tcx>, - expr: &hir::Expr<'_>, -) -> Option<(Span, DefId, ty::GenericArgsRef<'tcx>)> { - match expr.kind { - hir::ExprKind::MethodCall(segment, ..) - if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => - { - Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id))) - } - _ => match cx.typeck_results().node_type(expr.hir_id).kind() { - &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)), - _ => None, - }, - } -} - declare_tool_lint! { /// The `potential_query_instability` lint detects use of methods which can lead to /// potential query instability, such as iterating over a `HashMap`. @@ -101,10 +82,12 @@ declare_tool_lint! { declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]); -impl LateLintPass<'_> for QueryStability { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; - if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, args) +impl<'tcx> LateLintPass<'tcx> for QueryStability { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let Some((callee_def_id, span, generic_args, _recv, _args)) = + get_callee_span_generic_args_and_args(cx, expr) + && let Ok(Some(instance)) = + ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { @@ -113,7 +96,15 @@ impl LateLintPass<'_> for QueryStability { span, QueryInstability { query: cx.tcx.item_name(def_id) }, ); + } else if has_unstable_into_iter_predicate(cx, callee_def_id, generic_args) { + let call_span = span.with_hi(expr.span.hi()); + cx.emit_span_lint( + POTENTIAL_QUERY_INSTABILITY, + call_span, + QueryInstability { query: sym::into_iter }, + ); } + if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) { cx.emit_span_lint( UNTRACKED_QUERY_INFORMATION, @@ -125,6 +116,64 @@ impl LateLintPass<'_> for QueryStability { } } +fn has_unstable_into_iter_predicate<'tcx>( + cx: &LateContext<'tcx>, + callee_def_id: DefId, + generic_args: GenericArgsRef<'tcx>, +) -> bool { + let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { + return false; + }; + let Some(into_iter_fn_def_id) = cx.tcx.lang_items().into_iter_fn() else { + return false; + }; + let predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args); + for (predicate, _) in predicates { + let ClauseKind::Trait(TraitPredicate { trait_ref, polarity: PredicatePolarity::Positive }) = + predicate.kind().skip_binder() + else { + continue; + }; + // Does the function or method require any of its arguments to implement `IntoIterator`? + if trait_ref.def_id != into_iterator_def_id { + continue; + } + let Ok(Some(instance)) = + ty::Instance::try_resolve(cx.tcx, cx.typing_env(), into_iter_fn_def_id, trait_ref.args) + else { + continue; + }; + // Does the input type's `IntoIterator` implementation have the + // `rustc_lint_query_instability` attribute on its `into_iter` method? + if cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_query_instability) { + return true; + } + } + false +} + +/// Checks whether an expression is a function or method call and, if so, returns its `DefId`, +/// `Span`, `GenericArgs`, and arguments. This is a slight augmentation of a similarly named Clippy +/// function, `get_callee_generic_args_and_args`. +fn get_callee_span_generic_args_and_args<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<(DefId, Span, GenericArgsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> { + if let ExprKind::Call(callee, args) = expr.kind + && let callee_ty = cx.typeck_results().expr_ty(callee) + && let ty::FnDef(callee_def_id, generic_args) = callee_ty.kind() + { + return Some((*callee_def_id, callee.span, generic_args, None, args)); + } + if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + { + let generic_args = cx.typeck_results().node_args(expr.hir_id); + return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args)); + } + None +} + declare_tool_lint! { /// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::`, /// where `ty::` would suffice. @@ -461,33 +510,22 @@ declare_tool_lint! { declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]); impl LateLintPass<'_> for Diagnostics { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| { let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra)); result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span))); result }; // Only check function calls and method calls. - let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind { - hir::ExprKind::Call(callee, args) => { - match cx.typeck_results().node_type(callee.hir_id).kind() { - &ty::FnDef(def_id, fn_gen_args) => { - (callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false)) - } - _ => return, // occurs for fns passed as args - } - } - hir::ExprKind::MethodCall(_segment, _recv, args, _span) => { - let Some((span, def_id, fn_gen_args)) = typeck_results_of_method_fn(cx, expr) - else { - return; - }; - let mut args = collect_args_tys_and_spans(args, true); - args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self` - (span, def_id, fn_gen_args, args) - } - _ => return, + let Some((def_id, span, fn_gen_args, recv, args)) = + get_callee_span_generic_args_and_args(cx, expr) + else { + return; }; + let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some()); + if let Some(recv) = recv { + arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); // dummy inserted for `self` + } Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args); Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans); @@ -496,7 +534,7 @@ impl LateLintPass<'_> for Diagnostics { impl Diagnostics { // Is the type `{D,Subd}iagMessage`? - fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool { + fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool { if let Some(adt_def) = ty.ty_adt_def() && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) && matches!(name, sym::DiagMessage | sym::SubdiagMessage) @@ -510,7 +548,7 @@ impl Diagnostics { fn untranslatable_diagnostic<'cx>( cx: &LateContext<'cx>, def_id: DefId, - arg_tys_and_spans: &[(MiddleTy<'cx>, Span)], + arg_tys_and_spans: &[(Ty<'cx>, Span)], ) { let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates; diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 918b292466d..359a35ec7fa 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -48,7 +48,7 @@ pub(crate) struct Cache { /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - pub(crate) external_paths: FxHashMap, ItemType)>, + pub(crate) external_paths: FxIndexMap, ItemType)>, /// Maps local `DefId`s of exported types to fully qualified paths. /// Unlike 'paths', this mapping ignores any renames that occur diff --git a/tests/ui-fulldeps/internal-lints/query_stability.rs b/tests/ui-fulldeps/internal-lints/query_stability.rs index 7b897fabd2d..9dc65250064 100644 --- a/tests/ui-fulldeps/internal-lints/query_stability.rs +++ b/tests/ui-fulldeps/internal-lints/query_stability.rs @@ -34,4 +34,16 @@ fn main() { //~^ ERROR using `values_mut` can result in unstable query results *val = *val + 10; } + + FxHashMap::::default().extend(x); + //~^ ERROR using `into_iter` can result in unstable query results +} + +fn hide_into_iter(x: impl IntoIterator) -> impl Iterator { + x.into_iter() +} + +fn take(map: std::collections::HashMap) { + _ = hide_into_iter(map); + //~^ ERROR using `into_iter` can result in unstable query results } diff --git a/tests/ui-fulldeps/internal-lints/query_stability.stderr b/tests/ui-fulldeps/internal-lints/query_stability.stderr index 43b156dc20a..a95ffd25a47 100644 --- a/tests/ui-fulldeps/internal-lints/query_stability.stderr +++ b/tests/ui-fulldeps/internal-lints/query_stability.stderr @@ -59,5 +59,21 @@ LL | for val in x.values_mut() { | = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale -error: aborting due to 7 previous errors +error: using `into_iter` can result in unstable query results + --> $DIR/query_stability.rs:38:38 + | +LL | FxHashMap::::default().extend(x); + | ^^^^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +error: using `into_iter` can result in unstable query results + --> $DIR/query_stability.rs:47:9 + | +LL | _ = hide_into_iter(map); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +error: aborting due to 9 previous errors -- cgit 1.4.1-3-g733a5 From e31fed054bc19845b04ee0be50c1254174e87ad0 Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 6 Aug 2025 17:21:25 -0500 Subject: run spellcheck as a tidy extra check in ci --- compiler/rustc_next_trait_solver/src/canonicalizer.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- library/std/src/sync/nonpoison/mutex.rs | 2 +- library/std/src/sync/poison/mutex.rs | 2 +- src/ci/docker/host-x86_64/tidy/Dockerfile | 2 +- src/librustdoc/html/static/js/main.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1bc35e599c7..3e1f48610ff 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -27,7 +27,7 @@ enum CanonicalizeInputKind { ParamEnv, /// When canonicalizing predicates, we don't keep `'static`. If we're /// currently outside of the trait solver and canonicalize the root goal - /// during HIR typeck, we replace each occurance of a region with a + /// during HIR typeck, we replace each occurrence of a region with a /// unique region variable. See the comment on `InferCtxt::in_hir_typeck` /// for more details. Predicate { is_hir_typeck_root_goal: bool }, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5200f9340e1..679e663f886 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4270,7 +4270,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if path.len() == 2 && let [segment] = prefix_path { - // Delay to check whether methond name is an associated function or not + // Delay to check whether method name is an associated function or not // ``` // let foo = Foo {}; // foo::bar(); // possibly suggest to foo.bar(); diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs index b6861c78f00..fd1e671d7a3 100644 --- a/library/std/src/sync/nonpoison/mutex.rs +++ b/library/std/src/sync/nonpoison/mutex.rs @@ -100,7 +100,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 6205c4fa4ca..720c212c65c 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -279,7 +279,7 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { poison: poison::Guard, } -/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// A [`MutexGuard`] is not `Send` to maximize platform portability. /// /// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to /// release mutex locks on the same thread they were acquired. diff --git a/src/ci/docker/host-x86_64/tidy/Dockerfile b/src/ci/docker/host-x86_64/tidy/Dockerfile index ee1ae5410ee..c8558689d3b 100644 --- a/src/ci/docker/host-x86_64/tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/tidy/Dockerfile @@ -45,4 +45,4 @@ RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ - src/tools/tidy tidyselftest --extra-checks=py,cpp,js + src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 8e3d07b3a1c..21d154edf5d 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1529,7 +1529,7 @@ function preLoadCss(cssUrl) { ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], - // for the sake of brevity, we don't say "inherint impl blocks", + // for the sake of brevity, we don't say "inherit impl blocks", // although that would be more correct, // since trait impl blocks are collapsed by - ["_", "Collapse all sections, including impl blocks"], -- cgit 1.4.1-3-g733a5 From 1cb4fd7dd12be93465a55d56622c52002e3b050b Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Aug 2025 13:18:53 -0500 Subject: tidy now installs typos-cli as-needed via cargo --- compiler/rustc_resolve/src/imports.rs | 6 ++-- library/std/src/sys/mod.rs | 2 +- src/tools/tidy/src/extra_checks/mod.rs | 37 +++++-------------- src/tools/tidy/src/lib.rs | 66 ++++++++++++++++++++++++++++++++++ src/tools/tidy/src/main.rs | 1 + 5 files changed, 80 insertions(+), 32 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7c93fdb88ee..2ecabb33763 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -866,7 +866,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } ImportKind::Glob { .. } => { // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. self.get_mut_unchecked().resolve_glob_import(import); return 0; } @@ -903,7 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. this.get_mut_unchecked().define_binding_local( parent, target, @@ -917,7 +917,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if target.name != kw::Underscore { let key = BindingKey::new(target, ns); // FIXME: Use mutable resolver directly as a hack, this should be an output of - // specualtive resolution. + // speculative resolution. this.get_mut_unchecked().update_local_resolution( parent, key, diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8ec0a0e3302..6324c1a232a 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -1,7 +1,7 @@ #![allow(unsafe_op_in_unsafe_fn)] /// The configure builtins provides runtime support compiler-builtin features -/// which require dynamic intialization to work as expected, e.g. aarch64 +/// which require dynamic initialization to work as expected, e.g. aarch64 /// outline-atomics. mod configure_builtins; diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index f90f716cd95..604b5d1e37c 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -41,7 +41,6 @@ const RUFF_CONFIG_PATH: &[&str] = &["src", "tools", "tidy", "config", "ruff.toml const RUFF_CACHE_PATH: &[&str] = &["cache", "ruff_cache"]; const PIP_REQ_PATH: &[&str] = &["src", "tools", "tidy", "config", "requirements.txt"]; -// this must be kept in sync with with .github/workflows/spellcheck.yml const SPELLCHECK_DIRS: &[&str] = &["compiler", "library", "src/bootstrap", "src/librustdoc"]; pub fn check( @@ -51,6 +50,7 @@ pub fn check( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -63,6 +63,7 @@ pub fn check( librustdoc_path, tools_path, npm, + cargo, bless, extra_checks, pos_args, @@ -78,6 +79,7 @@ fn check_impl( librustdoc_path: &Path, tools_path: &Path, npm: &Path, + cargo: &Path, bless: bool, extra_checks: Option<&str>, pos_args: &[String], @@ -293,7 +295,7 @@ fn check_impl( } else { eprintln!("spellcheck files"); } - spellcheck_runner(&args)?; + spellcheck_runner(&outdir, &cargo, &args)?; } if js_lint || js_typecheck { @@ -576,33 +578,12 @@ fn shellcheck_runner(args: &[&OsStr]) -> Result<(), Error> { if status.success() { Ok(()) } else { Err(Error::FailedCheck("shellcheck")) } } -/// Check that spellchecker is installed then run it at the given path -fn spellcheck_runner(args: &[&str]) -> Result<(), Error> { - // sync version with .github/workflows/spellcheck.yml - let expected_version = "typos-cli 1.34.0"; - match Command::new("typos").arg("--version").output() { - Ok(o) => { - let stdout = String::from_utf8_lossy(&o.stdout); - if stdout.trim() != expected_version { - return Err(Error::Version { - program: "typos", - required: expected_version, - installed: stdout.trim().to_string(), - }); - } - } - Err(e) if e.kind() == io::ErrorKind::NotFound => { - return Err(Error::MissingReq( - "typos", - "spellcheck file checks", - // sync version with .github/workflows/spellcheck.yml - Some("install tool via `cargo install typos-cli@1.34.0`".to_owned()), - )); - } - Err(e) => return Err(e.into()), - } +/// Ensure that spellchecker is installed then run it at the given path +fn spellcheck_runner(outdir: &Path, cargo: &Path, args: &[&str]) -> Result<(), Error> { + let bin_path = + crate::ensure_version_or_cargo_install(outdir, cargo, "typos-cli", "typos", "1.34.0")?; - let status = Command::new("typos").args(args).status()?; + let status = Command::new(bin_path).args(args).status()?; if status.success() { Ok(()) } else { Err(Error::FailedCheck("typos")) } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 4ea9d051ddb..37713cbf75e 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -4,7 +4,9 @@ //! to be used by tools. use std::ffi::OsStr; +use std::path::{Path, PathBuf}; use std::process::Command; +use std::{env, io}; use build_helper::ci::CiEnv; use build_helper::git::{GitConfig, get_closest_upstream_commit}; @@ -180,6 +182,70 @@ pub fn files_modified(ci_info: &CiInfo, pred: impl Fn(&str) -> bool) -> bool { !v.is_empty() } +/// If the given executable is installed with the given version, use that, +/// otherwise install via cargo. +pub fn ensure_version_or_cargo_install( + build_dir: &Path, + cargo: &Path, + pkg_name: &str, + bin_name: &str, + version: &str, +) -> io::Result { + // ignore the process exit code here and instead just let the version number check fail. + // we also importantly don't return if the program wasn't installed, + // instead we want to continue to the fallback. + 'ck: { + // FIXME: rewrite as if-let chain once this crate is 2024 edition. + let Ok(output) = Command::new(bin_name).arg("--version").output() else { + break 'ck; + }; + let Ok(s) = str::from_utf8(&output.stdout) else { + break 'ck; + }; + let Some(v) = s.trim().split_whitespace().last() else { + break 'ck; + }; + if v == version { + return Ok(PathBuf::from(bin_name)); + } + } + + let tool_root_dir = build_dir.join("misc-tools"); + let tool_bin_dir = tool_root_dir.join("bin"); + eprintln!("building external tool {bin_name} from package {pkg_name}@{version}"); + // use --force to ensure that if the required version is bumped, we update it. + // use --target-dir to ensure we have a build cache so repeated invocations aren't slow. + // modify PATH so that cargo doesn't print a warning telling the user to modify the path. + let cargo_exit_code = Command::new(cargo) + .args(["install", "--locked", "--force", "--quiet"]) + .arg("--root") + .arg(&tool_root_dir) + .arg("--target-dir") + .arg(tool_root_dir.join("target")) + .arg(format!("{pkg_name}@{version}")) + .env( + "PATH", + env::join_paths( + env::split_paths(&env::var("PATH").unwrap()) + .chain(std::iter::once(tool_bin_dir.clone())), + ) + .expect("build dir contains invalid char"), + ) + .env("RUSTFLAGS", "-Copt-level=0") + .spawn()? + .wait()?; + if !cargo_exit_code.success() { + return Err(io::Error::other("cargo install failed")); + } + let bin_path = tool_bin_dir.join(bin_name); + assert!( + matches!(bin_path.try_exists(), Ok(true)), + "cargo install did not produce the expected binary" + ); + eprintln!("finished building tool {bin_name}"); + Ok(bin_path) +} + pub mod alphabetical; pub mod bins; pub mod debug_artifacts; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index cd2567ddb64..bfe30258915 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -184,6 +184,7 @@ fn main() { &librustdoc_path, &tools_path, &npm, + &cargo, bless, extra_checks, pos_args -- cgit 1.4.1-3-g733a5 From 1cd7080c3a7f29297675a72a157575ae12717304 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 7 May 2025 07:57:01 +0000 Subject: Add -Zindirect-branch-cs-prefix (from draft PR) --- compiler/rustc_codegen_llvm/src/context.rs | 9 +++++++++ compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ tests/codegen-llvm/indirect-branch-cs-prefix.rs | 18 ++++++++++++++++++ 4 files changed, 30 insertions(+) create mode 100644 tests/codegen-llvm/indirect-branch-cs-prefix.rs (limited to 'compiler') diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b0f3494ea68..ea3a21dfdb5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -462,6 +462,15 @@ pub(crate) unsafe fn create_module<'ll>( } } + if sess.opts.unstable_opts.indirect_branch_cs_prefix { + llvm::add_module_flag_u32( + llmod, + llvm::ModuleFlagMergeBehavior::Override, + "indirect_branch_cs_prefix", + 1, + ); + } + match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support()) { // Set up the small-data optimization limit for architectures that use diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 0a764808f95..4425877308a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() { tracked!(hint_mostly_unused, true); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); + tracked!(indirect_branch_cs_prefix, true); tracked!(inline_mir, Some(true)); tracked!(inline_mir_hint_threshold, Some(123)); tracked!(inline_mir_threshold, Some(123)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0e112edc733..fce4d18a1d8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2295,6 +2295,8 @@ options! { - hashes of green query instances - hash collisions of query keys - hash collisions when creating dep-nodes"), + indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "add cs prefix to call and jmp to indirect thunk (default: no)"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], diff --git a/tests/codegen-llvm/indirect-branch-cs-prefix.rs b/tests/codegen-llvm/indirect-branch-cs-prefix.rs new file mode 100644 index 00000000000..a00b63a4970 --- /dev/null +++ b/tests/codegen-llvm/indirect-branch-cs-prefix.rs @@ -0,0 +1,18 @@ +// Test that the `indirect_branch_cs_prefix` module attribute is (not) emitted when the +// `-Zindirect-branch-cs-prefix` flag is (not) set. + +//@ add-core-stubs +//@ revisions: unset set +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [set] compile-flags: -Zindirect-branch-cs-prefix + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +// unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} +// set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} -- cgit 1.4.1-3-g733a5 From 1a29d9c23ff8df46197f5ebd3df15fe99904d312 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Wed, 7 May 2025 15:38:14 +0200 Subject: Add `-Zindirect-branch-cs-prefix` option This is intended to be used for Linux kernel RETPOLINE builds. Signed-off-by: Miguel Ojeda --- compiler/rustc_session/messages.ftl | 2 ++ compiler/rustc_session/src/errors.rs | 4 ++++ compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 6 +++++ .../compiler-flags/indirect-branch-cs-prefix.md | 19 +++++++++++++++ .../x86_64-indirect-branch-cs-prefix.rs | 27 ++++++++++++++++++++++ tests/codegen-llvm/indirect-branch-cs-prefix.rs | 8 +++---- .../requires-x86-or-x86_64.aarch64.stderr | 4 ++++ .../requires-x86-or-x86_64.rs | 21 +++++++++++++++++ 9 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md create mode 100644 tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs create mode 100644 tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr create mode 100644 tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs (limited to 'compiler') diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 528c52eace7..80754964c43 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -49,6 +49,8 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target .note = compatible flavors are: {$compatible_list} +session_indirect_branch_cs_prefix_requires_x86_or_x86_64 = `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64 + session_instrumentation_not_supported = {$us} instrumentation is not supported for this target session_int_literal_too_large = integer literal is too large diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index bf95014843d..9471807df01 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -471,6 +471,10 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664; #[diag(session_function_return_thunk_extern_requires_non_large_code_model)] pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; +#[derive(Diagnostic)] +#[diag(session_indirect_branch_cs_prefix_requires_x86_or_x86_64)] +pub(crate) struct IndirectBranchCsPrefixRequiresX86OrX8664; + #[derive(Diagnostic)] #[diag(session_unsupported_regparm)] pub(crate) struct UnsupportedRegparm { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index fce4d18a1d8..6d5be2d92cd 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2296,7 +2296,7 @@ options! { - hash collisions of query keys - hash collisions when creating dep-nodes"), indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "add cs prefix to call and jmp to indirect thunk (default: no)"), + "add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"), inline_llvm: bool = (true, parse_bool, [TRACKED], "enable LLVM inlining (default: yes)"), inline_mir: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index c6956cf5f23..c8f4b511a7e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1368,6 +1368,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + if sess.opts.unstable_opts.indirect_branch_cs_prefix { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.dcx().emit_err(errors::IndirectBranchCsPrefixRequiresX86OrX8664); + } + } + if let Some(regparm) = sess.opts.unstable_opts.regparm { if regparm > 3 { sess.dcx().emit_err(errors::UnsupportedRegparm { regparm }); diff --git a/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md new file mode 100644 index 00000000000..040e2d41701 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/indirect-branch-cs-prefix.md @@ -0,0 +1,19 @@ +# `indirect-branch-cs-prefix` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116852. + +------------------------ + +Option `-Zindirect-branch-cs-prefix` controls whether a `cs` prefix is added to +`call` and `jmp` to indirect thunks. + +It is equivalent to [Clang]'s and [GCC]'s `-mindirect-branch-cs-prefix`. The +Linux kernel uses it for RETPOLINE builds. For details, see +[LLVM commit 6f867f910283] ("[X86] Support ``-mindirect-branch-cs-prefix`` for +call and jmp to indirect thunk") which introduces the feature. + +Only x86 and x86_64 are supported. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mindirect-branch-cs-prefix +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mindirect-branch-cs-prefix +[LLVM commit 6f867f910283]: https://github.com/llvm/llvm-project/commit/6f867f9102838ebe314c1f3661fdf95700386e5a diff --git a/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs b/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs new file mode 100644 index 00000000000..8e4470ee451 --- /dev/null +++ b/tests/assembly-llvm/x86_64-indirect-branch-cs-prefix.rs @@ -0,0 +1,27 @@ +// Test that the `cs` prefix is (not) added into a `call` and a `jmp` to the +// indirect thunk when the `-Zindirect-branch-cs-prefix` flag is (not) set. + +//@ revisions: unset set +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 -Cunsafe-allow-abi-mismatch=retpoline,retpoline-external-thunk,indirect-branch-cs-prefix -Zretpoline-external-thunk +//@ [set] compile-flags: -Zindirect-branch-cs-prefix +//@ only-x86_64 +//@ ignore-apple Symbol is called `___x86_indirect_thunk` (Darwin's extra underscore) + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +#[no_mangle] +pub fn foo(g: fn()) { + // unset-NOT: cs + // unset: callq {{__x86_indirect_thunk.*}} + // set: cs + // set-NEXT: callq {{__x86_indirect_thunk.*}} + g(); + + // unset-NOT: cs + // unset: jmp {{__x86_indirect_thunk.*}} + // set: cs + // set-NEXT: jmp {{__x86_indirect_thunk.*}} + g(); +} diff --git a/tests/codegen-llvm/indirect-branch-cs-prefix.rs b/tests/codegen-llvm/indirect-branch-cs-prefix.rs index a00b63a4970..df25008d5f0 100644 --- a/tests/codegen-llvm/indirect-branch-cs-prefix.rs +++ b/tests/codegen-llvm/indirect-branch-cs-prefix.rs @@ -1,5 +1,5 @@ -// Test that the `indirect_branch_cs_prefix` module attribute is (not) emitted when the -// `-Zindirect-branch-cs-prefix` flag is (not) set. +// Test that the `indirect_branch_cs_prefix` module attribute is (not) +// emitted when the `-Zindirect-branch-cs-prefix` flag is (not) set. //@ add-core-stubs //@ revisions: unset set @@ -11,8 +11,8 @@ #![feature(no_core, lang_items)] #![no_core] -#[lang = "sized"] -trait Sized {} +extern crate minicore; +use minicore::*; // unset-NOT: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} // set: !{{[0-9]+}} = !{i32 4, !"indirect_branch_cs_prefix", i32 1} diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr new file mode 100644 index 00000000000..e3f7871da35 --- /dev/null +++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs new file mode 100644 index 00000000000..bc81c993d26 --- /dev/null +++ b/tests/ui/invalid-compile-flags/indirect-branch-cs-prefix/requires-x86-or-x86_64.rs @@ -0,0 +1,21 @@ +//@ revisions: x86 x86_64 aarch64 + +//@ compile-flags: -Zindirect-branch-cs-prefix + +//@[x86] check-pass +//@[x86] needs-llvm-components: x86 +//@[x86] compile-flags: --target i686-unknown-linux-gnu + +//@[x86_64] check-pass +//@[x86_64] needs-llvm-components: x86 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu + +//@[aarch64] check-fail +//@[aarch64] needs-llvm-components: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu + +#![feature(no_core)] +#![no_core] +#![no_main] + +//[aarch64]~? ERROR `-Zindirect-branch-cs-prefix` is only supported on x86 and x86_64 -- cgit 1.4.1-3-g733a5 From f5e43d5ee31f0740a96479b4ffa2dcff009c226f Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 5 Jun 2025 15:22:25 +0200 Subject: nll-relate: improve hr opaque types support --- .../rustc_borrowck/src/type_check/relate_tys.rs | 9 +++++++-- compiler/rustc_infer/src/infer/mod.rs | 22 +++++++++++++++------- .../type-alias-impl-trait/higher_kinded_params3.rs | 3 +-- .../higher_kinded_params3.stderr | 11 ++++------- tests/ui/type-alias-impl-trait/hkl_forbidden3.rs | 2 +- .../ui/type-alias-impl-trait/hkl_forbidden3.stderr | 11 ++++------- 6 files changed, 32 insertions(+), 26 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 84ca9bad2c1..7ac2dff12f7 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -124,8 +124,13 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to // the opaque. let mut enable_subtyping = |ty, opaque_is_expected| { - let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT); - + // We create the fresh inference variable in the highest universe. + // In theory we could limit it to the highest universe in the args of + // the opaque but that isn't really worth the effort. + // + // We'll make sure that the opaque type can actually name everything + // in its hidden type later on. + let ty_vid = infcx.next_ty_vid(self.span()); let variance = if opaque_is_expected { self.ambient_variance } else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 82d4856df39..9ff06bda89b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -782,22 +782,30 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> { - self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None }) + pub fn next_ty_vid(&self, span: Span) -> TyVid { + self.next_ty_vid_with_origin(TypeVariableOrigin { span, param_def_id: None }) } - pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); - Ty::new_var(self.tcx, vid) + pub fn next_ty_vid_with_origin(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } - pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid { + pub fn next_ty_vid_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid { let origin = TypeVariableOrigin { span, param_def_id: None }; self.inner.borrow_mut().type_variables().new_var(universe, origin) } + pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> { + self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None }) + } + + pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + let vid = self.next_ty_vid_with_origin(origin); + Ty::new_var(self.tcx, vid) + } + pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> { - let vid = self.next_ty_var_id_in_universe(span, universe); + let vid = self.next_ty_vid_in_universe(span, universe); Ty::new_var(self.tcx, vid) } diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs index 4fb2e60b5c5..04208faddde 100644 --- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.rs @@ -24,8 +24,7 @@ type Successors<'a> = impl std::fmt::Debug + 'a; impl Terminator { #[define_opaque(Successors, Tait)] fn successors(&self, mut f: for<'x> fn(&'x ()) -> <&'x A as B>::C) -> Successors<'_> { - f = g; - //~^ ERROR mismatched types + f = g; //~ ERROR expected generic lifetime parameter, found `'x` } } diff --git a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr index 558792987f3..8e6778bdd0b 100644 --- a/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr +++ b/tests/ui/type-alias-impl-trait/higher_kinded_params3.stderr @@ -1,15 +1,12 @@ -error[E0308]: mismatched types +error[E0792]: expected generic lifetime parameter, found `'x` --> $DIR/higher_kinded_params3.rs:27:9 | LL | type Tait<'a> = impl std::fmt::Debug + 'a; - | ------------------------- the expected opaque type + | -- this generic parameter must be used with a generic lifetime parameter ... LL | f = g; - | ^^^^^ one type is more general than the other - | - = note: expected fn pointer `for<'x> fn(&'x ()) -> Tait<'x>` - found fn pointer `for<'a> fn(&'a ()) -> &'a ()` + | ^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs index c7f04dc07bb..ba75b114a11 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.rs @@ -8,7 +8,7 @@ fn foo<'a>(x: &'a ()) -> &'a () { #[define_opaque(Opaque)] fn test() -> for<'a> fn(&'a ()) -> Opaque<'a> { - foo //~ ERROR: mismatched types + foo //~ ERROR: expected generic lifetime parameter, found `'a` } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr index b8c04185a7d..d699059e397 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden3.stderr @@ -1,15 +1,12 @@ -error[E0308]: mismatched types +error[E0792]: expected generic lifetime parameter, found `'a` --> $DIR/hkl_forbidden3.rs:11:5 | LL | type Opaque<'a> = impl Sized + 'a; - | --------------- the expected opaque type + | -- this generic parameter must be used with a generic lifetime parameter ... LL | foo - | ^^^ one type is more general than the other - | - = note: expected fn pointer `for<'a> fn(&'a ()) -> Opaque<'a>` - found fn pointer `for<'a> fn(&'a ()) -> &'a ()` + | ^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0792`. -- cgit 1.4.1-3-g733a5 From ece1397e3ff40e7f8a411981844a8214659da970 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Aug 2025 17:22:02 +0200 Subject: interpret: fix in-place return place semantics when the return place expression is a local variable --- compiler/rustc_const_eval/src/interpret/call.rs | 12 +++++++++--- compiler/rustc_const_eval/src/interpret/place.rs | 6 ++++++ compiler/rustc_const_eval/src/interpret/step.rs | 1 + .../return_pointer_aliasing_read.none.stderr | 4 ++-- .../fail/function_calls/return_pointer_aliasing_read.rs | 8 ++++---- .../return_pointer_aliasing_read.stack.stderr | 14 +++++++------- .../return_pointer_aliasing_read.tree.stderr | 8 ++++---- .../fail/function_calls/return_pointer_aliasing_write.rs | 4 ++-- .../return_pointer_aliasing_write.stack.stderr | 10 +++++----- .../return_pointer_aliasing_write.tree.stderr | 4 ++-- .../return_pointer_aliasing_write_tail_call.rs | 4 ++-- .../return_pointer_aliasing_write_tail_call.stack.stderr | 14 +++++++------- .../return_pointer_aliasing_write_tail_call.tree.stderr | 4 ++-- 13 files changed, 53 insertions(+), 40 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index b1cc0cc2878..7b3c80538ca 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -27,8 +27,9 @@ use crate::{enter_trace_span, fluent_generated as fluent}; pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> { /// Pass a copy of the given operand. Copy(OpTy<'tcx, Prov>), - /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and - /// make the place inaccessible for the duration of the function call. + /// Allow for the argument to be passed in-place: destroy the value originally stored at that + /// place and make the place inaccessible for the duration of the function call. This *must* be + /// an in-memory place so that we can do the proper alias checks. InPlace(MPlaceTy<'tcx, Prov>), } @@ -379,6 +380,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + // *Before* pushing the new frame, determine whether the return destination is in memory. + // Need to use `place_to_op` to be *sure* we get the mplace if there is one. + let destination_mplace = self.place_to_op(destination)?.as_mplace_or_imm().left(); + + // Push the "raw" frame -- this leaves locals uninitialized. self.push_stack_frame_raw(instance, body, destination, cont)?; // If an error is raised here, pop the frame again to get an accurate backtrace. @@ -496,7 +502,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Protect return place for in-place return value passing. // We only need to protect anything if this is actually an in-memory place. - if let Left(mplace) = destination.as_mplace_or_local() { + if let Some(mplace) = destination_mplace { M::protect_in_place_function_argument(self, &mplace)?; } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 6ff50dc700f..921fa8677fe 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -234,6 +234,12 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { } /// A place is either an mplace or some local. + /// + /// Note that the return value can be different even for logically identical places! + /// Specifically, if a local is stored in-memory, this may return `Local` or `MPlaceTy` + /// depending on how the place was constructed. In other words, seeing `Local` here does *not* + /// imply that this place does not point to memory. Every caller must therefore always handle + /// both cases. #[inline(always)] pub fn as_mplace_or_local( &self, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 76e470b69dc..36251f774c6 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -415,6 +415,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // caller directly access this local! // This is also crucial for tail calls, where we want the `FnArg` to // stay valid when the old stack frame gets popped. + // FIXME: How can this be right for aliasing arguments? FnArg::Copy(op) } } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index 24091547258..d478568ceae 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: ALLOC (stack variable, size: 4, align: 4) { diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs index a6e0134bd17..dc22e129e18 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.rs @@ -10,11 +10,11 @@ use std::intrinsics::mir::*; pub fn main() { mir! { { - let x = 0; - let ptr = &raw mut x; + let _x = 0; + let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Even just reading from that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -25,7 +25,7 @@ pub fn main() { fn myfun(ptr: *mut i32) -> i32 { unsafe { ptr.read() }; - //~[stack]^ ERROR: not granting access + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /read access .* forbidden/ //~[none]| ERROR: uninitialized // Without an aliasing model, reads are "fine" but at least they return uninit data. diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr index 77cc0332a1c..86adbab353b 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; - | ^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,12 +11,12 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | / mir! { LL | | { -LL | | let x = 0; -LL | | let ptr = &raw mut x; +LL | | let _x = 0; +LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: is this argument +help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -26,8 +26,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index bae3819c979..a1cf0b730eb 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -13,8 +13,8 @@ help: the accessed tag was created here | LL | / mir! { LL | | { -LL | | let x = 0; -LL | | let ptr = &raw mut x; +LL | | let _x = 0; +LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ @@ -34,8 +34,8 @@ LL | unsafe { ptr.read() }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs index 6155e925c4b..2fddaf37235 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.rs @@ -14,7 +14,7 @@ pub fn main() { let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Writing to that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -26,7 +26,7 @@ pub fn main() { fn myfun(ptr: *mut i32) -> i32 { // This overwrites the return place, which shouldn't be possible through another pointer. unsafe { ptr.write(0) }; - //~[stack]^ ERROR: strongly protected + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /write access .* forbidden/ 13 } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr index 828b2339f8c..faae6172d75 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -16,7 +16,7 @@ LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: is this argument +help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; @@ -26,8 +26,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index e0df9370fee..01d15f38af6 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -34,8 +34,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs index 37ee7ae1b0d..5f3ecb65022 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs @@ -16,7 +16,7 @@ pub fn main() { let ptr = &raw mut _x; // We arrange for `myfun` to have a pointer that aliases // its return place. Writing to that pointer is UB. - Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { @@ -32,7 +32,7 @@ fn myfun(ptr: *mut i32) -> i32 { fn myfun2(ptr: *mut i32) -> i32 { // This overwrites the return place, which shouldn't be possible through another pointer. unsafe { ptr.write(0) }; - //~[stack]^ ERROR: strongly protected + //~[stack]^ ERROR: does not exist in the borrow stack //~[tree]| ERROR: /write access .* forbidden/ 13 } diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr index f5183cfaf5b..1a18857bb17 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^^^ this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -16,18 +16,18 @@ LL | | let ptr = &raw mut _x; ... | LL | | } | |_____^ -help: is this argument +help: was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | unsafe { ptr.write(0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | become myfun2(ptr) + | ^^^^^^^^^^^^^^^^^^ = note: BACKTRACE (of the first span): = note: inside `myfun2` at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index fa03ed6869b..812ddb94a73 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -34,8 +34,8 @@ LL | unsafe { ptr.write(0) }; note: inside `main` --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | -LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -- cgit 1.4.1-3-g733a5 From dc72692591c937e15cb016c57d4dee6a81340bbd Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 12 Aug 2025 12:16:43 +0200 Subject: Add tracing to various miscellaneous functions Also use tracing macro syntax instead of format() --- compiler/rustc_const_eval/src/interpret/eval_context.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/stack.rs | 5 ++++- compiler/rustc_const_eval/src/interpret/step.rs | 5 ++++- compiler/rustc_const_eval/src/interpret/validity.rs | 4 +++- src/tools/miri/src/machine.rs | 2 ++ 5 files changed, 15 insertions(+), 5 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c4b705d7124..bd312b2b8d1 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -325,8 +325,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let _span = enter_trace_span!( M, "instantiate_from_frame_and_normalize_erasing_regions", - "{}", - frame.instance + %frame.instance ); frame .instance @@ -582,6 +581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { span: Span, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let _trace = enter_trace_span!(M, const_eval::eval_mir_constant, ?val); let const_val = val.eval(*self.tcx, self.typing_env, span).map_err(|err| { if M::ALL_CONSTS_ARE_PRECHECKED { match err { diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 73cc87508ef..7cabfd96121 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -20,7 +20,7 @@ use super::{ MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar, from_known_layout, interp_ok, throw_ub, throw_unsup, }; -use crate::errors; +use crate::{enter_trace_span, errors}; // The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread // boundary and dropped in the other thread, it would exit the span in the other thread. @@ -386,6 +386,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). for &const_ in body.required_consts() { + // We can't use `eval_mir_constant` here as that assumes that all required consts have + // already been checked, so we need a separate tracing call. + let _trace = enter_trace_span!(M, const_eval::required_consts, ?const_.const_); let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| { diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9df49c0f4cc..c0c00e6196c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -436,7 +436,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .map(|arg| self.eval_fn_call_argument(&arg.node)) .collect::>>()?; - let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); + let fn_sig_binder = { + let _trace = enter_trace_span!(M, "fn_sig", ty = ?func.layout.ty.kind()); + func.layout.ty.fn_sig(*self.tcx) + }; let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ed48f53c310..db4e8e83ff2 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1418,7 +1418,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let _span = enter_trace_span!( M, "validate_operand", - "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}" + recursive, + reset_provenance_and_padding, + ?val, ); // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 00c3373bb0f..75bc9705bd2 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1111,6 +1111,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { // For foreign items, try to see if we can emulate them. if ecx.tcx.is_foreign_item(instance.def_id()) { + let _trace = enter_trace_span!("emulate_foreign_item"); // An external function call that does not have a MIR body. We either find MIR elsewhere // or emulate its effect. // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need @@ -1123,6 +1124,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } // Otherwise, load the MIR. + let _trace = enter_trace_span!("load_mir"); interp_ok(Some((ecx.load_mir(instance.def, None)?, instance))) } -- cgit 1.4.1-3-g733a5 From 7dfbc0ac1435b76bce4b6baf1ce1b3f7080538e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Aug 2025 19:44:45 +0200 Subject: miri: detect passing the same local twice as an in-place argument --- compiler/rustc_const_eval/src/interpret/step.rs | 61 +++++++++++++++------- .../function_calls/arg_inplace_locals_alias.rs | 34 ++++++++++++ .../arg_inplace_locals_alias.stack.stderr | 25 +++++++++ .../arg_inplace_locals_alias.tree.stderr | 33 ++++++++++++ 4 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs create mode 100644 src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr create mode 100644 src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr (limited to 'compiler') diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 36251f774c6..19fecd623b6 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -4,6 +4,7 @@ use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexSlice; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; @@ -389,8 +390,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Evaluate the arguments of a function call fn eval_fn_call_argument( - &self, + &mut self, op: &mir::Operand<'tcx>, + move_definitely_disjoint: bool, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { interp_ok(match op { mir::Operand::Copy(_) | mir::Operand::Constant(_) => { @@ -399,25 +401,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FnArg::Copy(op) } mir::Operand::Move(place) => { - // If this place lives in memory, preserve its location. - // We call `place_to_op` which will be an `MPlaceTy` whenever there exists - // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local` - // which can return a local even if that has an mplace.) let place = self.eval_place(*place)?; - let op = self.place_to_op(&place)?; - - match op.as_mplace_or_imm() { - Either::Left(mplace) => FnArg::InPlace(mplace), - Either::Right(_imm) => { - // This argument doesn't live in memory, so there's no place - // to make inaccessible during the call. - // We rely on there not being any stray `PlaceTy` that would let the - // caller directly access this local! - // This is also crucial for tail calls, where we want the `FnArg` to - // stay valid when the old stack frame gets popped. - // FIXME: How can this be right for aliasing arguments? - FnArg::Copy(op) + if move_definitely_disjoint { + // We still have to ensure that no *other* pointers are used to access this place, + // so *if* it is in memory then we have to treat it as `InPlace`. + // Use `place_to_op` to guarantee that we notice it being in memory. + let op = self.place_to_op(&place)?; + match op.as_mplace_or_imm() { + Either::Left(mplace) => FnArg::InPlace(mplace), + Either::Right(_imm) => FnArg::Copy(op), } + } else { + // We have to force this into memory to detect aliasing among `Move` arguments. + FnArg::InPlace(self.force_allocation(&place)?) } } }) @@ -426,15 +422,40 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the /// necessary information about callee and arguments to make a call. fn eval_callee_and_args( - &self, + &mut self, terminator: &mir::Terminator<'tcx>, func: &mir::Operand<'tcx>, args: &[Spanned>], ) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> { let func = self.eval_operand(func, None)?; + + // Evaluating function call arguments. The tricky part here is dealing with `Move` + // arguments: we have to ensure no two such arguments alias. This would be most easily done + // by just forcing them all into memory and then doing the usual in-place argument + // protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic + // pre-processing here where if all `move` arguments are syntactically distinct local + // variables (and none is indirect), we can skip the in-memory forcing. + let move_definitely_disjoint = 'move_definitely_disjoint: { + let mut previous_locals = FxHashSet::::default(); + for arg in args { + let mir::Operand::Move(place) = arg.node else { + continue; // we can skip non-`Move` arguments. + }; + if place.is_indirect_first_projection() { + // An indirect `Move` argument could alias with anything else... + break 'move_definitely_disjoint false; + } + if !previous_locals.insert(place.local) { + // This local is the base for two arguments! They might overlap. + break 'move_definitely_disjoint false; + } + } + // We found no violation so they are all definitely disjoint. + true + }; let args = args .iter() - .map(|arg| self.eval_fn_call_argument(&arg.node)) + .map(|arg| self.eval_fn_call_argument(&arg.node, move_definitely_disjoint)) .collect::>>()?; let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs new file mode 100644 index 00000000000..b91a41d7650 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.rs @@ -0,0 +1,34 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows +// Validation forces more things into memory, which we can't have here. +//@compile-flags: -Zmiri-disable-validation +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +pub struct S(i32); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let _unit: (); + { + let staging = S(42); // This forces `staging` into memory... + let non_copy = staging; // ... so we move it to a non-inmemory local here. + // This specifically uses a type with scalar representation to tempt Miri to use the + // efficient way of storing local variables (outside adressable memory). + Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + //~[stack]^ ERROR: not granting access + //~[tree]| ERROR: /read access .* forbidden/ + } + after_call = { + Return() + } + } +} + +pub fn callee(x: S, mut y: S) { + // With the setup above, if `x` and `y` are both moved, + // then writing to `y` will change the value stored in `x`! + y.0 = 0; + assert_eq!(x.0, 42); +} diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr new file mode 100644 index 00000000000..0c1100cae63 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.stack.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is strongly protected + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created here, as the root tag for ALLOC + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: is this argument + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr new file mode 100644 index 00000000000..f376c30c879 --- /dev/null +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -0,0 +1,33 @@ +error: Undefined Behavior: read access through (root of the allocation) at ALLOC[0x0] is forbidden + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: the accessed tag (root of the allocation) is foreign to the protected tag (i.e., it is not a child) + = help: this foreign read access would cause the protected tag (currently Active) to become Disabled + = help: protected tags must never be Disabled +help: the accessed tag was created here + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: the protected tag was created here, in the initial state Reserved + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ +help: the protected tag later transitioned to Active due to a child write access at offsets [0x0..0x4] + --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + | +LL | y.0 = 0; + | ^^^^^^^ + = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5