From df933640571861bcc2854431823cd9d4803b9f88 Mon Sep 17 00:00:00 2001 From: Steven Trotter Date: Sun, 25 Feb 2024 16:36:26 +0000 Subject: [PATCH 01/18] Added ability to report on generic argument mismatch better Needs some checking over and some tests have altered that need sanity checking, but overall this is starting to get somewhere now. --- compiler/rustc_errors/src/lib.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 388 +++++++++++++++++- compiler/rustc_lint_defs/src/lib.rs | 33 ++ .../extra_arguments.stderr | 14 +- .../invalid_arguments.stderr | 20 +- tests/ui/argument-suggestions/too-long.stderr | 24 +- tests/ui/async-await/coroutine-desc.stderr | 31 +- .../coerce-reborrow-multi-arg-fail.stderr | 11 +- tests/ui/coercion/coerce-to-bang.stderr | 10 +- tests/ui/fn/fn-item-type.stderr | 55 ++- ...generic-mismatch-reporting-issue-116615.rs | 12 + ...ric-mismatch-reporting-issue-116615.stderr | 75 ++++ tests/ui/never_type/issue-96335.stderr | 1 + tests/ui/parser/issues/issue-93282.stderr | 2 +- tests/ui/span/issue-34264.stderr | 2 +- .../tuple/add-tuple-within-arguments.stderr | 4 +- ...call-return-type-due-to-generic-arg.stderr | 2 +- 17 files changed, 611 insertions(+), 75 deletions(-) create mode 100644 tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs create mode 100644 tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 723f13dbe8d31..b88b5bcd7ea58 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, }; -pub use rustc_lint_defs::{pluralize, Applicability}; +pub use rustc_lint_defs::{a_or_an, display_list_with_comma_and, pluralize, Applicability}; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; pub use rustc_span::ErrorGuaranteed; pub use snippet::Style; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 1fa1da93018af..b65ac134fbc1f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -17,7 +17,8 @@ use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - codes::*, pluralize, Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, + a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag, + DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -423,11 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "expected formal_input_tys to be the same size as expected_input_tys" ); let formal_and_expected_inputs = IndexVec::from_iter( - formal_input_tys - .iter() - .copied() - .zip_eq(expected_input_tys.iter().copied()) - .map(|vars| self.resolve_vars_if_possible(vars)), + formal_input_tys.iter().copied().zip_eq(expected_input_tys.iter().copied()), ); self.set_tainted_by_errors(self.report_arg_errors( @@ -642,6 +639,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; + let formal_input_ty = self.resolve_vars_if_possible(formal_input_ty); + let expected_input_ty = self.resolve_vars_if_possible(expected_input_ty); // If either is an error type, we defy the usual convention and consider them to *not* be // coercible. This prevents our error message heuristic from trying to pass errors into // every argument. @@ -714,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Do we have as many extra provided arguments as the tuple's length? // If so, we might have just forgotten to wrap some args in a tuple. if let Some(ty::Tuple(tys)) = - formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) + formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| self.resolve_vars_if_possible(tys.1).kind()) // If the tuple is unit, we're not actually wrapping any arguments. && !tys.is_empty() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() @@ -733,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), ), ) { - if !self.can_coerce(provided_ty, *expected_ty) { + if !self.can_coerce(provided_ty, self.resolve_vars_if_possible(*expected_ty)) { satisfied = false; break; } @@ -752,10 +751,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tys.len() == 1 { // A tuple wrap suggestion actually occurs within, // so don't do anything special here. + let (formal_ty, expected_ty) = + formal_and_expected_inputs[mismatch_idx.into()]; + let formal_ty = self.resolve_vars_if_possible(formal_ty); + let expected_ty = self.resolve_vars_if_possible(expected_ty); err = self.err_ctxt().report_and_explain_type_error( mk_trace( *lo, - formal_and_expected_inputs[mismatch_idx.into()], + (formal_ty, expected_ty), provided_arg_tys[mismatch_idx.into()].0, ), terr, @@ -795,6 +798,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, None, Some(mismatch_idx), + &matched_inputs, + &formal_and_expected_inputs, is_method, ); suggest_confusable(&mut err); @@ -837,8 +842,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; }; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; - let trace = - mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); + let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; + let formal_ty = self.resolve_vars_if_possible(formal_ty); + let expected_ty = self.resolve_vars_if_possible(expected_ty); + let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e); suggest_confusable(&mut err); @@ -866,6 +873,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ] = &errors[..] { let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; + let formal_ty = self.resolve_vars_if_possible(formal_ty); + let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); @@ -881,6 +890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); + self.label_generic_mismatches( + &mut err, + fn_def_id, + &matched_inputs, + &provided_arg_tys, + &formal_and_expected_inputs, + ); + if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind && provided_idx.as_usize() == expected_idx.as_usize() { @@ -909,6 +926,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr, Some(expected_ty), Some(expected_idx.as_usize()), + &matched_inputs, + &formal_and_expected_inputs, is_method, ); suggest_confusable(&mut err); @@ -984,6 +1003,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match error { Error::Invalid(provided_idx, expected_idx, compatibility) => { let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; + let formal_ty = self.resolve_vars_if_possible(formal_ty); + let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; if let Compatibility::Incompatible(error) = compatibility { let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); @@ -1088,6 +1109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &missing_idxs[..] { &[expected_idx] => { let (_, input_ty) = formal_and_expected_inputs[expected_idx]; + let input_ty = self.resolve_vars_if_possible(input_ty); let span = if let Some((_, arg_span)) = provided_arg_tys.get(expected_idx.to_provided_idx()) { @@ -1110,6 +1132,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[first_idx, second_idx] => { let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let first_expected_ty = + self.resolve_vars_if_possible(first_expected_ty); + let second_expected_ty = + self.resolve_vars_if_possible(second_expected_ty); let span = if let (Some((_, first_span)), Some((_, second_span))) = ( provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(second_idx.to_provided_idx()), @@ -1136,8 +1162,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } &[first_idx, second_idx, third_idx] => { let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; + let first_expected_ty = + self.resolve_vars_if_possible(first_expected_ty); let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let second_expected_ty = + self.resolve_vars_if_possible(second_expected_ty); let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; + let third_expected_ty = + self.resolve_vars_if_possible(third_expected_ty); let span = if let (Some((_, first_span)), Some((_, third_span))) = ( provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(third_idx.to_provided_idx()), @@ -1197,6 +1229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) => { let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; + let first_expected_ty = self.resolve_vars_if_possible(first_expected_ty); let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { format!(", found `{first_provided_ty}`") } else { @@ -1209,6 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; + let second_provided_ty = self.resolve_vars_if_possible(second_provided_ty); let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { format!(", found `{second_provided_ty}`") } else { @@ -1227,6 +1261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Error::Permutation(args) => { for (dst_arg, dest_input) in args { let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; + let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_span) = provided_arg_tys[dest_input]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { format!(", found `{provided_ty}`") @@ -1247,6 +1282,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + self.label_generic_mismatches( + &mut err, + fn_def_id, + &matched_inputs, + &provided_arg_tys, + &formal_and_expected_inputs, + ); + // Incorporate the argument changes in the removal suggestion. // When a type is *missing*, and the rest are additional, we want to suggest these with a // multipart suggestion, but in order to do so we need to figure out *where* the arg that @@ -1282,6 +1325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // To suggest a multipart suggestion when encountering `foo(1, "")` where the def // was `fn foo(())`. let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; + let expected_ty = self.resolve_vars_if_possible(expected_ty); suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx))); } } @@ -1294,7 +1338,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method); + self.label_fn_like( + &mut err, + fn_def_id, + callee_ty, + call_expr, + None, + None, + &matched_inputs, + &formal_and_expected_inputs, + is_method, + ); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1348,6 +1402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Propose a placeholder of the correct type let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; + let expected_ty = self.resolve_vars_if_possible(expected_ty); ty_to_snippet(expected_ty, expected_idx) }; suggestion += &suggestion_text; @@ -2054,6 +2109,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Option>, // A specific argument should be labeled, instead of all of them expected_idx: Option, + matched_inputs: &IndexVec>, + formal_and_expected_inputs: &IndexVec, Ty<'tcx>)>, is_method: bool, ) { let Some(mut def_id) = callable_def_id else { @@ -2145,21 +2202,200 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let params = self + let param_generics: Vec>> = self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.fn_decl()) + .into_iter() + .flat_map(|decl| decl.inputs) + .skip(if is_method { 1 } else { 0 }) + .map(|param| { + if let hir::TyKind::Path(QPath::Resolved( + _, + hir::Path { res: Res::Def(_, res_def_id), .. }, + )) = param.kind + { + self.tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|generics| generics.params) + .find(|gen| &gen.def_id.to_def_id() == res_def_id) + } else { + None + } + }) + .collect(); + + let params: Vec<&hir::Param<'_>> = self .tcx .hir() .get_if_local(def_id) .and_then(|node| node.body_id()) .into_iter() .flat_map(|id| self.tcx.hir().body(id).params) - .skip(if is_method { 1 } else { 0 }); + .skip(if is_method { 1 } else { 0 }) + .collect(); + + if params.len() == param_generics.len() { + let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new(); + // This is a map from the index of the generic to the index of the parameter and the + // parameter + let mut matched_params_map: Vec<(usize, usize, &hir::Param<'_>)> = Vec::new(); + let mut unmatched_params_map: Vec<(usize, &hir::Param<'_>)> = Vec::new(); + + for (idx, (param, generic)) in + params.iter().zip_eq(param_generics.iter()).enumerate() + { + if matched_inputs[idx.into()].is_none() { + spans.push_span_label(param.span, ""); + continue; + } - for (_, param) in params - .into_iter() - .enumerate() - .filter(|(idx, _)| expected_idx.map_or(true, |expected_idx| expected_idx == *idx)) - { - spans.push_span_label(param.span, ""); + let Some(generic) = generic else { + spans.push_span_label(param.span, ""); + continue; + }; + + let mut found_unmatched_generic_params = vec![]; + + for unmatching_idx in idx + 1..params.len() { + if matched_inputs[unmatching_idx.into()].is_none() + && let Some(unmatched_idx_param_generic) = + param_generics[unmatching_idx] + && unmatched_idx_param_generic.name.ident() == generic.name.ident() + { + found_unmatched_generic_params.push(params[unmatching_idx]); + } + } + + if found_unmatched_generic_params.is_empty() { + continue; + } + + let generics_idx = generics_map + .iter() + .filter(|x| x.1.name.ident() == generic.name.ident()) + .next() + .map(|x| x.0); + + let generics_idx = generics_idx.unwrap_or_else(|| { + let generics_map_len = generics_map.len(); + generics_map.push((generics_map_len, generic)); + generics_map_len + }); + matched_params_map.push((generics_idx, idx, param)); + if unmatched_params_map.iter().filter(|x| x.0 == generics_idx).count() > 0 { + // Already processed the unmatched params + continue; + } + for unmatched_param in &found_unmatched_generic_params { + unmatched_params_map.push((generics_idx, unmatched_param)); + } + } + + for (generic_idx, generic) in &generics_map { + let matched_params: Vec<(usize, &hir::Param<'_>)> = matched_params_map + .iter() + .filter(|x| x.0 == *generic_idx) + .map(|x| (x.1, x.2)) + .collect(); + let unmatched_params: Vec<&hir::Param<'_>> = unmatched_params_map + .iter() + .filter(|x| x.0 == *generic_idx) + .map(|x| x.1) + .collect(); + + let all_param_idents: Vec = matched_params + .iter() + .map(|x| &x.1) + .chain(unmatched_params.iter()) + .map(|x| { + if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + spans.push_span_label( + generic.span, + format!( + "{} all reference this parameter {}", + display_list_with_comma_and(&all_param_idents), + generic.name.ident().name, + ), + ); + + for unmatched_param in &unmatched_params { + let idents: Vec = matched_params + .iter() + .map(|x| { + if let hir::PatKind::Binding(_, _, ident, _) = x.1.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + let matched_ty = matched_params + .iter() + .next() + .map(|x| formal_and_expected_inputs[x.0.into()]); + + if let Some(matched_ty) = matched_ty { + let matched_ty = + self.resolve_vars_if_possible(matched_ty.0).sort_string(self.tcx); + spans.push_span_label( + unmatched_param.span, + format!( + "this parameter needs to match the {} type of {}", + matched_ty, + display_list_with_comma_and(&idents) + ), + ); + } else { + spans.push_span_label( + unmatched_param.span, + format!( + "this parameter needs to match the type of {}", + display_list_with_comma_and(&idents) + ), + ); + } + } + + for matched_param in &matched_params { + let idents: Vec = unmatched_params + .iter() + .map(|x| { + if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + spans.push_span_label( + matched_param.1.span, + format!( + "{} needs to match the type of this parameter", + display_list_with_comma_and(&idents) + ), + ); + } + } + } else { + for (_, param) in params.iter().enumerate().filter(|(idx, _)| { + expected_idx.map_or(true, |expected_idx| expected_idx == *idx) + }) { + spans.push_span_label(param.span, ""); + } } err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); @@ -2225,6 +2461,118 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } + + fn label_generic_mismatches( + &self, + err: &mut DiagnosticBuilder<'_>, + callable_def_id: Option, + matched_inputs: &IndexVec>, + provided_arg_tys: &IndexVec, Span)>, + formal_and_expected_inputs: &IndexVec, Ty<'tcx>)>, + ) { + let Some(def_id) = callable_def_id else { + return; + }; + + for (matched_idx, matched_arg) in matched_inputs.iter_enumerated() { + let Some(matched_input) = matched_arg else { + continue; + }; + + let (_, matched_arg_span) = provided_arg_tys[*matched_input]; + let (matched_formal_ty, _) = formal_and_expected_inputs[matched_idx]; + let ty::Infer(ty::TyVar(a)) = matched_formal_ty.kind() else { + continue; + }; + + let mut formal_ty_idxs_matched: Vec = vec![]; + let mut expected_ty_matched = None; + for (input_idx, (formal_ty, expected_ty)) in formal_and_expected_inputs + .iter_enumerated() + // Only care about args after the matched one we're checking. + // + // NB: Incompatible should always come after their matching generics. + // e.g. if we have a function fn f(a: T, b: T, c: T) and we call it with + // f(1, 2, 3.0) then the first will force T to be an integer, the second + // then matches and the third is the incompatible argument. + .filter(|(idx, _)| *idx > matched_idx) + { + if let ty::Infer(ty::TyVar(b)) = formal_ty.kind() { + if self.root_var(*a) == self.root_var(*b) { + formal_ty_idxs_matched.push(input_idx.into()); + if expected_ty_matched.is_none() { + expected_ty_matched = Some(expected_ty); + } + } + } + } + + let Some(expected_ty) = expected_ty_matched else { + continue; + }; + + let params = self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .flat_map(|id| self.tcx.hir().body(id).params); + + let mut all_pats_matched: Vec = vec![]; + let mut incompatible_pats_matched: Vec = vec![]; + for (idx, param) in params + .into_iter() + .enumerate() + .filter(|(idx, _)| formal_ty_idxs_matched.contains(idx)) + { + let ident = if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { + format!("`{ident}`") + } else { + format!("`idx:{idx}`") + }; + if matched_inputs[idx.into()].is_none() { + incompatible_pats_matched.push(ident.clone()); + } + all_pats_matched.push(ident); + } + + let expected_display_type = + self.resolve_vars_if_possible(*expected_ty).sort_string(self.tcx); + let label = if all_pats_matched.len() == 0 { + format!( + "expected all arguments to be {} because they need to match the type of this parameter", + expected_display_type + ) + } else if all_pats_matched.len() == incompatible_pats_matched.len() { + format!( + "expected {} {} to be {} {} because {} to match the type of this parameter", + format!("argument{}", pluralize!(incompatible_pats_matched.len())), + display_list_with_comma_and(&incompatible_pats_matched), + a_or_an(&expected_display_type), + expected_display_type, + if all_pats_matched.len() == 1 { + "that argument needs" + } else { + "those arguments need" + } + ) + } else { + format!( + "expected {} {} to be {} {} because the {} {} {} to match the type of this parameter", + format!("argument{}", pluralize!(incompatible_pats_matched.len())), + display_list_with_comma_and(&incompatible_pats_matched), + a_or_an(&expected_display_type), + expected_display_type, + format!("argument{}", pluralize!(all_pats_matched.len())), + display_list_with_comma_and(&all_pats_matched), + format!("need{}", pluralize!(if all_pats_matched.len() == 1 { 0 } else { 1 })), + ) + }; + + err.span_label(matched_arg_span, label); + } + } } struct FindClosureArg<'tcx> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7f200a7b623d6..6279c402fc808 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -39,6 +39,39 @@ macro_rules! pluralize { }; } +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Returns "an" if the given string starts with a vowel, and "a" otherwise. +pub fn a_or_an(s: &str) -> &'static str { + let mut chars = s.chars(); + let Some(mut first_alpha_char) = chars.next() else { + return "a"; + }; + if first_alpha_char == '`' { + let Some(next) = chars.next() else { + return "a"; + }; + first_alpha_char = next; + } + if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) { + "an" + } else { + "a" + } +} + +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" +pub fn display_list_with_comma_and(v: &[T]) -> String { + match v.len() { + 0 => "".to_string(), + 1 => v[0].to_string(), + 2 => format!("{} and {}", v[0], v[1]), + _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])), + } +} + /// Indicates the confidence in the correctness of a suggestion. /// /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index 5ad8e35920a10..4cbe9124deec1 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -45,7 +45,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:23:3 @@ -60,7 +60,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 @@ -74,7 +74,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ help: remove the extra arguments | LL - one_arg(1, "", 1.0); @@ -319,7 +319,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 @@ -334,7 +334,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:55:3 @@ -349,7 +349,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:60:3 @@ -364,7 +364,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ ----- + | ^^^^^^^ error: aborting due to 22 previous errors diff --git a/tests/ui/argument-suggestions/invalid_arguments.stderr b/tests/ui/argument-suggestions/invalid_arguments.stderr index d26f33d098be0..61a46b067f5bc 100644 --- a/tests/ui/argument-suggestions/invalid_arguments.stderr +++ b/tests/ui/argument-suggestions/invalid_arguments.stderr @@ -24,7 +24,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:6:4 | LL | fn two_arg_same(_a: i32, _b: i32) {} - | ^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^ ------- ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:17:16 @@ -38,7 +38,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:6:4 | LL | fn two_arg_same(_a: i32, _b: i32) {} - | ^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^ ------- ------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:18:3 @@ -66,7 +66,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:7:4 | LL | fn two_arg_diff(_a: i32, _b: f32) {} - | ^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^ ------- ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:20:16 @@ -80,7 +80,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:7:4 | LL | fn two_arg_diff(_a: i32, _b: f32) {} - | ^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^ ------- ------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:21:3 @@ -108,7 +108,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:25:21 @@ -122,7 +122,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:26:26 @@ -136,7 +136,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ -------- + | ^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:28:3 @@ -207,7 +207,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:35:23 @@ -221,7 +221,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ ------- + | ^^^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:36:26 @@ -235,7 +235,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ -------- + | ^^^^^^^^^^^^^^^^ ------- ------- -------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:38:3 diff --git a/tests/ui/argument-suggestions/too-long.stderr b/tests/ui/argument-suggestions/too-long.stderr index 04ee9275cb363..9400f2a02a827 100644 --- a/tests/ui/argument-suggestions/too-long.stderr +++ b/tests/ui/argument-suggestions/too-long.stderr @@ -11,9 +11,31 @@ note: method defined here | LL | fn foo( | ^^^ -... +LL | &self, +LL | a: i32, + | ------ +LL | b: i32, + | ------ +LL | c: i32, + | ------ +LL | d: i32, + | ------ +LL | e: i32, + | ------ LL | f: i32, | ------ +LL | g: i32, + | ------ +LL | h: i32, + | ------ +LL | i: i32, + | ------ +LL | j: i32, + | ------ +LL | k: i32, + | ------ +LL | l: i32, + | ------ help: consider dereferencing the borrow | LL | qux.foo(a, b, c, d, e, *f, g, h, i, j, k, l); diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index e4cb0915a1090..5ad54bc5b8e3f 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -5,6 +5,7 @@ LL | fun(async {}, async {}); | --- -------- ^^^^^^^^ expected `async` block, found a different `async` block | | | | | the expected `async` block + | | expected argument `f2` to be an `async` block because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}` @@ -13,14 +14,19 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ ----- + | ^^^ - ----- ----- + | | | | + | | | this parameter needs to match the `async` block type of `f1` + | | `f2` needs to match the type of this parameter + | `f1` and `f2` all reference this parameter F error[E0308]: mismatched types --> $DIR/coroutine-desc.rs:12:16 | LL | fun(one(), two()); - | --- ^^^^^ expected future, found a different future - | | + | --- ----- ^^^^^ expected future, found a different future + | | | + | | expected argument `f2` to be a future because that argument needs to match the type of this parameter | arguments to this function are incorrect | = help: consider `await`ing on both `Future`s @@ -29,15 +35,20 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ ----- + | ^^^ - ----- ----- + | | | | + | | | this parameter needs to match the future type of `f1` + | | `f2` needs to match the type of this parameter + | `f1` and `f2` all reference this parameter F error[E0308]: mismatched types --> $DIR/coroutine-desc.rs:14:26 | LL | fun((async || {})(), (async || {})()); - | --- -- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body - | | | - | | the expected `async` closure body + | --- --------------- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body + | | | | + | | | the expected `async` closure body + | | expected argument `f2` to be an `async` closure body because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}` @@ -46,7 +57,11 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ ----- + | ^^^ - ----- ----- + | | | | + | | | this parameter needs to match the `async` closure body type of `f1` + | | `f2` needs to match the type of this parameter + | `f1` and `f2` all reference this parameter F error: aborting due to 3 previous errors diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr index 498ef33d52ecc..b67f91ff8e28d 100644 --- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr +++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr @@ -2,8 +2,9 @@ error[E0308]: mismatched types --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18 | LL | test(&mut 7, &7); - | ---- ^^ types differ in mutability - | | + | ---- ------ ^^ types differ in mutability + | | | + | | expected argument `_b` to be an `&mut {integer}` because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected mutable reference `&mut {integer}` @@ -12,7 +13,11 @@ note: function defined here --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4 | LL | fn test(_a: T, _b: T) {} - | ^^^^ ----- + | ^^^^ - ----- ----- + | | | | + | | | this parameter needs to match the `&mut {integer}` type of `_a` + | | `_b` needs to match the type of this parameter + | `_a` and `_b` all reference this parameter T error: aborting due to 1 previous error diff --git a/tests/ui/coercion/coerce-to-bang.stderr b/tests/ui/coercion/coerce-to-bang.stderr index 3c737358adc77..4c21eef5c2917 100644 --- a/tests/ui/coercion/coerce-to-bang.stderr +++ b/tests/ui/coercion/coerce-to-bang.stderr @@ -12,7 +12,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- + | ^^^ -------- ---- -------- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:18:13 @@ -28,7 +28,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- + | ^^^ -------- ---- -------- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:26:12 @@ -44,7 +44,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- + | ^^^ -------- ---- -------- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:36:12 @@ -60,7 +60,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- + | ^^^ -------- ---- -------- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:45:12 @@ -76,7 +76,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ ---- + | ^^^ -------- ---- -------- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:50:21 diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr index da90b8b81c855..24c7a3cb4828a 100644 --- a/tests/ui/fn/fn-item-type.stderr +++ b/tests/ui/fn/fn-item-type.stderr @@ -2,8 +2,9 @@ error[E0308]: mismatched types --> $DIR/fn-item-type.rs:22:19 | LL | eq(foo::, bar::); - | -- ^^^^^^^^^ expected fn item, found a different fn item - | | + | -- --------- ^^^^^^^^^ expected fn item, found a different fn item + | | | + | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -13,15 +14,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ ---- + | ^^ - ---- ---- + | | | | + | | | this parameter needs to match the fn item type of `x` + | | `y` needs to match the type of this parameter + | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:29:19 | LL | eq(foo::, foo::); - | -- ^^^^^^^^^ expected `u8`, found `i8` - | | + | -- --------- ^^^^^^^^^ expected `u8`, found `i8` + | | | + | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -31,15 +37,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ ---- + | ^^ - ---- ---- + | | | | + | | | this parameter needs to match the fn item type of `x` + | | `y` needs to match the type of this parameter + | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:34:23 | LL | eq(bar::, bar::>); - | -- ^^^^^^^^^^^^^^ expected `String`, found `Vec` - | | + | -- ------------- ^^^^^^^^^^^^^^ expected `String`, found `Vec` + | | | + | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {bar::}` @@ -49,15 +60,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ ---- + | ^^ - ---- ---- + | | | | + | | | this parameter needs to match the fn item type of `x` + | | `y` needs to match the type of this parameter + | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:40:26 | LL | eq(::foo, ::foo); - | -- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` - | | + | -- ---------------- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` + | | | + | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn() {::foo}` @@ -67,15 +83,20 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ ---- + | ^^ - ---- ---- + | | | | + | | | this parameter needs to match the fn item type of `x` + | | `y` needs to match the type of this parameter + | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn()` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:45:19 | LL | eq(foo::, bar:: as fn(isize) -> isize); - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer - | | + | -- --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer + | | | + | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -85,7 +106,11 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ ---- + | ^^ - ---- ---- + | | | | + | | | this parameter needs to match the fn item type of `x` + | | `y` needs to match the type of this parameter + | `x` and `y` all reference this parameter T error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs new file mode 100644 index 0000000000000..9a38b948e8ea5 --- /dev/null +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs @@ -0,0 +1,12 @@ +fn foo(a: T, b: T) {} +fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} +fn foo_multi_generics(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {} + +fn main() { + foo(1, 2.); + //~^ ERROR mismatched types + foo_multi_same("a", "b", false, true, (), 32); + //~^ ERROR arguments to this function are incorrect + foo_multi_generics("a", "b", "c", true, false, 32, 2.); + //~^ ERROR arguments to this function are incorrect +} diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr new file mode 100644 index 0000000000000..a4f55ce06ac76 --- /dev/null +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr @@ -0,0 +1,75 @@ +error[E0308]: mismatched types + --> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12 + | +LL | foo(1, 2.); + | --- - ^^ expected integer, found floating-point number + | | | + | | expected argument `b` to be an integer because that argument needs to match the type of this parameter + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4 + | +LL | fn foo(a: T, b: T) {} + | ^^^ - ---- ---- + | | | | + | | | this parameter needs to match the integer type of `a` + | | `b` needs to match the type of this parameter + | `a` and `b` all reference this parameter T + +error[E0308]: arguments to this function are incorrect + --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5 + | +LL | foo_multi_same("a", "b", false, true, (), 32); + | ^^^^^^^^^^^^^^ --- --- ----- ---- -- expected `&str`, found `()` + | | | | | + | | | | expected `&str`, found `bool` + | | | expected `&str`, found `bool` + | | expected arguments `c`, `d` and `e` to be an `&str` because those arguments need to match the type of this parameter + | expected arguments `c`, `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need to match the type of this parameter + | +note: function defined here + --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4 + | +LL | fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} + | ^^^^^^^^^^^^^^ - ---- ---- ---- ---- ---- ------ + | | | | | | | + | | | | | | this parameter needs to match the `&str` type of `a` and `b` + | | | | | this parameter needs to match the `&str` type of `a` and `b` + | | | | this parameter needs to match the `&str` type of `a` and `b` + | | | `c`, `d` and `e` needs to match the type of this parameter + | | `c`, `d` and `e` needs to match the type of this parameter + | `a`, `b`, `c`, `d` and `e` all reference this parameter T + +error[E0308]: arguments to this function are incorrect + --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5 + | +LL | foo_multi_generics("a", "b", "c", true, false, 32, 2.); + | ^^^^^^^^^^^^^^^^^^ --- --- --- ---- ----- -- -- expected integer, found floating-point number + | | | | | | | + | | | | | | expected argument `g` to be an integer because that argument needs to match the type of this parameter + | | | | | expected `&str`, found `bool` + | | | | expected `&str`, found `bool` + | | | expected arguments `d` and `e` to be an `&str` because those arguments need to match the type of this parameter + | | expected arguments `d` and `e` to be an `&str` because the arguments `c`, `d` and `e` need to match the type of this parameter + | expected arguments `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need to match the type of this parameter + | +note: function defined here + --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4 + | +LL | fn foo_multi_generics(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {} + | ^^^^^^^^^^^^^^^^^^ - - ---- ---- ---- ---- ---- ---- ---- + | | | | | | | | | | + | | | | | | | | | this parameter needs to match the integer type of `f` + | | | | | | | | `g` needs to match the type of this parameter + | | | | | | | this parameter needs to match the `&str` type of `a`, `b` and `c` + | | | | | | this parameter needs to match the `&str` type of `a`, `b` and `c` + | | | | | `d` and `e` needs to match the type of this parameter + | | | | `d` and `e` needs to match the type of this parameter + | | | `d` and `e` needs to match the type of this parameter + | | `a`, `b`, `c`, `d` and `e` all reference this parameter T + | `f` and `g` all reference this parameter S + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/never_type/issue-96335.stderr b/tests/ui/never_type/issue-96335.stderr index c3d80a425e057..13cdbe842c9dc 100644 --- a/tests/ui/never_type/issue-96335.stderr +++ b/tests/ui/never_type/issue-96335.stderr @@ -21,6 +21,7 @@ LL | 0.....{loop{}1}; | | | | | expected integer, found `RangeTo<{integer}>` | arguments to this function are incorrect + | expected all arguments to be integer because they need to match the type of this parameter | = note: expected type `{integer}` found struct `RangeTo<{integer}>` diff --git a/tests/ui/parser/issues/issue-93282.stderr b/tests/ui/parser/issues/issue-93282.stderr index c6140bb821e48..fc15865e1a729 100644 --- a/tests/ui/parser/issues/issue-93282.stderr +++ b/tests/ui/parser/issues/issue-93282.stderr @@ -43,7 +43,7 @@ note: function defined here --> $DIR/issue-93282.rs:7:4 | LL | fn bar(a: usize, b: usize) -> usize { - | ^^^ -------- + | ^^^ -------- -------- error: aborting due to 4 previous errors diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index f0dea66f6128d..1b9ad3a3f1675 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -77,7 +77,7 @@ note: function defined here --> $DIR/issue-34264.rs:3:4 | LL | fn bar(x, y: usize) {} - | ^^^ -------- + | ^^^ - -------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 diff --git a/tests/ui/tuple/add-tuple-within-arguments.stderr b/tests/ui/tuple/add-tuple-within-arguments.stderr index 6849128eaddde..8414a51bfd5e8 100644 --- a/tests/ui/tuple/add-tuple-within-arguments.stderr +++ b/tests/ui/tuple/add-tuple-within-arguments.stderr @@ -8,7 +8,7 @@ note: function defined here --> $DIR/add-tuple-within-arguments.rs:1:4 | LL | fn foo(s: &str, a: (i32, i32), s2: &str) {} - | ^^^ ------------- + | ^^^ ------- ------------- -------- help: wrap these arguments in parentheses to construct a tuple | LL | foo("hi", (1, 2), "hi"); @@ -28,7 +28,7 @@ note: function defined here --> $DIR/add-tuple-within-arguments.rs:3:4 | LL | fn bar(s: &str, a: (&str,), s2: &str) {} - | ^^^ ---------- + | ^^^ ------- ---------- -------- help: use a trailing comma to create a tuple with one element | LL | bar("hi", ("hi",), "hi"); diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index fbe6bfeebb149..63a98a55127a8 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -74,7 +74,7 @@ note: function defined here --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 | LL | fn function(x: T, y: bool) -> T { - | ^^^^^^^^ ---- + | ^^^^^^^^ ---- ------- help: change the type of the numeric literal from `u32` to `u16` | LL | let x: u16 = function(0u16, true); From 8a5245e7dd006e2eb6bf6d3834b05772285efe28 Mon Sep 17 00:00:00 2001 From: Steven Trotter Date: Mon, 26 Feb 2024 21:00:35 +0000 Subject: [PATCH 02/18] Refactored a few bits: - Firstly get all the information about generics matching out of the HIR - Secondly the labelling for the function is more coherent now - Lastly a few error message improvements --- compiler/rustc_errors/src/lib.rs | 35 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 493 ++++++++---------- compiler/rustc_lint_defs/src/lib.rs | 33 -- .../extra_arguments.stderr | 14 +- .../invalid_arguments.stderr | 20 +- tests/ui/argument-suggestions/too-long.stderr | 24 +- tests/ui/async-await/coroutine-desc.stderr | 27 +- .../coerce-reborrow-multi-arg-fail.stderr | 9 +- tests/ui/coercion/coerce-to-bang.stderr | 10 +- tests/ui/fn/fn-item-type.stderr | 45 +- ...generic-mismatch-reporting-issue-116615.rs | 2 + ...ric-mismatch-reporting-issue-116615.stderr | 64 ++- tests/ui/never_type/issue-96335.stderr | 1 - tests/ui/parser/issues/issue-93282.stderr | 2 +- tests/ui/span/issue-34264.stderr | 2 +- .../tuple/add-tuple-within-arguments.stderr | 4 +- ...call-return-type-due-to-generic-arg.stderr | 2 +- 17 files changed, 359 insertions(+), 428 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b88b5bcd7ea58..3098eb20be3ac 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, }; -pub use rustc_lint_defs::{a_or_an, display_list_with_comma_and, pluralize, Applicability}; +pub use rustc_lint_defs::{pluralize, Applicability}; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; pub use rustc_span::ErrorGuaranteed; pub use snippet::Style; @@ -1946,6 +1946,39 @@ pub fn report_ambiguity_error<'a, G: EmissionGuarantee>( } } +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Returns "an" if the given string starts with a vowel, and "a" otherwise. +pub fn a_or_an(s: &str) -> &'static str { + let mut chars = s.chars(); + let Some(mut first_alpha_char) = chars.next() else { + return "a"; + }; + if first_alpha_char == '`' { + let Some(next) = chars.next() else { + return "a"; + }; + first_alpha_char = next; + } + if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) { + "an" + } else { + "a" + } +} + +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" +pub fn display_list_with_comma_and(v: &[T]) -> String { + match v.len() { + 0 => "".to_string(), + 1 => v[0].to_string(), + 2 => format!("{} and {}", v[0], v[1]), + _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])), + } +} + #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TerminalUrl { No, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b65ac134fbc1f..c0d971523548e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -18,7 +18,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ a_or_an, codes::*, display_list_with_comma_and, pluralize, Applicability, Diag, - DiagnosticBuilder, ErrorGuaranteed, MultiSpan, StashKey, + ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -424,7 +424,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "expected formal_input_tys to be the same size as expected_input_tys" ); let formal_and_expected_inputs = IndexVec::from_iter( - formal_input_tys.iter().copied().zip_eq(expected_input_tys.iter().copied()), + formal_input_tys + .iter() + .copied() + .zip_eq(expected_input_tys.iter().copied()) + .map(|vars| self.resolve_vars_if_possible(vars)), ); self.set_tainted_by_errors(self.report_arg_errors( @@ -639,8 +643,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; - let formal_input_ty = self.resolve_vars_if_possible(formal_input_ty); - let expected_input_ty = self.resolve_vars_if_possible(expected_input_ty); // If either is an error type, we defy the usual convention and consider them to *not* be // coercible. This prevents our error message heuristic from trying to pass errors into // every argument. @@ -713,7 +715,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Do we have as many extra provided arguments as the tuple's length? // If so, we might have just forgotten to wrap some args in a tuple. if let Some(ty::Tuple(tys)) = - formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| self.resolve_vars_if_possible(tys.1).kind()) + formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) // If the tuple is unit, we're not actually wrapping any arguments. && !tys.is_empty() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() @@ -732,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), ), ) { - if !self.can_coerce(provided_ty, self.resolve_vars_if_possible(*expected_ty)) { + if !self.can_coerce(provided_ty, *expected_ty) { satisfied = false; break; } @@ -751,14 +753,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tys.len() == 1 { // A tuple wrap suggestion actually occurs within, // so don't do anything special here. - let (formal_ty, expected_ty) = - formal_and_expected_inputs[mismatch_idx.into()]; - let formal_ty = self.resolve_vars_if_possible(formal_ty); - let expected_ty = self.resolve_vars_if_possible(expected_ty); err = self.err_ctxt().report_and_explain_type_error( mk_trace( *lo, - (formal_ty, expected_ty), + formal_and_expected_inputs[mismatch_idx.into()], provided_arg_tys[mismatch_idx.into()].0, ), terr, @@ -842,10 +840,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; }; let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; - let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; - let formal_ty = self.resolve_vars_if_possible(formal_ty); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); + let trace = + mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { let mut err = self.err_ctxt().report_and_explain_type_error(trace, *e); suggest_confusable(&mut err); @@ -873,8 +869,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ] = &errors[..] { let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; - let formal_ty = self.resolve_vars_if_possible(formal_ty); - let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); let mut err = self.err_ctxt().report_and_explain_type_error(trace, *err); @@ -896,6 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &provided_arg_tys, &formal_and_expected_inputs, + is_method, ); if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind @@ -1003,8 +998,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match error { Error::Invalid(provided_idx, expected_idx, compatibility) => { let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; - let formal_ty = self.resolve_vars_if_possible(formal_ty); - let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; if let Compatibility::Incompatible(error) = compatibility { let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); @@ -1109,7 +1102,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &missing_idxs[..] { &[expected_idx] => { let (_, input_ty) = formal_and_expected_inputs[expected_idx]; - let input_ty = self.resolve_vars_if_possible(input_ty); let span = if let Some((_, arg_span)) = provided_arg_tys.get(expected_idx.to_provided_idx()) { @@ -1132,10 +1124,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[first_idx, second_idx] => { let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; - let first_expected_ty = - self.resolve_vars_if_possible(first_expected_ty); - let second_expected_ty = - self.resolve_vars_if_possible(second_expected_ty); let span = if let (Some((_, first_span)), Some((_, second_span))) = ( provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(second_idx.to_provided_idx()), @@ -1162,14 +1150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } &[first_idx, second_idx, third_idx] => { let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; - let first_expected_ty = - self.resolve_vars_if_possible(first_expected_ty); let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; - let second_expected_ty = - self.resolve_vars_if_possible(second_expected_ty); let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; - let third_expected_ty = - self.resolve_vars_if_possible(third_expected_ty); let span = if let (Some((_, first_span)), Some((_, third_span))) = ( provided_arg_tys.get(first_idx.to_provided_idx()), provided_arg_tys.get(third_idx.to_provided_idx()), @@ -1229,7 +1211,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) => { let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; - let first_expected_ty = self.resolve_vars_if_possible(first_expected_ty); let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { format!(", found `{first_provided_ty}`") } else { @@ -1242,7 +1223,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; - let second_provided_ty = self.resolve_vars_if_possible(second_provided_ty); let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { format!(", found `{second_provided_ty}`") } else { @@ -1261,7 +1241,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Error::Permutation(args) => { for (dst_arg, dest_input) in args { let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; - let expected_ty = self.resolve_vars_if_possible(expected_ty); let (provided_ty, provided_span) = provided_arg_tys[dest_input]; let provided_ty_name = if !has_error_or_infer([provided_ty]) { format!(", found `{provided_ty}`") @@ -1288,6 +1267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &matched_inputs, &provided_arg_tys, &formal_and_expected_inputs, + is_method, ); // Incorporate the argument changes in the removal suggestion. @@ -1325,7 +1305,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // To suggest a multipart suggestion when encountering `foo(1, "")` where the def // was `fn foo(())`. let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; - let expected_ty = self.resolve_vars_if_possible(expected_ty); suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx))); } } @@ -1402,7 +1381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Propose a placeholder of the correct type let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; - let expected_ty = self.resolve_vars_if_possible(expected_ty); ty_to_snippet(expected_ty, expected_idx) }; suggestion += &suggestion_text; @@ -2202,118 +2180,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let mut spans: MultiSpan = def_span.into(); - let param_generics: Vec>> = self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.fn_decl()) - .into_iter() - .flat_map(|decl| decl.inputs) - .skip(if is_method { 1 } else { 0 }) - .map(|param| { - if let hir::TyKind::Path(QPath::Resolved( - _, - hir::Path { res: Res::Def(_, res_def_id), .. }, - )) = param.kind - { - self.tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.generics()) - .into_iter() - .flat_map(|generics| generics.params) - .find(|gen| &gen.def_id.to_def_id() == res_def_id) - } else { - None - } - }) - .collect(); + let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); + let mut generics_with_unmatched_params = Vec::new(); - let params: Vec<&hir::Param<'_>> = self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params) - .skip(if is_method { 1 } else { 0 }) - .collect(); - - if params.len() == param_generics.len() { - let mut generics_map: Vec<(usize, &hir::GenericParam<'_>)> = Vec::new(); - // This is a map from the index of the generic to the index of the parameter and the - // parameter - let mut matched_params_map: Vec<(usize, usize, &hir::Param<'_>)> = Vec::new(); - let mut unmatched_params_map: Vec<(usize, &hir::Param<'_>)> = Vec::new(); - - for (idx, (param, generic)) in - params.iter().zip_eq(param_generics.iter()).enumerate() + let check_for_matched_generics = || { + if matched_inputs.iter().any(|x| x.is_some()) + && params_with_generics.iter().any(|x| x.0.is_some()) { - if matched_inputs[idx.into()].is_none() { - spans.push_span_label(param.span, ""); - continue; - } - - let Some(generic) = generic else { - spans.push_span_label(param.span, ""); - continue; - }; + for (idx, (generic, _)) in params_with_generics.iter().enumerate() { + // Param has to have a generic and be matched to be relevant + if matched_inputs[idx.into()].is_none() { + continue; + } - let mut found_unmatched_generic_params = vec![]; + let Some(generic) = generic else { + continue; + }; - for unmatching_idx in idx + 1..params.len() { - if matched_inputs[unmatching_idx.into()].is_none() - && let Some(unmatched_idx_param_generic) = - param_generics[unmatching_idx] - && unmatched_idx_param_generic.name.ident() == generic.name.ident() - { - found_unmatched_generic_params.push(params[unmatching_idx]); + for unmatching_idx in idx + 1..params_with_generics.len() { + if matched_inputs[unmatching_idx.into()].is_none() + && let Some(unmatched_idx_param_generic) = + params_with_generics[unmatching_idx].0 + && unmatched_idx_param_generic.name.ident() == generic.name.ident() + { + // We found a parameter that didn't match that needed to + return true; + } } } + } + false + }; - if found_unmatched_generic_params.is_empty() { - continue; - } + let check_for_matched_generics = check_for_matched_generics(); - let generics_idx = generics_map - .iter() - .filter(|x| x.1.name.ident() == generic.name.ident()) - .next() - .map(|x| x.0); - - let generics_idx = generics_idx.unwrap_or_else(|| { - let generics_map_len = generics_map.len(); - generics_map.push((generics_map_len, generic)); - generics_map_len - }); - matched_params_map.push((generics_idx, idx, param)); - if unmatched_params_map.iter().filter(|x| x.0 == generics_idx).count() > 0 { - // Already processed the unmatched params - continue; - } - for unmatched_param in &found_unmatched_generic_params { - unmatched_params_map.push((generics_idx, unmatched_param)); - } - } + for (idx, (generic_param, param)) in + params_with_generics.iter().enumerate().filter(|(idx, _)| { + check_for_matched_generics + || expected_idx.map_or(true, |expected_idx| expected_idx == *idx) + }) + { + let Some(generic_param) = generic_param else { + spans.push_span_label(param.span, ""); + continue; + }; - for (generic_idx, generic) in &generics_map { - let matched_params: Vec<(usize, &hir::Param<'_>)> = matched_params_map - .iter() - .filter(|x| x.0 == *generic_idx) - .map(|x| (x.1, x.2)) - .collect(); - let unmatched_params: Vec<&hir::Param<'_>> = unmatched_params_map - .iter() - .filter(|x| x.0 == *generic_idx) - .map(|x| x.1) - .collect(); + let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics + .iter() + .enumerate() + .filter(|(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; + } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[idx.into()].is_none() + && matched_inputs[(*other_idx).into()].is_none() + { + return false; + } + if matched_inputs[idx.into()].is_some() + && matched_inputs[(*other_idx).into()].is_some() + { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }) + .map(|(other_idx, (_, other_param))| (other_idx, *other_param)) + .collect(); - let all_param_idents: Vec = matched_params + if !other_params_matched.is_empty() { + let other_param_matched_names: Vec = other_params_matched .iter() - .map(|x| &x.1) - .chain(unmatched_params.iter()) - .map(|x| { - if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind { + .map(|(_, other_param)| { + if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind { format!("`{ident}`") } else { "{unknown}".to_string() @@ -2321,83 +2262,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - spans.push_span_label( - generic.span, - format!( - "{} all reference this parameter {}", - display_list_with_comma_and(&all_param_idents), - generic.name.ident().name, - ), - ); + let matched_ty = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); - for unmatched_param in &unmatched_params { - let idents: Vec = matched_params - .iter() - .map(|x| { - if let hir::PatKind::Binding(_, _, ident, _) = x.1.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() - } - }) - .collect(); - - let matched_ty = matched_params - .iter() - .next() - .map(|x| formal_and_expected_inputs[x.0.into()]); - - if let Some(matched_ty) = matched_ty { - let matched_ty = - self.resolve_vars_if_possible(matched_ty.0).sort_string(self.tcx); - spans.push_span_label( - unmatched_param.span, - format!( - "this parameter needs to match the {} type of {}", - matched_ty, - display_list_with_comma_and(&idents) - ), - ); - } else { - spans.push_span_label( - unmatched_param.span, + if matched_inputs[idx.into()].is_some() { + spans.push_span_label( + param.span, + format!( + "{} {} to match the {} type of this parameter", + display_list_with_comma_and(&other_param_matched_names), format!( - "this parameter needs to match the type of {}", - display_list_with_comma_and(&idents) + "need{}", + pluralize!(if other_param_matched_names.len() == 1 { + 0 + } else { + 1 + }) ), - ); - } - } - - for matched_param in &matched_params { - let idents: Vec = unmatched_params - .iter() - .map(|x| { - if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind { - format!("`{ident}`") - } else { - "{unknown}".to_string() - } - }) - .collect(); - + matched_ty, + ), + ); + } else { spans.push_span_label( - matched_param.1.span, + param.span, format!( - "{} needs to match the type of this parameter", - display_list_with_comma_and(&idents) + "this parameter needs to match the {} type of {}", + matched_ty, + display_list_with_comma_and(&other_param_matched_names), ), ); } - } - } else { - for (_, param) in params.iter().enumerate().filter(|(idx, _)| { - expected_idx.map_or(true, |expected_idx| expected_idx == *idx) - }) { + generics_with_unmatched_params.push(generic_param); + } else { spans.push_span_label(param.span, ""); } } + for generic_param in self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|x| x.params) + .filter(|x| { + generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident()) + }) + { + let param_idents_matching: Vec = params_with_generics + .iter() + .filter(|(generic, _)| { + if let Some(generic) = generic { + generic.name.ident() == generic_param.name.ident() + } else { + false + } + }) + .map(|(_, param)| { + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { + format!("`{ident}`") + } else { + "{unknown}".to_string() + } + }) + .collect(); + + if !param_idents_matching.is_empty() { + spans.push_span_label( + generic_param.span, + format!( + "{} all reference this parameter {}", + display_list_with_comma_and(¶m_idents_matching), + generic_param.name.ident().name, + ), + ); + } + } + err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind @@ -2464,115 +2406,112 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn label_generic_mismatches( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut Diag<'_>, callable_def_id: Option, matched_inputs: &IndexVec>, provided_arg_tys: &IndexVec, Span)>, formal_and_expected_inputs: &IndexVec, Ty<'tcx>)>, + is_method: bool, ) { let Some(def_id) = callable_def_id else { return; }; - for (matched_idx, matched_arg) in matched_inputs.iter_enumerated() { - let Some(matched_input) = matched_arg else { + let params_with_generics = self.get_hir_params_with_generics(def_id, is_method); + + for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() { + if matched_inputs[idx.into()].is_none() { + continue; + } + + let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else { continue; }; - let (_, matched_arg_span) = provided_arg_tys[*matched_input]; - let (matched_formal_ty, _) = formal_and_expected_inputs[matched_idx]; - let ty::Infer(ty::TyVar(a)) = matched_formal_ty.kind() else { + let Some(generic_param) = generic_param else { continue; }; - let mut formal_ty_idxs_matched: Vec = vec![]; - let mut expected_ty_matched = None; - for (input_idx, (formal_ty, expected_ty)) in formal_and_expected_inputs - .iter_enumerated() - // Only care about args after the matched one we're checking. - // - // NB: Incompatible should always come after their matching generics. - // e.g. if we have a function fn f(a: T, b: T, c: T) and we call it with - // f(1, 2, 3.0) then the first will force T to be an integer, the second - // then matches and the third is the incompatible argument. - .filter(|(idx, _)| *idx > matched_idx) - { - if let ty::Infer(ty::TyVar(b)) = formal_ty.kind() { - if self.root_var(*a) == self.root_var(*b) { - formal_ty_idxs_matched.push(input_idx.into()); - if expected_ty_matched.is_none() { - expected_ty_matched = Some(expected_ty); - } + let mut idxs_matched: Vec = vec![]; + for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter( + |(other_idx, (other_generic_param, _))| { + if *other_idx == idx { + return false; } - } + let Some(other_generic_param) = other_generic_param else { + return false; + }; + if matched_inputs[(*other_idx).into()].is_some() { + return false; + } + other_generic_param.name.ident() == generic_param.name.ident() + }, + ) { + idxs_matched.push(other_idx.into()); } - let Some(expected_ty) = expected_ty_matched else { + if idxs_matched.is_empty() { continue; - }; - - let params = self - .tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .flat_map(|id| self.tcx.hir().body(id).params); - - let mut all_pats_matched: Vec = vec![]; - let mut incompatible_pats_matched: Vec = vec![]; - for (idx, param) in params - .into_iter() - .enumerate() - .filter(|(idx, _)| formal_ty_idxs_matched.contains(idx)) - { - let ident = if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind { - format!("`{ident}`") - } else { - format!("`idx:{idx}`") - }; - if matched_inputs[idx.into()].is_none() { - incompatible_pats_matched.push(ident.clone()); - } - all_pats_matched.push(ident); } - let expected_display_type = - self.resolve_vars_if_possible(*expected_ty).sort_string(self.tcx); - let label = if all_pats_matched.len() == 0 { + let expected_display_type = self + .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .sort_string(self.tcx); + let label = if idxs_matched.len() == params_with_generics.len() - 1 { format!( - "expected all arguments to be {} because they need to match the type of this parameter", + "expected all arguments to be this {} type because they need to match the type of this parameter", expected_display_type ) - } else if all_pats_matched.len() == incompatible_pats_matched.len() { - format!( - "expected {} {} to be {} {} because {} to match the type of this parameter", - format!("argument{}", pluralize!(incompatible_pats_matched.len())), - display_list_with_comma_and(&incompatible_pats_matched), - a_or_an(&expected_display_type), - expected_display_type, - if all_pats_matched.len() == 1 { - "that argument needs" - } else { - "those arguments need" - } - ) } else { format!( - "expected {} {} to be {} {} because the {} {} {} to match the type of this parameter", - format!("argument{}", pluralize!(incompatible_pats_matched.len())), - display_list_with_comma_and(&incompatible_pats_matched), + "expected some other arguments to be {} {} type to match the type of this parameter", a_or_an(&expected_display_type), expected_display_type, - format!("argument{}", pluralize!(all_pats_matched.len())), - display_list_with_comma_and(&all_pats_matched), - format!("need{}", pluralize!(if all_pats_matched.len() == 1 { 0 } else { 1 })), ) }; - err.span_label(matched_arg_span, label); + err.span_label(*matched_arg_span, label); } } + + fn get_hir_params_with_generics( + &self, + def_id: DefId, + is_method: bool, + ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> { + let fn_node = self.tcx.hir().get_if_local(def_id); + + let generic_params: Vec>> = fn_node + .and_then(|node| node.fn_decl()) + .into_iter() + .flat_map(|decl| decl.inputs) + .skip(if is_method { 1 } else { 0 }) + .map(|param| { + if let hir::TyKind::Path(QPath::Resolved( + _, + hir::Path { res: Res::Def(_, res_def_id), .. }, + )) = param.kind + { + fn_node + .and_then(|node| node.generics()) + .into_iter() + .flat_map(|generics| generics.params) + .find(|gen| &gen.def_id.to_def_id() == res_def_id) + } else { + None + } + }) + .collect(); + + let params: Vec<&hir::Param<'_>> = fn_node + .and_then(|node| node.body_id()) + .into_iter() + .flat_map(|id| self.tcx.hir().body(id).params) + .skip(if is_method { 1 } else { 0 }) + .collect(); + + generic_params.into_iter().zip(params).collect() + } } struct FindClosureArg<'tcx> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 6279c402fc808..7f200a7b623d6 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -39,39 +39,6 @@ macro_rules! pluralize { }; } -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Returns "an" if the given string starts with a vowel, and "a" otherwise. -pub fn a_or_an(s: &str) -> &'static str { - let mut chars = s.chars(); - let Some(mut first_alpha_char) = chars.next() else { - return "a"; - }; - if first_alpha_char == '`' { - let Some(next) = chars.next() else { - return "a"; - }; - first_alpha_char = next; - } - if ["a", "e", "i", "o", "u", "&"].contains(&&first_alpha_char.to_lowercase().to_string()[..]) { - "an" - } else { - "a" - } -} - -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" -pub fn display_list_with_comma_and(v: &[T]) -> String { - match v.len() { - 0 => "".to_string(), - 1 => v[0].to_string(), - 2 => format!("{} and {}", v[0], v[1]), - _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])), - } -} - /// Indicates the confidence in the correctness of a suggestion. /// /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index 4cbe9124deec1..5ad8e35920a10 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -45,7 +45,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:23:3 @@ -60,7 +60,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 @@ -74,7 +74,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- help: remove the extra arguments | LL - one_arg(1, "", 1.0); @@ -319,7 +319,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 @@ -334,7 +334,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:55:3 @@ -349,7 +349,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:60:3 @@ -364,7 +364,7 @@ note: function defined here --> $DIR/extra_arguments.rs:2:4 | LL | fn one_arg(_a: T) {} - | ^^^^^^^ + | ^^^^^^^ ----- error: aborting due to 22 previous errors diff --git a/tests/ui/argument-suggestions/invalid_arguments.stderr b/tests/ui/argument-suggestions/invalid_arguments.stderr index 61a46b067f5bc..d26f33d098be0 100644 --- a/tests/ui/argument-suggestions/invalid_arguments.stderr +++ b/tests/ui/argument-suggestions/invalid_arguments.stderr @@ -24,7 +24,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:6:4 | LL | fn two_arg_same(_a: i32, _b: i32) {} - | ^^^^^^^^^^^^ ------- ------- + | ^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:17:16 @@ -38,7 +38,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:6:4 | LL | fn two_arg_same(_a: i32, _b: i32) {} - | ^^^^^^^^^^^^ ------- ------- + | ^^^^^^^^^^^^ ------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:18:3 @@ -66,7 +66,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:7:4 | LL | fn two_arg_diff(_a: i32, _b: f32) {} - | ^^^^^^^^^^^^ ------- ------- + | ^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:20:16 @@ -80,7 +80,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:7:4 | LL | fn two_arg_diff(_a: i32, _b: f32) {} - | ^^^^^^^^^^^^ ------- ------- + | ^^^^^^^^^^^^ ------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:21:3 @@ -108,7 +108,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:25:21 @@ -122,7 +122,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:26:26 @@ -136,7 +136,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:8:4 | LL | fn three_arg_diff(_a: i32, _b: f32, _c: &str) {} - | ^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^ -------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:28:3 @@ -207,7 +207,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:35:23 @@ -221,7 +221,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^^^ ------- error[E0308]: mismatched types --> $DIR/invalid_arguments.rs:36:26 @@ -235,7 +235,7 @@ note: function defined here --> $DIR/invalid_arguments.rs:9:4 | LL | fn three_arg_repeat(_a: i32, _b: i32, _c: &str) {} - | ^^^^^^^^^^^^^^^^ ------- ------- -------- + | ^^^^^^^^^^^^^^^^ -------- error[E0308]: arguments to this function are incorrect --> $DIR/invalid_arguments.rs:38:3 diff --git a/tests/ui/argument-suggestions/too-long.stderr b/tests/ui/argument-suggestions/too-long.stderr index 9400f2a02a827..04ee9275cb363 100644 --- a/tests/ui/argument-suggestions/too-long.stderr +++ b/tests/ui/argument-suggestions/too-long.stderr @@ -11,31 +11,9 @@ note: method defined here | LL | fn foo( | ^^^ -LL | &self, -LL | a: i32, - | ------ -LL | b: i32, - | ------ -LL | c: i32, - | ------ -LL | d: i32, - | ------ -LL | e: i32, - | ------ +... LL | f: i32, | ------ -LL | g: i32, - | ------ -LL | h: i32, - | ------ -LL | i: i32, - | ------ -LL | j: i32, - | ------ -LL | k: i32, - | ------ -LL | l: i32, - | ------ help: consider dereferencing the borrow | LL | qux.foo(a, b, c, d, e, *f, g, h, i, j, k, l); diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index 5ad54bc5b8e3f..1f1e303ea4c67 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -5,7 +5,7 @@ LL | fun(async {}, async {}); | --- -------- ^^^^^^^^ expected `async` block, found a different `async` block | | | | | the expected `async` block - | | expected argument `f2` to be an `async` block because that argument needs to match the type of this parameter + | | expected all arguments to be this `async` block type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}` @@ -14,10 +14,9 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ - ----- ----- - | | | | - | | | this parameter needs to match the `async` block type of `f1` - | | `f2` needs to match the type of this parameter + | ^^^ - ----- ----- this parameter needs to match the `async` block type of `f1` + | | | + | | `f2` needs to match the `async` block type of this parameter | `f1` and `f2` all reference this parameter F error[E0308]: mismatched types @@ -26,7 +25,7 @@ error[E0308]: mismatched types LL | fun(one(), two()); | --- ----- ^^^^^ expected future, found a different future | | | - | | expected argument `f2` to be a future because that argument needs to match the type of this parameter + | | expected all arguments to be this future type because they need to match the type of this parameter | arguments to this function are incorrect | = help: consider `await`ing on both `Future`s @@ -35,10 +34,9 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ - ----- ----- - | | | | - | | | this parameter needs to match the future type of `f1` - | | `f2` needs to match the type of this parameter + | ^^^ - ----- ----- this parameter needs to match the future type of `f1` + | | | + | | `f2` needs to match the future type of this parameter | `f1` and `f2` all reference this parameter F error[E0308]: mismatched types @@ -48,7 +46,7 @@ LL | fun((async || {})(), (async || {})()); | --- --------------- ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body | | | | | | | the expected `async` closure body - | | expected argument `f2` to be an `async` closure body because that argument needs to match the type of this parameter + | | expected all arguments to be this `async` closure body type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}` @@ -57,10 +55,9 @@ note: function defined here --> $DIR/coroutine-desc.rs:8:4 | LL | fn fun>(f1: F, f2: F) {} - | ^^^ - ----- ----- - | | | | - | | | this parameter needs to match the `async` closure body type of `f1` - | | `f2` needs to match the type of this parameter + | ^^^ - ----- ----- this parameter needs to match the `async` closure body type of `f1` + | | | + | | `f2` needs to match the `async` closure body type of this parameter | `f1` and `f2` all reference this parameter F error: aborting due to 3 previous errors diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr index b67f91ff8e28d..46723c5a297f7 100644 --- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr +++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | test(&mut 7, &7); | ---- ------ ^^ types differ in mutability | | | - | | expected argument `_b` to be an `&mut {integer}` because that argument needs to match the type of this parameter + | | expected all arguments to be this `&mut {integer}` type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected mutable reference `&mut {integer}` @@ -13,10 +13,9 @@ note: function defined here --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4 | LL | fn test(_a: T, _b: T) {} - | ^^^^ - ----- ----- - | | | | - | | | this parameter needs to match the `&mut {integer}` type of `_a` - | | `_b` needs to match the type of this parameter + | ^^^^ - ----- ----- this parameter needs to match the `&mut {integer}` type of `_a` + | | | + | | `_b` needs to match the `&mut {integer}` type of this parameter | `_a` and `_b` all reference this parameter T error: aborting due to 1 previous error diff --git a/tests/ui/coercion/coerce-to-bang.stderr b/tests/ui/coercion/coerce-to-bang.stderr index 4c21eef5c2917..3c737358adc77 100644 --- a/tests/ui/coercion/coerce-to-bang.stderr +++ b/tests/ui/coercion/coerce-to-bang.stderr @@ -12,7 +12,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ -------- ---- -------- + | ^^^ ---- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:18:13 @@ -28,7 +28,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ -------- ---- -------- + | ^^^ ---- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:26:12 @@ -44,7 +44,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ -------- ---- -------- + | ^^^ ---- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:36:12 @@ -60,7 +60,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ -------- ---- -------- + | ^^^ ---- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:45:12 @@ -76,7 +76,7 @@ note: function defined here --> $DIR/coerce-to-bang.rs:3:4 | LL | fn foo(x: usize, y: !, z: usize) { } - | ^^^ -------- ---- -------- + | ^^^ ---- error[E0308]: mismatched types --> $DIR/coerce-to-bang.rs:50:21 diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr index 24c7a3cb4828a..76cdbcceac841 100644 --- a/tests/ui/fn/fn-item-type.stderr +++ b/tests/ui/fn/fn-item-type.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | eq(foo::, bar::); | -- --------- ^^^^^^^^^ expected fn item, found a different fn item | | | - | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter + | | expected all arguments to be this fn item type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -14,10 +14,9 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ - ---- ---- - | | | | - | | | this parameter needs to match the fn item type of `x` - | | `y` needs to match the type of this parameter + | ^^ - ---- ---- this parameter needs to match the fn item type of `x` + | | | + | | `y` needs to match the fn item type of this parameter | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` @@ -27,7 +26,7 @@ error[E0308]: mismatched types LL | eq(foo::, foo::); | -- --------- ^^^^^^^^^ expected `u8`, found `i8` | | | - | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter + | | expected all arguments to be this fn item type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -37,10 +36,9 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ - ---- ---- - | | | | - | | | this parameter needs to match the fn item type of `x` - | | `y` needs to match the type of this parameter + | ^^ - ---- ---- this parameter needs to match the fn item type of `x` + | | | + | | `y` needs to match the fn item type of this parameter | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` @@ -50,7 +48,7 @@ error[E0308]: mismatched types LL | eq(bar::, bar::>); | -- ------------- ^^^^^^^^^^^^^^ expected `String`, found `Vec` | | | - | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter + | | expected all arguments to be this fn item type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {bar::}` @@ -60,10 +58,9 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ - ---- ---- - | | | | - | | | this parameter needs to match the fn item type of `x` - | | `y` needs to match the type of this parameter + | ^^ - ---- ---- this parameter needs to match the fn item type of `x` + | | | + | | `y` needs to match the fn item type of this parameter | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize` @@ -73,7 +70,7 @@ error[E0308]: mismatched types LL | eq(::foo, ::foo); | -- ---------------- ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16` | | | - | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter + | | expected all arguments to be this fn item type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn() {::foo}` @@ -83,10 +80,9 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ - ---- ---- - | | | | - | | | this parameter needs to match the fn item type of `x` - | | `y` needs to match the type of this parameter + | ^^ - ---- ---- this parameter needs to match the fn item type of `x` + | | | + | | `y` needs to match the fn item type of this parameter | `x` and `y` all reference this parameter T = help: consider casting both fn items to fn pointers using `as fn()` @@ -96,7 +92,7 @@ error[E0308]: mismatched types LL | eq(foo::, bar:: as fn(isize) -> isize); | -- --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer | | | - | | expected argument `y` to be a fn item because that argument needs to match the type of this parameter + | | expected all arguments to be this fn item type because they need to match the type of this parameter | arguments to this function are incorrect | = note: expected fn item `fn(_) -> _ {foo::}` @@ -106,10 +102,9 @@ note: function defined here --> $DIR/fn-item-type.rs:11:4 | LL | fn eq(x: T, y: T) {} - | ^^ - ---- ---- - | | | | - | | | this parameter needs to match the fn item type of `x` - | | `y` needs to match the type of this parameter + | ^^ - ---- ---- this parameter needs to match the fn item type of `x` + | | | + | | `y` needs to match the fn item type of this parameter | `x` and `y` all reference this parameter T error: aborting due to 5 previous errors diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs index 9a38b948e8ea5..2bd10e762d9a0 100644 --- a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs @@ -9,4 +9,6 @@ fn main() { //~^ ERROR arguments to this function are incorrect foo_multi_generics("a", "b", "c", true, false, 32, 2.); //~^ ERROR arguments to this function are incorrect + foo_multi_same("a", 1, 2, "d", "e", 32); + //~^ ERROR arguments to this function are incorrect } diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr index a4f55ce06ac76..a845dfabe93b7 100644 --- a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr +++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr @@ -4,17 +4,16 @@ error[E0308]: mismatched types LL | foo(1, 2.); | --- - ^^ expected integer, found floating-point number | | | - | | expected argument `b` to be an integer because that argument needs to match the type of this parameter + | | expected all arguments to be this integer type because they need to match the type of this parameter | arguments to this function are incorrect | note: function defined here --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4 | LL | fn foo(a: T, b: T) {} - | ^^^ - ---- ---- - | | | | - | | | this parameter needs to match the integer type of `a` - | | `b` needs to match the type of this parameter + | ^^^ - ---- ---- this parameter needs to match the integer type of `a` + | | | + | | `b` needs to match the integer type of this parameter | `a` and `b` all reference this parameter T error[E0308]: arguments to this function are incorrect @@ -25,8 +24,8 @@ LL | foo_multi_same("a", "b", false, true, (), 32); | | | | | | | | | expected `&str`, found `bool` | | | expected `&str`, found `bool` - | | expected arguments `c`, `d` and `e` to be an `&str` because those arguments need to match the type of this parameter - | expected arguments `c`, `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need to match the type of this parameter + | | expected some other arguments to be an `&str` type to match the type of this parameter + | expected some other arguments to be an `&str` type to match the type of this parameter | note: function defined here --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4 @@ -37,8 +36,8 @@ LL | fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} | | | | | | this parameter needs to match the `&str` type of `a` and `b` | | | | | this parameter needs to match the `&str` type of `a` and `b` | | | | this parameter needs to match the `&str` type of `a` and `b` - | | | `c`, `d` and `e` needs to match the type of this parameter - | | `c`, `d` and `e` needs to match the type of this parameter + | | | `c`, `d` and `e` need to match the `&str` type of this parameter + | | `c`, `d` and `e` need to match the `&str` type of this parameter | `a`, `b`, `c`, `d` and `e` all reference this parameter T error[E0308]: arguments to this function are incorrect @@ -47,29 +46,52 @@ error[E0308]: arguments to this function are incorrect LL | foo_multi_generics("a", "b", "c", true, false, 32, 2.); | ^^^^^^^^^^^^^^^^^^ --- --- --- ---- ----- -- -- expected integer, found floating-point number | | | | | | | - | | | | | | expected argument `g` to be an integer because that argument needs to match the type of this parameter + | | | | | | expected some other arguments to be an integer type to match the type of this parameter | | | | | expected `&str`, found `bool` | | | | expected `&str`, found `bool` - | | | expected arguments `d` and `e` to be an `&str` because those arguments need to match the type of this parameter - | | expected arguments `d` and `e` to be an `&str` because the arguments `c`, `d` and `e` need to match the type of this parameter - | expected arguments `d` and `e` to be an `&str` because the arguments `b`, `c`, `d` and `e` need to match the type of this parameter + | | | expected some other arguments to be an `&str` type to match the type of this parameter + | | expected some other arguments to be an `&str` type to match the type of this parameter + | expected some other arguments to be an `&str` type to match the type of this parameter | note: function defined here --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4 | LL | fn foo_multi_generics(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {} - | ^^^^^^^^^^^^^^^^^^ - - ---- ---- ---- ---- ---- ---- ---- - | | | | | | | | | | - | | | | | | | | | this parameter needs to match the integer type of `f` - | | | | | | | | `g` needs to match the type of this parameter + | ^^^^^^^^^^^^^^^^^^ - - ---- ---- ---- ---- ---- ---- ---- this parameter needs to match the integer type of `f` + | | | | | | | | | + | | | | | | | | `g` needs to match the integer type of this parameter | | | | | | | this parameter needs to match the `&str` type of `a`, `b` and `c` | | | | | | this parameter needs to match the `&str` type of `a`, `b` and `c` - | | | | | `d` and `e` needs to match the type of this parameter - | | | | `d` and `e` needs to match the type of this parameter - | | | `d` and `e` needs to match the type of this parameter + | | | | | `d` and `e` need to match the `&str` type of this parameter + | | | | `d` and `e` need to match the `&str` type of this parameter + | | | `d` and `e` need to match the `&str` type of this parameter | | `a`, `b`, `c`, `d` and `e` all reference this parameter T | `f` and `g` all reference this parameter S -error: aborting due to 3 previous errors +error[E0308]: arguments to this function are incorrect + --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5 + | +LL | foo_multi_same("a", 1, 2, "d", "e", 32); + | ^^^^^^^^^^^^^^ --- - - --- --- expected some other arguments to be an `&str` type to match the type of this parameter + | | | | | + | | | | expected some other arguments to be an `&str` type to match the type of this parameter + | | | expected `&str`, found integer + | | expected `&str`, found integer + | expected some other arguments to be an `&str` type to match the type of this parameter + | +note: function defined here + --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4 + | +LL | fn foo_multi_same(a: T, b: T, c: T, d: T, e: T, f: i32) {} + | ^^^^^^^^^^^^^^ - ---- ---- ---- ---- ---- ------ + | | | | | | | + | | | | | | `b` and `c` need to match the `&str` type of this parameter + | | | | | `b` and `c` need to match the `&str` type of this parameter + | | | | this parameter needs to match the `&str` type of `a`, `d` and `e` + | | | this parameter needs to match the `&str` type of `a`, `d` and `e` + | | `b` and `c` need to match the `&str` type of this parameter + | `a`, `b`, `c`, `d` and `e` all reference this parameter T + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/never_type/issue-96335.stderr b/tests/ui/never_type/issue-96335.stderr index 13cdbe842c9dc..c3d80a425e057 100644 --- a/tests/ui/never_type/issue-96335.stderr +++ b/tests/ui/never_type/issue-96335.stderr @@ -21,7 +21,6 @@ LL | 0.....{loop{}1}; | | | | | expected integer, found `RangeTo<{integer}>` | arguments to this function are incorrect - | expected all arguments to be integer because they need to match the type of this parameter | = note: expected type `{integer}` found struct `RangeTo<{integer}>` diff --git a/tests/ui/parser/issues/issue-93282.stderr b/tests/ui/parser/issues/issue-93282.stderr index fc15865e1a729..c6140bb821e48 100644 --- a/tests/ui/parser/issues/issue-93282.stderr +++ b/tests/ui/parser/issues/issue-93282.stderr @@ -43,7 +43,7 @@ note: function defined here --> $DIR/issue-93282.rs:7:4 | LL | fn bar(a: usize, b: usize) -> usize { - | ^^^ -------- -------- + | ^^^ -------- error: aborting due to 4 previous errors diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index 1b9ad3a3f1675..f0dea66f6128d 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -77,7 +77,7 @@ note: function defined here --> $DIR/issue-34264.rs:3:4 | LL | fn bar(x, y: usize) {} - | ^^^ - -------- + | ^^^ -------- error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 diff --git a/tests/ui/tuple/add-tuple-within-arguments.stderr b/tests/ui/tuple/add-tuple-within-arguments.stderr index 8414a51bfd5e8..6849128eaddde 100644 --- a/tests/ui/tuple/add-tuple-within-arguments.stderr +++ b/tests/ui/tuple/add-tuple-within-arguments.stderr @@ -8,7 +8,7 @@ note: function defined here --> $DIR/add-tuple-within-arguments.rs:1:4 | LL | fn foo(s: &str, a: (i32, i32), s2: &str) {} - | ^^^ ------- ------------- -------- + | ^^^ ------------- help: wrap these arguments in parentheses to construct a tuple | LL | foo("hi", (1, 2), "hi"); @@ -28,7 +28,7 @@ note: function defined here --> $DIR/add-tuple-within-arguments.rs:3:4 | LL | fn bar(s: &str, a: (&str,), s2: &str) {} - | ^^^ ------- ---------- -------- + | ^^^ ---------- help: use a trailing comma to create a tuple with one element | LL | bar("hi", ("hi",), "hi"); diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index 63a98a55127a8..fbe6bfeebb149 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -74,7 +74,7 @@ note: function defined here --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4 | LL | fn function(x: T, y: bool) -> T { - | ^^^^^^^^ ---- ------- + | ^^^^^^^^ ---- help: change the type of the numeric literal from `u32` to `u16` | LL | let x: u16 = function(0u16, true); From 4498cd6a8da86e4d7a84953c891281c8c2dace26 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 00:07:42 -0400 Subject: [PATCH 03/18] extend extern tests to include FiveU16s As described in the code, this extends just beyond a 64bit reg, but isn't a round number, so it triggers some edge cases in the cast ABI. --- tests/auxiliary/rust_test_helpers.c | 24 +++++++++++++++ tests/ui/abi/extern/extern-pass-FiveU16s.rs | 30 +++++++++++++++++++ tests/ui/abi/extern/extern-return-FiveU16s.rs | 26 ++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/ui/abi/extern/extern-pass-FiveU16s.rs create mode 100644 tests/ui/abi/extern/extern-return-FiveU16s.rs diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c index 977ea487a9804..965df44c67608 100644 --- a/tests/auxiliary/rust_test_helpers.c +++ b/tests/auxiliary/rust_test_helpers.c @@ -118,6 +118,30 @@ rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) { return u; } +struct FiveU16s { + uint16_t one; + uint16_t two; + uint16_t three; + uint16_t four; + uint16_t five; +}; + +struct FiveU16s +rust_dbg_extern_return_FiveU16s() { + struct FiveU16s s; + s.one = 10; + s.two = 20; + s.three = 30; + s.four = 40; + s.five = 50; + return s; +} + +struct FiveU16s +rust_dbg_extern_identity_FiveU16s(struct FiveU16s u) { + return u; +} + struct ManyInts { int8_t arg1; int16_t arg2; diff --git a/tests/ui/abi/extern/extern-pass-FiveU16s.rs b/tests/ui/abi/extern/extern-pass-FiveU16s.rs new file mode 100644 index 0000000000000..5f1307beb28e6 --- /dev/null +++ b/tests/ui/abi/extern/extern-pass-FiveU16s.rs @@ -0,0 +1,30 @@ +//@ run-pass +#![allow(improper_ctypes)] + +// Test a foreign function that accepts and returns a struct by value. + +// FiveU16s in particular is interesting because it is larger than a single 64 bit or 32 bit +// register, which are used as cast destinations on some targets, but does not evenly divide those +// sizes, causing there to be padding in the last element. + +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct FiveU16s { + one: u16, + two: u16, + three: u16, + four: u16, + five: u16, +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_extern_identity_FiveU16s(v: FiveU16s) -> FiveU16s; +} + +pub fn main() { + unsafe { + let x = FiveU16s { one: 22, two: 23, three: 24, four: 25, five: 26 }; + let y = rust_dbg_extern_identity_FiveU16s(x); + assert_eq!(x, y); + } +} diff --git a/tests/ui/abi/extern/extern-return-FiveU16s.rs b/tests/ui/abi/extern/extern-return-FiveU16s.rs new file mode 100644 index 0000000000000..d8ae8b2661c5a --- /dev/null +++ b/tests/ui/abi/extern/extern-return-FiveU16s.rs @@ -0,0 +1,26 @@ +//@ run-pass +#![allow(improper_ctypes)] + +pub struct FiveU16s { + one: u16, + two: u16, + three: u16, + four: u16, + five: u16, +} + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_extern_return_FiveU16s() -> FiveU16s; +} + +pub fn main() { + unsafe { + let y = rust_dbg_extern_return_FiveU16s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + assert_eq!(y.three, 30); + assert_eq!(y.four, 40); + assert_eq!(y.five, 50); + } +} From 41c6fa812b0bed63e54c455134734452f9cee97c Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 00:11:54 -0400 Subject: [PATCH 04/18] sparc64: fix crash in ABI code for { f64, f32 } struct This would trigger a `Size::sub: 0 - 8 would result in negative size` abort, if `data.last_offset > offset`. This is almost hilariously easy to trigger (https://godbolt.org/z/8rbv57xET): ```rust #[repr(C)] pub struct DoubleFloat { f: f64, g: f32, } #[no_mangle] pub extern "C" fn foo(x: DoubleFloat) {} ``` Tests for this will be covered by the cast-target-abi.rs test added in a later commit. --- compiler/rustc_target/src/abi/call/sparc64.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index cbed5b4afc134..377fee0a2f514 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -35,12 +35,14 @@ where data.last_offset = data.last_offset + Reg::i32().size; } - for _ in 0..((offset - data.last_offset).bits() / 64) - .min((data.prefix.len() - data.prefix_index) as u64) - { - data.prefix[data.prefix_index] = Some(Reg::i64()); - data.prefix_index += 1; - data.last_offset = data.last_offset + Reg::i64().size; + if data.last_offset < offset { + for _ in 0..((offset - data.last_offset).bits() / 64) + .min((data.prefix.len() - data.prefix_index) as u64) + { + data.prefix[data.prefix_index] = Some(Reg::i64()); + data.prefix_index += 1; + data.last_offset = data.last_offset + Reg::i64().size; + } } if data.last_offset < offset { From 74ef47e90ca1466ea7f3dd8c3ec3738f05345809 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 00:14:20 -0400 Subject: [PATCH 05/18] make CastTarget::size and CastTarget::llvm_type consistent, remove special case that's not present in Clang Making the methods consistent doesn't require much justification. It's required for us to generate correct code. The special case was present near the end of `CastTarget::llvm_type`, and resulted in the final integer component of the ABI type being shrunk to the smallest integer that fits. You can see this in action here (https://godbolt.org/z/Pe73cr91d), where, for a struct with 5 u16 elements, rustc generates `{ i64, i16 }`, while Clang generates `[2 x i64]`. This special case was added a long time ago, when the function was originally written [1]. That commit consolidated logic from many backends, and in some of the code it deleted, sparc64 [2] and powerpc64 [3] had similar special cases. However, looking at Clang today, it doesn't have this special case for sparc64 (https://godbolt.org/z/YaafvYWdf) or powerpc64 (https://godbolt.org/z/5c3YePTje), so this change just removes it. [1]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-183c4dadf10704bd1f521b71f71d89bf755c9603a93f894d66c03bb1effc6021R231 [2]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-2d8f87ea6db6d7f0a6fbeb1d5549adc07e93331278d951a1e051a40f92914436L163-L166 [3]: https://github.com/rust-lang/rust/commit/f0636b61c7f84962a609e831760db9d77f4f5e14#diff-88af4a9df9ead503a5c7774a0455d270dea3ba60e9b0ec1ce550b4c53d3bce3bL172-L175 --- compiler/rustc_codegen_llvm/src/abi.rs | 52 +++++++++++------------ compiler/rustc_target/src/abi/call/mod.rs | 25 ++++++----- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index e5f5146fac8fb..1990634fc512a 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -16,13 +16,15 @@ pub use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc_middle::ty::Ty; use rustc_session::config; pub use rustc_target::abi::call::*; -use rustc_target::abi::{self, HasDataLayout, Int}; +use rustc_target::abi::{self, HasDataLayout, Int, Size}; pub use rustc_target::spec::abi::Abi; use rustc_target::spec::SanitizerSet; use libc::c_uint; use smallvec::SmallVec; +use std::cmp; + pub trait ArgAttributesExt { fn apply_attrs_to_llfn(&self, idx: AttributePlace, cx: &CodegenCx<'_, '_>, llfn: &Value); fn apply_attrs_to_callsite( @@ -130,42 +132,36 @@ impl LlvmType for Reg { impl LlvmType for CastTarget { fn llvm_type<'ll>(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type { let rest_ll_unit = self.rest.unit.llvm_type(cx); - let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { - (0, 0) + let rest_count = if self.rest.total == Size::ZERO { + 0 } else { - ( - self.rest.total.bytes() / self.rest.unit.size.bytes(), - self.rest.total.bytes() % self.rest.unit.size.bytes(), - ) + assert_ne!( + self.rest.unit.size, + Size::ZERO, + "total size {:?} cannot be divided into units of zero size", + self.rest.total + ); + if self.rest.total.bytes() % self.rest.unit.size.bytes() != 0 { + assert_eq!(self.rest.unit.kind, RegKind::Integer, "only int regs can be split"); + } + self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes()) }; + // Simplify to a single unit or an array if there's no prefix. + // This produces the same layout, but using a simpler type. if self.prefix.iter().all(|x| x.is_none()) { - // Simplify to a single unit when there is no prefix and size <= unit size - if self.rest.total <= self.rest.unit.size { + if rest_count == 1 { return rest_ll_unit; } - // Simplify to array when all chunks are the same size and type - if rem_bytes == 0 { - return cx.type_array(rest_ll_unit, rest_count); - } - } - - // Create list of fields in the main structure - let mut args: Vec<_> = self - .prefix - .iter() - .flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx))) - .chain((0..rest_count).map(|_| rest_ll_unit)) - .collect(); - - // Append final integer - if rem_bytes != 0 { - // Only integers can be really split further. - assert_eq!(self.rest.unit.kind, RegKind::Integer); - args.push(cx.type_ix(rem_bytes * 8)); + return cx.type_array(rest_ll_unit, rest_count); } + // Generate a struct type with the prefix and the "rest" arguments. + let prefix_args = + self.prefix.iter().flat_map(|option_reg| option_reg.map(|reg| reg.llvm_type(cx))); + let rest_args = (0..rest_count).map(|_| rest_ll_unit); + let args: Vec<_> = prefix_args.chain(rest_args).collect(); cx.type_struct(&args, false) } } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 486afc5f8f30a..643ba9f1cddcc 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -251,9 +251,9 @@ pub struct Uniform { /// The total size of the argument, which can be: /// * equal to `unit.size` (one scalar/vector), /// * a multiple of `unit.size` (an array of scalar/vectors), - /// * if `unit.kind` is `Integer`, the last element - /// can be shorter, i.e., `{ i64, i64, i32 }` for - /// 64-bit integers with a total size of 20 bytes. + /// * if `unit.kind` is `Integer`, the last element can be shorter, i.e., `{ i64, i64, i32 }` + /// for 64-bit integers with a total size of 20 bytes. When the argument is actually passed, + /// this size will be rounded up to the nearest multiple of `unit.size`. pub total: Size, } @@ -319,14 +319,17 @@ impl CastTarget { } pub fn size(&self, _cx: &C) -> Size { - let mut size = self.rest.total; - for i in 0..self.prefix.iter().count() { - match self.prefix[i] { - Some(v) => size += v.size, - None => {} - } - } - return size; + // Prefix arguments are passed in specific designated registers + let prefix_size = self + .prefix + .iter() + .filter_map(|x| x.map(|reg| reg.size)) + .fold(Size::ZERO, |acc, size| acc + size); + // Remaining arguments are passed in chunks of the unit size + let rest_size = + self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes()); + + prefix_size + rest_size } pub fn align(&self, cx: &C) -> Align { From 8841315d3e9aa02cb54d757cb5cd8131c263a893 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 00:22:35 -0400 Subject: [PATCH 06/18] make PassMode::Cast consistently copy between Rust/ABI representation Previously, we did this slightly incorrectly for return values, and didn't do it at all for arguments. --- compiler/rustc_codegen_llvm/src/abi.rs | 68 ++++++++------------- compiler/rustc_codegen_ssa/src/mir/block.rs | 32 +++++++++- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 1990634fc512a..d2828669d438f 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -211,47 +211,33 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } PassMode::Cast { cast, pad_i32: _ } => { - // FIXME(eddyb): Figure out when the simpler Store is safe, clang - // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. - let can_store_through_cast_ptr = false; - if can_store_through_cast_ptr { - bx.store(val, dst.llval, self.layout.align.abi); - } else { - // The actual return type is a struct, but the ABI - // adaptation code has cast it into some scalar type. The - // code that follows is the only reliable way I have - // found to do a transform like i64 -> {i32,i32}. - // Basically we dump the data onto the stack then memcpy it. - // - // Other approaches I tried: - // - Casting rust ret pointer to the foreign type and using Store - // is (a) unsafe if size of foreign type > size of rust type and - // (b) runs afoul of strict aliasing rules, yielding invalid - // assembly under -O (specifically, the store gets removed). - // - Truncating foreign type to correct integral type and then - // bitcasting to the struct type yields invalid cast errors. - - // We instead thus allocate some scratch space... - let scratch_size = cast.size(bx); - let scratch_align = cast.align(bx); - let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); - bx.lifetime_start(llscratch, scratch_size); - - // ... where we first store the value... - bx.store(val, llscratch, scratch_align); - - // ... and then memcpy it to the intended destination. - bx.memcpy( - dst.llval, - self.layout.align.abi, - llscratch, - scratch_align, - bx.const_usize(self.layout.size.bytes()), - MemFlags::empty(), - ); - - bx.lifetime_end(llscratch, scratch_size); - } + // The ABI mandates that the value is passed as a different struct representation. + // Spill and reload it from the stack to convert from the ABI representation to + // the Rust representation. + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + // Note that the ABI type may be either larger or smaller than the Rust type, + // due to the presence or absence of trailing padding. For example: + // - On some ABIs, the Rust layout { f64, f32, } may omit padding + // when passed by value, making it smaller. + // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes + // when passed by value, making it larger. + let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes()); + // Allocate some scratch space... + let llscratch = bx.alloca(cast.llvm_type(bx), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + // ...store the value... + bx.store(val, llscratch, scratch_align); + // ... and then memcpy it to the intended destination. + bx.memcpy( + dst.llval, + self.layout.align.abi, + llscratch, + scratch_align, + bx.const_usize(copy_bytes), + MemFlags::empty(), + ); + bx.lifetime_end(llscratch, scratch_size); } _ => { OperandRef::from_immediate_or_packed_pair(bx, val, self.layout).val.store(bx, dst); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 9bb2a52826585..333c03ce82377 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1471,9 +1471,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if let PassMode::Cast { cast: ty, .. } = &arg.mode { - let llty = bx.cast_backend_type(ty); - llval = bx.load(llty, llval, align.min(arg.layout.align.abi)); + if let PassMode::Cast { cast, pad_i32: _ } = &arg.mode { + // The ABI mandates that the value is passed as a different struct representation. + // Spill and reload it from the stack to convert from the Rust representation to + // the ABI representation. + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + // Note that the ABI type may be either larger or smaller than the Rust type, + // due to the presence or absence of trailing padding. For example: + // - On some ABIs, the Rust layout { f64, f32, } may omit padding + // when passed by value, making it smaller. + // - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes + // when passed by value, making it larger. + let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes()); + // Allocate some scratch space... + let llscratch = bx.alloca(bx.cast_backend_type(cast), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + // ...memcpy the value... + bx.memcpy( + llscratch, + scratch_align, + llval, + align, + bx.const_usize(copy_bytes), + MemFlags::empty(), + ); + // ...and then load it with the ABI type. + let cast_ty = bx.cast_backend_type(cast); + llval = bx.load(cast_ty, llscratch, scratch_align); + bx.lifetime_end(llscratch, scratch_size); } else { // We can't use `PlaceRef::load` here because the argument // may have a type we don't treat as immediate, but the ABI From 8d5fd94e6292b298e59a637d84fa16bed30d64d4 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 00:25:36 -0400 Subject: [PATCH 07/18] add tests for PassMode::Cast fixes Tests added in cast-target-abi.rs, covering the single element, array, and prefix cases in `CastTarget::llvm_type`, and the Rust-is-larger/smaller cases in the Rust<->ABI copying code. ffi-out-of-bounds-loads.rs was overhauled to be runnable on any platform. Its alignment also increases due to the removal of a `min` in the previous commit; this was probably an insufficient workaround for this issue or similar. The higher alignment is fine, since the alloca is actually aligned to 8 bytes, as the test checks now confirm. --- tests/codegen/cast-target-abi.rs | 269 ++++++++++++++++++ tests/codegen/cffi/ffi-out-of-bounds-loads.rs | 28 +- 2 files changed, 291 insertions(+), 6 deletions(-) create mode 100644 tests/codegen/cast-target-abi.rs diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs new file mode 100644 index 0000000000000..2d800d044726a --- /dev/null +++ b/tests/codegen/cast-target-abi.rs @@ -0,0 +1,269 @@ +// ignore-tidy-linelength +//@ revisions:aarch64 loongarch64 powerpc64 sparc64 +//@ compile-flags: -O -C no-prepopulate-passes + +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: arm +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc + +// Tests that arguments with `PassMode::Cast` are handled correctly. + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } + +// This struct will be passed as a single `i64` or `i32`. +// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`. +#[repr(C)] +pub struct TwoU16s { + a: u16, + b: u16, +} + +// This struct will be passed as `[2 x i64]`. +// This is larger than the Rust layout. +#[repr(C)] +pub struct FiveU16s { + a: u16, + b: u16, + c: u16, + d: u16, + e: u16, +} + +// This struct will be passed as `[2 x double]`. +// This is the same as the Rust layout. +#[repr(C)] +pub struct DoubleDouble { + f: f64, + g: f64, +} + +// On loongarch, this struct will be passed as `{ double, float }`. +// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, }`) +#[repr(C)] +pub struct DoubleFloat { + f: f64, + g: f32, +} + +extern "C" { + fn receives_twou16s(x: TwoU16s); + fn returns_twou16s() -> TwoU16s; + + fn receives_fiveu16s(x: FiveU16s); + fn returns_fiveu16s() -> FiveU16s; + + fn receives_doubledouble(x: DoubleDouble); + fn returns_doubledouble() -> DoubleDouble; + + fn receives_doublefloat(x: DoubleFloat); + fn returns_doublefloat() -> DoubleFloat; +} + +// CHECK-LABEL: @call_twou16s +#[no_mangle] +pub unsafe fn call_twou16s() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i32]], align [[ABI_ALIGN:4]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false) + // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = TwoU16s { a: 1, b: 2 }; + receives_twou16s(x); +} + +// CHECK-LABEL: @return_twou16s +#[no_mangle] +pub unsafe fn return_twou16s() -> TwoU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca %TwoU16s, align 2 + // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]]) + + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false) + returns_twou16s() +} + +// CHECK-LABEL: @call_fiveu16s +#[no_mangle] +pub unsafe fn call_fiveu16s() { + // CHECK: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca %FiveU16s, align 2 + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false) + // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]]) + let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 }; + receives_fiveu16s(x); +} + +// CHECK-LABEL: @return_fiveu16s +// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]]) +#[no_mangle] +pub unsafe fn return_fiveu16s() -> FiveU16s { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]]) + + + // The other targets copy the cast ABI type to the sret pointer. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false) + returns_fiveu16s() +} + +// CHECK-LABEL: @call_doubledouble +#[no_mangle] +pub unsafe fn call_doubledouble() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]] + + // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]]) + let x = DoubleDouble { f: 1., g: 2. }; + receives_doubledouble(x); +} + +// CHECK-LABEL: @return_doubledouble +#[no_mangle] +pub unsafe fn return_doubledouble() -> DoubleDouble { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca %DoubleDouble, align 8 + // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]]) + + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble() + // sparc64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + returns_doubledouble() +} + +// CHECK-LABEL: @call_doublefloat +#[no_mangle] +pub unsafe fn call_doublefloat() { + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]] + // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float, i32, i64 }]], align [[ABI_ALIGN:8]] + + // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) + // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) + + // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // CHECK: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + let x = DoubleFloat { f: 1., g: 2. }; + receives_doublefloat(x); +} + +// CHECK-LABEL: @return_doublefloat +#[no_mangle] +pub unsafe fn return_doublefloat() -> DoubleFloat { + // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. + + // powerpc64: [[RETVAL:%.+]] = alloca %DoubleFloat, align 8 + // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]]) + + + // The other targets copy the cast ABI type to an alloca. + + // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] + // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]] + // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float, i32, i64 }]], align [[ABI_ALIGN:8]] + + // aarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + // sparc64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + + // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat() + // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat() + // sparc64: [[ABI_VALUE:%.+]] = call inreg [[ABI_TYPE]] @returns_doublefloat() + + // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) + // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) + returns_doublefloat() +} diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index 7eda6cf4d576e..8b32e902b3f55 100644 --- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs @@ -1,8 +1,21 @@ +//@ revisions: linux apple +//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes + +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 +//@[apple] compile-flags: --target x86_64-apple-darwin +//@[apple] needs-llvm-components: x86 + // Regression test for #29988 -//@ compile-flags: -C no-prepopulate-passes -//@ only-x86_64 -//@ ignore-windows +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } #[repr(C)] struct S { @@ -15,11 +28,14 @@ extern "C" { fn foo(s: S); } -fn main() { +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { let s = S { f1: 1, f2: 2, f3: 3 }; unsafe { - // CHECK: load { i64, i32 }, {{.*}}, align 4 - // CHECK: call void @foo({ i64, i32 } {{.*}}) + // CHECK: [[ALLOCA:%.+]] = alloca { i64, i32 }, align 8 + // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8 + // CHECK: call void @foo({ i64, i32 } [[LOAD]]) foo(s); } } From 6577aefc6f3863607b0d90d836d594a1887a0d90 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 13:33:59 -0400 Subject: [PATCH 08/18] Revert "sparc64: fix crash in ABI code for { f64, f32 } struct" This reverts commit 41c6fa812b0bed63e54c455134734452f9cee97c. --- compiler/rustc_target/src/abi/call/sparc64.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index 377fee0a2f514..cbed5b4afc134 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -35,14 +35,12 @@ where data.last_offset = data.last_offset + Reg::i32().size; } - if data.last_offset < offset { - for _ in 0..((offset - data.last_offset).bits() / 64) - .min((data.prefix.len() - data.prefix_index) as u64) - { - data.prefix[data.prefix_index] = Some(Reg::i64()); - data.prefix_index += 1; - data.last_offset = data.last_offset + Reg::i64().size; - } + for _ in 0..((offset - data.last_offset).bits() / 64) + .min((data.prefix.len() - data.prefix_index) as u64) + { + data.prefix[data.prefix_index] = Some(Reg::i64()); + data.prefix_index += 1; + data.last_offset = data.last_offset + Reg::i64().size; } if data.last_offset < offset { From dec81ac223aeda234e72de0eb70443153ef67e96 Mon Sep 17 00:00:00 2001 From: Erik Desjardins Date: Sun, 17 Mar 2024 13:40:01 -0400 Subject: [PATCH 09/18] disable crashing test on sparc --- tests/codegen/cast-target-abi.rs | 35 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index 2d800d044726a..e6024f03425f4 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -67,7 +67,10 @@ extern "C" { fn receives_doubledouble(x: DoubleDouble); fn returns_doubledouble() -> DoubleDouble; + // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) + #[cfg(not(target_arch = "sparc64"))] fn receives_doublefloat(x: DoubleFloat); + #[cfg(not(target_arch = "sparc64"))] fn returns_doublefloat() -> DoubleFloat; } @@ -214,28 +217,41 @@ pub unsafe fn return_doubledouble() -> DoubleDouble { returns_doubledouble() } -// CHECK-LABEL: @call_doublefloat +// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @call_doublefloat +// loongarch64-LABEL: @call_doublefloat +// powerpc64-LABEL: @call_doublefloat #[no_mangle] pub unsafe fn call_doublefloat() { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]] // powerpc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float, i32, i64 }]], align [[ABI_ALIGN:8]] - // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + // aarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] + // powerpc64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false) // powerpc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false) - // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // CHECK: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // aarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + // powerpc64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] + + // aarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) + // powerpc64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]]) let x = DoubleFloat { f: 1., g: 2. }; receives_doublefloat(x); } -// CHECK-LABEL: @return_doublefloat +// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620) +#[cfg(not(target_arch = "sparc64"))] +// aarch64-LABEL: @return_doublefloat +// loongarch64-LABEL: @return_doublefloat +// powerpc64-LABEL: @return_doublefloat #[no_mangle] pub unsafe fn return_doublefloat() -> DoubleFloat { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. @@ -248,22 +264,17 @@ pub unsafe fn return_doublefloat() -> DoubleFloat { // aarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]] // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]] - // sparc64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float, i32, i64 }]], align [[ABI_ALIGN:8]] // aarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] - // sparc64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]] // aarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat() // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat() - // sparc64: [[ABI_VALUE:%.+]] = call inreg [[ABI_TYPE]] @returns_doublefloat() // aarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] - // sparc64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]] // aarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false) - // sparc64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false) returns_doublefloat() } From 4c0aea0d47d9e01642ee59a8620795558f098408 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 31 Mar 2024 14:58:17 -0300 Subject: [PATCH 10/18] Move some tests --- src/tools/tidy/src/issues.txt | 18 ++++++++---------- src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/{issues => closures}/issue-1460.rs | 0 .../ui/{issues => closures}/issue-1460.stderr | 0 tests/ui/{issues => fn}/issue-1451.rs | 0 tests/ui/{issues => fn}/issue-1900.rs | 0 tests/ui/{issues => fn}/issue-1900.stderr | 0 tests/ui/issues/issue-1476.rs | 3 --- tests/ui/issues/issue-1476.stderr | 9 --------- tests/ui/issues/issue-1696.rs | 8 -------- tests/ui/{issues => loops}/issue-1962.fixed | 0 tests/ui/{issues => loops}/issue-1962.rs | 0 tests/ui/{issues => loops}/issue-1962.stderr | 0 tests/ui/{issues => loops}/issue-1974.rs | 0 .../{issues => mismatched_types}/issue-1362.rs | 0 .../issue-1362.stderr | 0 .../issue-1448-2.rs | 0 .../issue-1448-2.stderr | 0 tests/ui/{issues => static}/issue-1660.rs | 0 19 files changed, 9 insertions(+), 31 deletions(-) rename tests/ui/{issues => closures}/issue-1460.rs (100%) rename tests/ui/{issues => closures}/issue-1460.stderr (100%) rename tests/ui/{issues => fn}/issue-1451.rs (100%) rename tests/ui/{issues => fn}/issue-1900.rs (100%) rename tests/ui/{issues => fn}/issue-1900.stderr (100%) delete mode 100644 tests/ui/issues/issue-1476.rs delete mode 100644 tests/ui/issues/issue-1476.stderr delete mode 100644 tests/ui/issues/issue-1696.rs rename tests/ui/{issues => loops}/issue-1962.fixed (100%) rename tests/ui/{issues => loops}/issue-1962.rs (100%) rename tests/ui/{issues => loops}/issue-1962.stderr (100%) rename tests/ui/{issues => loops}/issue-1974.rs (100%) rename tests/ui/{issues => mismatched_types}/issue-1362.rs (100%) rename tests/ui/{issues => mismatched_types}/issue-1362.stderr (100%) rename tests/ui/{issues => mismatched_types}/issue-1448-2.rs (100%) rename tests/ui/{issues => mismatched_types}/issue-1448-2.stderr (100%) rename tests/ui/{issues => static}/issue-1660.rs (100%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index f6b1d45ee94ef..6e8452493421d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -434,6 +434,7 @@ "ui/closures/issue-111932.rs", "ui/closures/issue-113087.rs", "ui/closures/issue-11873.rs", +"ui/closures/issue-1460.rs", "ui/closures/issue-23012-supertrait-signature-inference.rs", "ui/closures/issue-25439.rs", "ui/closures/issue-41366.rs", @@ -1007,6 +1008,8 @@ "ui/fmt/issue-86085.rs", "ui/fmt/issue-89173.rs", "ui/fmt/issue-91556.rs", +"ui/fn/issue-1451.rs", +"ui/fn/issue-1900.rs", "ui/fn/issue-3044.rs", "ui/fn/issue-3099.rs", "ui/fn/issue-3904.rs", @@ -1550,7 +1553,6 @@ "ui/issues/issue-13497-2.rs", "ui/issues/issue-13497.rs", "ui/issues/issue-13507-2.rs", -"ui/issues/issue-1362.rs", "ui/issues/issue-13620.rs", "ui/issues/issue-13665.rs", "ui/issues/issue-13703.rs", @@ -1576,12 +1578,8 @@ "ui/issues/issue-14399.rs", "ui/issues/issue-14421.rs", "ui/issues/issue-14422.rs", -"ui/issues/issue-1448-2.rs", -"ui/issues/issue-1451.rs", "ui/issues/issue-14541.rs", -"ui/issues/issue-1460.rs", "ui/issues/issue-14721.rs", -"ui/issues/issue-1476.rs", "ui/issues/issue-14821.rs", "ui/issues/issue-14845.rs", "ui/issues/issue-14853.rs", @@ -1631,7 +1629,6 @@ "ui/issues/issue-16560.rs", "ui/issues/issue-16562.rs", "ui/issues/issue-16596.rs", -"ui/issues/issue-1660.rs", "ui/issues/issue-16643.rs", "ui/issues/issue-16648.rs", "ui/issues/issue-16668.rs", @@ -1645,7 +1642,6 @@ "ui/issues/issue-16819.rs", "ui/issues/issue-16922-rpass.rs", "ui/issues/issue-16939.rs", -"ui/issues/issue-1696.rs", "ui/issues/issue-16966.rs", "ui/issues/issue-16994.rs", "ui/issues/issue-17001.rs", @@ -1725,7 +1721,6 @@ "ui/issues/issue-18952.rs", "ui/issues/issue-18959.rs", "ui/issues/issue-18988.rs", -"ui/issues/issue-1900.rs", "ui/issues/issue-19001.rs", "ui/issues/issue-19037.rs", "ui/issues/issue-19086.rs", @@ -1753,12 +1748,10 @@ "ui/issues/issue-19482.rs", "ui/issues/issue-19499.rs", "ui/issues/issue-19601.rs", -"ui/issues/issue-1962.rs", "ui/issues/issue-19631.rs", "ui/issues/issue-19632.rs", "ui/issues/issue-19692.rs", "ui/issues/issue-19734.rs", -"ui/issues/issue-1974.rs", "ui/issues/issue-19811-escape-unicode.rs", "ui/issues/issue-19850.rs", "ui/issues/issue-19922.rs", @@ -2856,6 +2849,8 @@ "ui/lint/unused/issue-92751.rs", "ui/lint/unused/issue-96606.rs", "ui/lint/use-redundant/issue-92904.rs", +"ui/loops/issue-1962.rs", +"ui/loops/issue-1974.rs", "ui/loops/issue-43162.rs", "ui/loops/issue-50576.rs", "ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs", @@ -3045,6 +3040,8 @@ "ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs", "ui/mismatched_types/issue-118510.rs", "ui/mismatched_types/issue-13033.rs", +"ui/mismatched_types/issue-1362.rs", +"ui/mismatched_types/issue-1448-2.rs", "ui/mismatched_types/issue-19109.rs", "ui/mismatched_types/issue-26480.rs", "ui/mismatched_types/issue-35030.rs", @@ -3860,6 +3857,7 @@ "ui/stability-attribute/issue-28388-3.rs", "ui/stability-attribute/issue-99286-stable-intrinsics.rs", "ui/static/auxiliary/issue_24843.rs", +"ui/static/issue-1660.rs", "ui/static/issue-18118-2.rs", "ui/static/issue-18118.rs", "ui/static/issue-24446.rs", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index fe27964981e06..454811c5fbbfd 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1750; +const ISSUES_ENTRY_LIMIT: usize = 1733; const ROOT_ENTRY_LIMIT: usize = 860; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ diff --git a/tests/ui/issues/issue-1460.rs b/tests/ui/closures/issue-1460.rs similarity index 100% rename from tests/ui/issues/issue-1460.rs rename to tests/ui/closures/issue-1460.rs diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/closures/issue-1460.stderr similarity index 100% rename from tests/ui/issues/issue-1460.stderr rename to tests/ui/closures/issue-1460.stderr diff --git a/tests/ui/issues/issue-1451.rs b/tests/ui/fn/issue-1451.rs similarity index 100% rename from tests/ui/issues/issue-1451.rs rename to tests/ui/fn/issue-1451.rs diff --git a/tests/ui/issues/issue-1900.rs b/tests/ui/fn/issue-1900.rs similarity index 100% rename from tests/ui/issues/issue-1900.rs rename to tests/ui/fn/issue-1900.rs diff --git a/tests/ui/issues/issue-1900.stderr b/tests/ui/fn/issue-1900.stderr similarity index 100% rename from tests/ui/issues/issue-1900.stderr rename to tests/ui/fn/issue-1900.stderr diff --git a/tests/ui/issues/issue-1476.rs b/tests/ui/issues/issue-1476.rs deleted file mode 100644 index 138570a93c498..0000000000000 --- a/tests/ui/issues/issue-1476.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("{}", x); //~ ERROR cannot find value `x` in this scope -} diff --git a/tests/ui/issues/issue-1476.stderr b/tests/ui/issues/issue-1476.stderr deleted file mode 100644 index e30dbfd205b87..0000000000000 --- a/tests/ui/issues/issue-1476.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-1476.rs:2:20 - | -LL | println!("{}", x); - | ^ not found in this scope - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/issues/issue-1696.rs b/tests/ui/issues/issue-1696.rs deleted file mode 100644 index 08002ad3c58b1..0000000000000 --- a/tests/ui/issues/issue-1696.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -use std::collections::HashMap; - -pub fn main() { - let mut m = HashMap::new(); - m.insert(b"foo".to_vec(), b"bar".to_vec()); - println!("{:?}", m); -} diff --git a/tests/ui/issues/issue-1962.fixed b/tests/ui/loops/issue-1962.fixed similarity index 100% rename from tests/ui/issues/issue-1962.fixed rename to tests/ui/loops/issue-1962.fixed diff --git a/tests/ui/issues/issue-1962.rs b/tests/ui/loops/issue-1962.rs similarity index 100% rename from tests/ui/issues/issue-1962.rs rename to tests/ui/loops/issue-1962.rs diff --git a/tests/ui/issues/issue-1962.stderr b/tests/ui/loops/issue-1962.stderr similarity index 100% rename from tests/ui/issues/issue-1962.stderr rename to tests/ui/loops/issue-1962.stderr diff --git a/tests/ui/issues/issue-1974.rs b/tests/ui/loops/issue-1974.rs similarity index 100% rename from tests/ui/issues/issue-1974.rs rename to tests/ui/loops/issue-1974.rs diff --git a/tests/ui/issues/issue-1362.rs b/tests/ui/mismatched_types/issue-1362.rs similarity index 100% rename from tests/ui/issues/issue-1362.rs rename to tests/ui/mismatched_types/issue-1362.rs diff --git a/tests/ui/issues/issue-1362.stderr b/tests/ui/mismatched_types/issue-1362.stderr similarity index 100% rename from tests/ui/issues/issue-1362.stderr rename to tests/ui/mismatched_types/issue-1362.stderr diff --git a/tests/ui/issues/issue-1448-2.rs b/tests/ui/mismatched_types/issue-1448-2.rs similarity index 100% rename from tests/ui/issues/issue-1448-2.rs rename to tests/ui/mismatched_types/issue-1448-2.rs diff --git a/tests/ui/issues/issue-1448-2.stderr b/tests/ui/mismatched_types/issue-1448-2.stderr similarity index 100% rename from tests/ui/issues/issue-1448-2.stderr rename to tests/ui/mismatched_types/issue-1448-2.stderr diff --git a/tests/ui/issues/issue-1660.rs b/tests/ui/static/issue-1660.rs similarity index 100% rename from tests/ui/issues/issue-1660.rs rename to tests/ui/static/issue-1660.rs From 8cf2c0dc67d880e54be03ebb08f7f960c21bb794 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 29 Mar 2024 19:40:54 +0100 Subject: [PATCH 11/18] Improve debugging experience --- compiler/rustc_pattern_analysis/src/constructor.rs | 1 - compiler/rustc_pattern_analysis/src/rustc.rs | 2 -- compiler/rustc_pattern_analysis/src/usefulness.rs | 14 ++++++++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 1c9a9ab0f7206..49b2e510642a7 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -974,7 +974,6 @@ impl ConstructorSet { /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation /// and its invariants. - #[instrument(level = "debug", skip(self, ctors), ret)] pub fn split<'a>( &self, ctors: impl Iterator> + Clone, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index b0f506c3651a7..467f09e4c2944 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -186,7 +186,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns the types of the fields for a given constructor. The result must have a length of /// `ctor.arity()`. - #[instrument(level = "trace", skip(self))] pub(crate) fn ctor_sub_tys<'a>( &'a self, ctor: &'a Constructor<'p, 'tcx>, @@ -283,7 +282,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Creates a set that represents all the constructors of `ty`. /// /// See [`crate::constructor`] for considerations of emptiness. - #[instrument(level = "debug", skip(self), ret)] pub fn ctors_for_ty( &self, ty: RevealedTy<'tcx>, diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index cdc03eaeb37c1..1b5dd8478d645 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -871,12 +871,14 @@ impl PlaceInfo { where Cx: 'a, { + debug!(?self.ty); if self.private_uninhabited { // Skip the whole column return Ok((smallvec![Constructor::PrivateUninhabited], vec![])); } let ctors_for_ty = cx.ctors_for_ty(&self.ty)?; + debug!(?ctors_for_ty); // We treat match scrutinees of type `!` or `EmptyEnum` differently. let is_toplevel_exception = @@ -895,6 +897,7 @@ impl PlaceInfo { // Analyze the constructors present in this column. let mut split_set = ctors_for_ty.split(ctors); + debug!(?split_set); let all_missing = split_set.present.is_empty(); // Build the set of constructors we will specialize with. It must cover the whole type, so @@ -1254,7 +1257,7 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> { /// + true + [Second(true)] + /// + false + [_] + /// + _ + [_, _, tail @ ..] + -/// | ✓ | ? | // column validity +/// | ✓ | ? | // validity /// ``` impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1285,7 +1288,7 @@ impl<'p, Cx: PatCx> fmt::Debug for Matrix<'p, Cx> { write!(f, " {sep}")?; } if is_validity_row { - write!(f, " // column validity")?; + write!(f, " // validity")?; } write!(f, "\n")?; } @@ -1617,7 +1620,6 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( }; // Analyze the constructors present in this column. - debug!("ty: {:?}", place.ty); let ctors = matrix.heads().map(|p| p.ctor()); let (split_ctors, missing_ctors) = place.split_column_ctors(mcx.tycx, ctors)?; @@ -1669,7 +1671,10 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: PatCx>( for row in matrix.rows() { if row.useful { if let PatOrWild::Pat(pat) = row.head() { - mcx.useful_subpatterns.insert(pat.uid); + let newly_useful = mcx.useful_subpatterns.insert(pat.uid); + if newly_useful { + debug!("newly useful: {pat:?}"); + } } } } @@ -1768,6 +1773,7 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>( .map(|arm| { debug!(?arm); let usefulness = collect_pattern_usefulness(&cx.useful_subpatterns, arm.pat); + debug!(?usefulness); (arm, usefulness) }) .collect(); From db9b4eac480525d7af188a8360371d3cef84de98 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 31 Mar 2024 23:57:47 +0200 Subject: [PATCH 12/18] Add tests --- tests/ui/pattern/usefulness/unions.rs | 34 +++++++++++++++++++++++ tests/ui/pattern/usefulness/unions.stderr | 34 +++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/ui/pattern/usefulness/unions.rs create mode 100644 tests/ui/pattern/usefulness/unions.stderr diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs new file mode 100644 index 0000000000000..32fe9b4c04d1a --- /dev/null +++ b/tests/ui/pattern/usefulness/unions.rs @@ -0,0 +1,34 @@ +fn main() { + #[derive(Copy, Clone)] + union U8AsBool { + n: u8, + b: bool, + } + + let x = U8AsBool { n: 1 }; + unsafe { + match x { + // exhaustive + U8AsBool { n: 2 } => {} + U8AsBool { b: true } => {} + U8AsBool { b: false } => {} + } + match x { + // exhaustive + U8AsBool { b: true } => {} + U8AsBool { n: 0 } => {} + U8AsBool { n: 1.. } => {} + } + match x { + //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8, b: false }` not covered + U8AsBool { b: true } => {} + U8AsBool { n: 1.. } => {} + } + match (x, true) { + //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered + (U8AsBool { b: true }, true) => {} + (U8AsBool { b: false }, true) => {} + (U8AsBool { n: 1.. }, true) => {} + } + } +} diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr new file mode 100644 index 0000000000000..d824a031cd3f0 --- /dev/null +++ b/tests/ui/pattern/usefulness/unions.stderr @@ -0,0 +1,34 @@ +error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8, b: false }` not covered + --> $DIR/unions.rs:22:15 + | +LL | match x { + | ^ pattern `U8AsBool { n: 0_u8, b: false }` not covered + | +note: `U8AsBool` defined here + --> $DIR/unions.rs:3:11 + | +LL | union U8AsBool { + | ^^^^^^^^ + = note: the matched value is of type `U8AsBool` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ U8AsBool { n: 1.. } => {}, +LL + U8AsBool { n: 0_u8, b: false } => todo!() + | + +error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered + --> $DIR/unions.rs:27:15 + | +LL | match (x, true) { + | ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered + | + = note: the matched value is of type `(U8AsBool, bool)` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (U8AsBool { n: 1.. }, true) => {}, +LL + (U8AsBool { n: 0_u8, b: false }, false) | (U8AsBool { n: 0_u8, b: true }, false) => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. From 27704c7f9eea6e8ffaedac04ae1c932da7422fb7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 31 Mar 2024 23:57:53 +0200 Subject: [PATCH 13/18] Fix union handling in exhaustiveness --- compiler/rustc_middle/src/thir.rs | 3 +- .../rustc_pattern_analysis/src/constructor.rs | 28 +++++++++++++++ .../rustc_pattern_analysis/src/usefulness.rs | 35 +++++++++++++++---- tests/ui/pattern/usefulness/unions.rs | 5 +-- tests/ui/pattern/usefulness/unions.stderr | 18 +++++----- 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 05f6fbbbfa33b..5a0cf524e2614 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1120,7 +1120,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> { printed += 1; } - if printed < variant.fields.len() { + let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); + if printed < variant.fields.len() && (!is_union || printed == 0) { write!(f, "{}..", start_or_comma())?; } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 49b2e510642a7..44f09b66bf6c6 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -140,6 +140,34 @@ //! [`ConstructorSet::split`]. The invariants of [`SplitConstructorSet`] are also of interest. //! //! +//! ## Unions +//! +//! Unions allow us to match a value via several overlapping representations at the same time. For +//! example, the following is exhaustive because when seeing the value as a boolean we handled all +//! possible cases (other cases such as `n == 3` would trigger UB). +//! +//! ```rust +//! # fn main() { +//! union U8AsBool { +//! n: u8, +//! b: bool, +//! } +//! let x = U8AsBool { n: 1 }; +//! unsafe { +//! match x { +//! U8AsBool { n: 2 } => {} +//! U8AsBool { b: true } => {} +//! U8AsBool { b: false } => {} +//! } +//! } +//! # } +//! ``` +//! +//! Pattern-matching has no knowledge that e.g. `false as u8 == 0`, so the values we consider in the +//! algorithm look like `U8AsBool { b: true, n: 2 }`. In other words, for the most part a union is +//! treated like a struct with the same fields. The difference lies in how we construct witnesses of +//! non-exhaustiveness. +//! //! //! ## Opaque patterns //! diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 1b5dd8478d645..7246039174aff 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1384,12 +1384,35 @@ impl WitnessStack { /// pats: [(false, "foo"), _, true] /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true] /// ``` - fn apply_constructor(&mut self, pcx: &PlaceCtxt<'_, Cx>, ctor: &Constructor) { + fn apply_constructor( + mut self, + pcx: &PlaceCtxt<'_, Cx>, + ctor: &Constructor, + ) -> SmallVec<[Self; 1]> { let len = self.0.len(); let arity = pcx.ctor_arity(ctor); - let fields = self.0.drain((len - arity)..).rev().collect(); - let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty.clone()); - self.0.push(pat); + let fields: Vec<_> = self.0.drain((len - arity)..).rev().collect(); + if matches!(ctor, Constructor::UnionField) + && fields.iter().filter(|p| !matches!(p.ctor(), Constructor::Wildcard)).count() >= 2 + { + // Convert a `Union { a: p, b: q }` witness into `Union { a: p }` and `Union { b: q }`. + // First add `Union { .. }` to `self`. + self.0.push(WitnessPat::wild_from_ctor(pcx.cx, ctor.clone(), pcx.ty.clone())); + fields + .into_iter() + .enumerate() + .filter(|(_, p)| !matches!(p.ctor(), Constructor::Wildcard)) + .map(|(i, p)| { + let mut ret = self.clone(); + // Fill the `i`th field of the union with `p`. + ret.0.last_mut().unwrap().fields[i] = p; + ret + }) + .collect() + } else { + self.0.push(WitnessPat::new(ctor.clone(), fields, pcx.ty.clone())); + smallvec![self] + } } } @@ -1462,8 +1485,8 @@ impl WitnessMatrix { *self = ret; } else { // Any other constructor we unspecialize as expected. - for witness in self.0.iter_mut() { - witness.apply_constructor(pcx, ctor) + for witness in std::mem::take(&mut self.0) { + self.0.extend(witness.apply_constructor(pcx, ctor)); } } } diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs index 32fe9b4c04d1a..80a7f36a09a26 100644 --- a/tests/ui/pattern/usefulness/unions.rs +++ b/tests/ui/pattern/usefulness/unions.rs @@ -20,12 +20,13 @@ fn main() { U8AsBool { n: 1.. } => {} } match x { - //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8, b: false }` not covered + //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered U8AsBool { b: true } => {} U8AsBool { n: 1.. } => {} } + // Our approach can report duplicate witnesses sometimes. match (x, true) { - //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered + //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered (U8AsBool { b: true }, true) => {} (U8AsBool { b: false }, true) => {} (U8AsBool { n: 1.. }, true) => {} diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr index d824a031cd3f0..4b397dc25db8b 100644 --- a/tests/ui/pattern/usefulness/unions.stderr +++ b/tests/ui/pattern/usefulness/unions.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8, b: false }` not covered +error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered --> $DIR/unions.rs:22:15 | LL | match x { - | ^ pattern `U8AsBool { n: 0_u8, b: false }` not covered + | ^ patterns `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered | note: `U8AsBool` defined here --> $DIR/unions.rs:3:11 @@ -10,23 +10,23 @@ note: `U8AsBool` defined here LL | union U8AsBool { | ^^^^^^^^ = note: the matched value is of type `U8AsBool` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ U8AsBool { n: 1.. } => {}, -LL + U8AsBool { n: 0_u8, b: false } => todo!() +LL + U8AsBool { n: 0_u8 } | U8AsBool { b: false } => todo!() | -error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered - --> $DIR/unions.rs:27:15 +error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered + --> $DIR/unions.rs:28:15 | LL | match (x, true) { - | ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8, b: false }, false)` and `(U8AsBool { n: 0_u8, b: true }, false)` not covered + | ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered | = note: the matched value is of type `(U8AsBool, bool)` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | LL ~ (U8AsBool { n: 1.. }, true) => {}, -LL + (U8AsBool { n: 0_u8, b: false }, false) | (U8AsBool { n: 0_u8, b: true }, false) => todo!() +LL + _ => todo!() | error: aborting due to 2 previous errors From ab821aed0c048964a86285d534ca93203d61af89 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Apr 2024 19:30:32 -0400 Subject: [PATCH 14/18] Fix precedence of postfix match --- compiler/rustc_ast/src/ast.rs | 3 ++- compiler/rustc_ast/src/util/parser.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index aba94f4d817d7..ccbcd5091b47e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1276,7 +1276,8 @@ impl Expr { ExprKind::While(..) => ExprPrecedence::While, ExprKind::ForLoop { .. } => ExprPrecedence::ForLoop, ExprKind::Loop(..) => ExprPrecedence::Loop, - ExprKind::Match(..) => ExprPrecedence::Match, + ExprKind::Match(_, _, MatchKind::Prefix) => ExprPrecedence::Match, + ExprKind::Match(_, _, MatchKind::Postfix) => ExprPrecedence::PostfixMatch, ExprKind::Closure(..) => ExprPrecedence::Closure, ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::TryBlock(..) => ExprPrecedence::TryBlock, diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 13768c1201791..544db992f4f2b 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -281,6 +281,7 @@ pub enum ExprPrecedence { ForLoop, Loop, Match, + PostfixMatch, ConstBlock, Block, TryBlock, @@ -334,7 +335,8 @@ impl ExprPrecedence { | ExprPrecedence::InlineAsm | ExprPrecedence::Mac | ExprPrecedence::FormatArgs - | ExprPrecedence::OffsetOf => PREC_POSTFIX, + | ExprPrecedence::OffsetOf + | ExprPrecedence::PostfixMatch => PREC_POSTFIX, // Never need parens ExprPrecedence::Array From 4cb5643bd4b9a66f8c8b8fee2505a7f09b8ed10a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Apr 2024 19:40:12 -0400 Subject: [PATCH 15/18] Fix contains_exterior_struct_lit --- compiler/rustc_ast/src/util/parser.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 544db992f4f2b..373c0ebcc5cba 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -392,7 +392,8 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { | ast::ExprKind::Cast(x, _) | ast::ExprKind::Type(x, _) | ast::ExprKind::Field(x, _) - | ast::ExprKind::Index(x, _, _) => { + | ast::ExprKind::Index(x, _, _) + | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(x) } From 989660c3e6efc1c5eb2e822f68863df7d06cbcb4 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 3 Apr 2024 15:17:00 +0200 Subject: [PATCH 16/18] rename `expose_addr` to `expose_provenance` --- compiler/rustc_borrowck/src/type_check/mod.rs | 4 ++-- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- .../rustc_codegen_cranelift/src/intrinsics/simd.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_const_eval/src/interpret/cast.rs | 6 +++--- .../src/transform/check_consts/check.rs | 2 +- .../rustc_const_eval/src/transform/validate.rs | 2 +- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 2 +- compiler/rustc_hir_typeck/messages.ftl | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 6 +++--- compiler/rustc_middle/src/mir/statement.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 4 ++-- compiler/rustc_middle/src/ty/cast.rs | 2 +- compiler/rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_smir/src/rustc_smir/convert/mir.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- compiler/stable_mir/src/mir/body.rs | 1 + library/core/src/fmt/mod.rs | 4 ++-- library/core/src/intrinsics/simd.rs | 6 ++++++ library/core/src/ptr/const_ptr.rs | 10 +++++----- library/core/src/ptr/mod.rs | 14 +++++++------- library/core/src/ptr/mut_ptr.rs | 11 +++++------ .../crates/core_simd/src/simd/ptr/const_ptr.rs | 10 +++++----- .../crates/core_simd/src/simd/ptr/mut_ptr.rs | 10 +++++----- .../crates/core_simd/tests/pointers.rs | 6 +++--- library/std/src/sys/pal/hermit/thread.rs | 2 +- library/std/src/sys/pal/itron/thread.rs | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- src/tools/miri/src/alloc_addresses/mod.rs | 4 ++-- src/tools/miri/src/shims/intrinsics/simd.rs | 6 +++--- .../miri/tests/fail/provenance/ptr_invalid.rs | 2 +- .../tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- src/tools/miri/tests/pass/portable-simd-ptrs.rs | 2 +- src/tools/miri/tests/pass/ptr_int_from_exposed.rs | 10 +++++----- .../miri/tests/pass/stacked-borrows/int-to-ptr.rs | 4 ++-- .../pass/stacked-borrows/unknown-bottom-gc.rs | 2 +- ...er_expose_provenance.main.GVN.panic-abort.diff} | 2 +- ...r_expose_provenance.main.GVN.panic-unwind.diff} | 2 +- ...ose_address.rs => pointer_expose_provenance.rs} | 4 ++-- .../mir-opt/const_prop/reify_fn_ptr.main.GVN.diff | 2 +- tests/mir-opt/const_prop/reify_fn_ptr.rs | 2 +- ...ointer_to_int.DeadStoreElimination-initial.diff | 4 ++-- .../dead-store-elimination/provenance_soundness.rs | 4 ++-- ...ovenance.SimplifyLocals-before-const-prop.diff} | 8 ++++---- tests/mir-opt/simplify_locals.rs | 6 +++--- .../lint/lint-strict-provenance-lossy-casts.stderr | 8 ++++---- tests/ui/simd/intrinsic/ptr-cast.rs | 4 ++-- 49 files changed, 105 insertions(+), 99 deletions(-) rename tests/mir-opt/const_prop/{pointer_expose_address.main.GVN.panic-abort.diff => pointer_expose_provenance.main.GVN.panic-abort.diff} (93%) rename tests/mir-opt/const_prop/{pointer_expose_address.main.GVN.panic-unwind.diff => pointer_expose_provenance.main.GVN.panic-unwind.diff} (93%) rename tests/mir-opt/const_prop/{pointer_expose_address.rs => pointer_expose_provenance.rs} (72%) rename tests/mir-opt/{simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff => simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff} (54%) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6405364c30c14..71b54a761a2be 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2261,7 +2261,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::PointerExposeAddress => { + CastKind::PointerExposeProvenance => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); @@ -2271,7 +2271,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!( self, rvalue, - "Invalid PointerExposeAddress cast {:?} -> {:?}", + "Invalid PointerExposeProvenance cast {:?} -> {:?}", ty_from, ty ) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 249c16898ce6e..0aa2bae8f78b1 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -649,7 +649,7 @@ fn codegen_stmt<'tcx>( | CastKind::IntToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::PointerExposeAddress + | CastKind::PointerExposeProvenance | CastKind::PointerWithExposedProvenance, ref operand, to_ty, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 783ad5d1dd1fc..67f9d83106294 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -965,7 +965,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - sym::simd_expose_addr | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => { + sym::simd_expose_provenance | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => { intrinsic_args!(fx, args => (arg); intrinsic); ret.write_cvalue_transmute(fx, arg); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e4ec7974e9000..dc52dd156b7e7 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -2111,7 +2111,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(args[0].immediate()); } - if name == sym::simd_expose_addr { + if name == sym::simd_expose_provenance { let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn); require!( in_len == out_len, diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6f7b98a262d55..4d746c89f1fc3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -405,7 +405,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { - mir::CastKind::PointerExposeAddress => { + mir::CastKind::PointerExposeProvenance => { assert!(bx.cx().is_backend_immediate(cast)); let llptr = operand.immediate(); let llcast_ty = bx.cx().immediate_backend_type(cast); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index e0d45f1fe1146..9447d18fe8c93 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -34,9 +34,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.unsize_into(src, cast_layout, dest)?; } - CastKind::PointerExposeAddress => { + CastKind::PointerExposeProvenance => { let src = self.read_immediate(src)?; - let res = self.pointer_expose_address_cast(&src, cast_layout)?; + let res = self.pointer_expose_provenance_cast(&src, cast_layout)?; self.write_immediate(*res, dest)?; } @@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - pub fn pointer_expose_address_cast( + pub fn pointer_expose_provenance_cast( &mut self, src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx>, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index b6dcc33414739..543996c86baca 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -544,7 +544,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Unsizing is implemented for CTFE. } - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { self.check_op(ops::RawPtrToIntCast); } Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => { diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index e1e98ebc1e9ae..a499e4b980fc3 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1077,7 +1077,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } // FIXME: Add Checks for these CastKind::PointerWithExposedProvenance - | CastKind::PointerExposeAddress + | CastKind::PointerExposeProvenance | CastKind::PointerCoercion(_) => {} CastKind::IntToInt | CastKind::IntToFloat => { let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool(); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 00a0fca490722..cea6f3c1dba2d 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -627,7 +627,7 @@ pub fn check_intrinsic_type( sym::simd_cast | sym::simd_as | sym::simd_cast_ptr - | sym::simd_expose_addr + | sym::simd_expose_provenance | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), sym::simd_bitmask => (2, 0, vec![param(0)], param(1)), sym::simd_select | sym::simd_select_bitmask => { diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index fbdc3d1adb81a..1d51101c94031 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -91,7 +91,7 @@ hir_typeck_lossy_provenance_int2ptr = hir_typeck_lossy_provenance_ptr2int = under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}` .suggestion = use `.addr()` to obtain the address of a pointer - .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead hir_typeck_method_call_on_unknown_raw_pointee = cannot call a method on a raw pointer with an unknown pointee type diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 7e9d35ca6c1a6..30522628f4680 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2797,17 +2797,17 @@ declare_lint! { /// Since this cast is lossy, it is considered good style to use the /// [`ptr::addr`] method instead, which has a similar effect, but doesn't /// "expose" the pointer provenance. This improves optimisation potential. - /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information + /// See the docs of [`ptr::addr`] and [`ptr::expose_provenance`] for more information /// about exposing pointer provenance. /// /// If your code can't comply with strict provenance and needs to expose - /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch, + /// the provenance, then there is [`ptr::expose_provenance`] as an escape hatch, /// which preserves the behaviour of `as usize` casts while being explicit /// about the semantics. /// /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 /// [`ptr::addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.addr - /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_addr + /// [`ptr::expose_provenance`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.expose_provenance pub LOSSY_PROVENANCE_CASTS, Allow, "a lossy pointer to integer cast is used", diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 947764307e498..069c8019cb2c8 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -409,7 +409,7 @@ impl<'tcx> Rvalue<'tcx> { // Pointer to int casts may be side-effects due to exposing the provenance. // While the model is undecided, we should be conservative. See // - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, + Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1f6165babdfb0..7ce48036a684b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1309,8 +1309,8 @@ pub enum Rvalue<'tcx> { pub enum CastKind { /// An exposing pointer to address cast. A cast between a pointer and an integer type, or /// between a function pointer and an integer type. - /// See the docs on `expose_addr` for more details. - PointerExposeAddress, + /// See the docs on `expose_provenance` for more details. + PointerExposeProvenance, /// An address-to-pointer cast that picks up an exposed provenance. /// See the docs on `with_exposed_provenance` for more details. PointerWithExposedProvenance, diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index 9bdc679d4e5b3..c9fd20bc1126a 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -83,7 +83,7 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin let cast = CastTy::from_ty(cast_ty); let cast_kind = match (from, cast) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { - mir::CastKind::PointerExposeAddress + mir::CastKind::PointerExposeProvenance } (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance, (_, Some(CastTy::DynStar)) => mir::CastKind::DynStar, diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index d64cb9b12b2bd..a9d4b860b7ad8 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -434,7 +434,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), // ptr-to-int casts are not possible in consts and thus not promotable - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable), + Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => return Err(Unpromotable), // all other casts including int-to-ptr casts are fine, they just use the integer value // at pointer type. diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index b60ee7649b24a..93bad88262555 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -985,7 +985,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t let locals = local_decls_for_sig(&sig, span); let source_info = SourceInfo::outermost(span); - // FIXME: use `expose_addr` once we figure out whether function pointers have meaningful provenance. + // FIXME: use `expose_provenance` once we figure out whether function pointers have meaningful provenance. let rvalue = Rvalue::Cast( CastKind::FnPtrToPtr, Operand::Move(Place::from(Local::new(1))), diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 9d91032c1d2c7..c9f6661259022 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -267,7 +267,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use rustc_middle::mir::CastKind::*; match self { - PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress, + PointerExposeProvenance => stable_mir::mir::CastKind::PointerExposeAddress, PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance, PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)), DynStar => stable_mir::mir::CastKind::DynStar, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b1d4a63812f42..a13c9c9b2784d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1659,7 +1659,7 @@ symbols! { simd_cttz, simd_div, simd_eq, - simd_expose_addr, + simd_expose_provenance, simd_extract, simd_fabs, simd_fcos, diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 0d866f27dadf7..8f77a19fc0e50 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -971,6 +971,7 @@ pub enum PointerCoercion { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum CastKind { + // FIXME(smir-rename): rename this to PointerExposeProvenance PointerExposeAddress, PointerWithExposedProvenance, PointerCoercion(PointerCoercion), diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e880d5758ec0a..287f6c23c899f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2438,8 +2438,8 @@ impl Display for char { #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for *const T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - // Cast is needed here because `.expose_addr()` requires `T: Sized`. - pointer_fmt_inner((*self as *const ()).expose_addr(), f) + // Cast is needed here because `.expose_provenance()` requires `T: Sized`. + pointer_fmt_inner((*self as *const ()).expose_provenance(), f) } } diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 614b4b589d37c..eeff4ec609a30 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -540,6 +540,10 @@ extern "rust-intrinsic" { /// `T` must be a vector of pointers. /// /// `U` must be a vector of `usize` with the same length as `T`. + #[cfg(not(bootstrap))] + #[rustc_nounwind] + pub fn simd_expose_provenance(ptr: T) -> U; + #[cfg(bootstrap)] #[rustc_nounwind] pub fn simd_expose_addr(ptr: T) -> U; @@ -660,5 +664,7 @@ extern "rust-intrinsic" { pub fn simd_flog(a: T) -> T; } +#[cfg(bootstrap)] +pub use simd_expose_addr as simd_expose_provenance; #[cfg(bootstrap)] pub use simd_from_exposed_addr as simd_with_exposed_provenance; diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e5713ee89df95..01db050e666f2 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -136,7 +136,7 @@ impl *const T { #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[deprecated( since = "1.67.0", - note = "replaced by the `expose_addr` method, or update your code \ + note = "replaced by the `expose_provenance` method, or update your code \ to follow the strict provenance rules using its APIs" )] #[inline(always)] @@ -187,7 +187,7 @@ impl *const T { /// /// If using those APIs is not possible because there is no way to preserve a pointer with the /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts - /// or [`expose_addr`][pointer::expose_addr] and [`with_exposed_provenance`][with_exposed_provenance] + /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance] /// instead. However, note that this makes your code less portable and less amenable to tools /// that check for compliance with the Rust memory model. /// @@ -210,8 +210,8 @@ impl *const T { unsafe { mem::transmute(self.cast::<()>()) } } - /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future - /// use in [`with_exposed_provenance`][]. + /// Exposes the "provenance" part of the pointer for future use in + /// [`with_exposed_provenance`][] and returns the "address" portion. /// /// This is equivalent to `self as usize`, which semantically discards *provenance* and /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit @@ -238,7 +238,7 @@ impl *const T { #[must_use] #[inline(always)] #[unstable(feature = "exposed_provenance", issue = "95228")] - pub fn expose_addr(self) -> usize { + pub fn expose_provenance(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. self.cast::<()>() as usize } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 28df2b04c88c6..f12ab3d50cdd4 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -340,8 +340,8 @@ //! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance. //! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI]. //! -//! Exposed Provenance is provided by the [`expose_addr`] and [`with_exposed_provenance`] methods, which -//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like +//! Exposed Provenance is provided by the [`expose_provenance`] and [`with_exposed_provenance`] methods, +//! which are meant to replace `as` casts between pointers and integers. [`expose_provenance`] is a lot like //! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed' //! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but //! is not materialized in actual executions, except in tools like [Miri].) [`with_exposed_provenance`] @@ -355,9 +355,9 @@ //! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will //! be used, the program has undefined behavior. //! -//! Using [`expose_addr`] or [`with_exposed_provenance`] (or the `as` casts) means that code is +//! Using [`expose_provenance`] or [`with_exposed_provenance`] (or the `as` casts) means that code is //! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to -//! determine how far one can get in Rust without the use of [`expose_addr`] and +//! determine how far one can get in Rust without the use of [`expose_provenance`] and //! [`with_exposed_provenance`], and to encourage code to be written with Strict Provenance APIs only. //! Maximizing the amount of such code is a major win for avoiding specification complexity and to //! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the @@ -374,7 +374,7 @@ //! [`map_addr`]: pointer::map_addr //! [`addr`]: pointer::addr //! [`ptr::dangling`]: core::ptr::dangling -//! [`expose_addr`]: pointer::expose_addr +//! [`expose_provenance`]: pointer::expose_provenance //! [`with_exposed_provenance`]: with_exposed_provenance //! [Miri]: https://github.com/rust-lang/miri //! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/ @@ -663,7 +663,7 @@ pub const fn dangling_mut() -> *mut T { /// /// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the /// returned pointer is that of *any* pointer that was previously exposed by passing it to -/// [`expose_addr`][pointer::expose_addr], or a `ptr as usize` cast. In addition, memory which is +/// [`expose_provenance`][pointer::expose_provenance], or a `ptr as usize` cast. In addition, memory which is /// outside the control of the Rust abstract machine (MMIO registers, for example) is always /// considered to be exposed, so long as this memory is disjoint from memory that will be used by /// the abstract machine such as the stack, heap, and statics. @@ -711,7 +711,7 @@ where /// /// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the /// returned pointer is that of *any* pointer that was previously passed to -/// [`expose_addr`][pointer::expose_addr] or a `ptr as usize` cast. If there is no previously +/// [`expose_provenance`][pointer::expose_provenance] or a `ptr as usize` cast. If there is no previously /// 'exposed' provenance that justifies the way this pointer will be used, the program has undefined /// behavior. Note that there is no algorithm that decides which provenance will be used. You can /// think of this as "guessing" the right provenance, and the guess will be "maximally in your diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 042658fa35f81..41e5ba6745827 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -142,7 +142,7 @@ impl *mut T { #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[deprecated( since = "1.67.0", - note = "replaced by the `expose_addr` method, or update your code \ + note = "replaced by the `expose_provenance` method, or update your code \ to follow the strict provenance rules using its APIs" )] #[inline(always)] @@ -194,7 +194,7 @@ impl *mut T { /// /// If using those APIs is not possible because there is no way to preserve a pointer with the /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts - /// or [`expose_addr`][pointer::expose_addr] and [`with_exposed_provenance`][with_exposed_provenance] + /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance] /// instead. However, note that this makes your code less portable and less amenable to tools /// that check for compliance with the Rust memory model. /// @@ -217,8 +217,8 @@ impl *mut T { unsafe { mem::transmute(self.cast::<()>()) } } - /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future - /// use in [`with_exposed_provenance`][]. + /// Exposes the "provenance" part of the pointer for future use in + /// [`with_exposed_provenance`][] and returns the "address" portion. /// /// This is equivalent to `self as usize`, which semantically discards *provenance* and /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit @@ -242,10 +242,9 @@ impl *mut T { /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance]. /// /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut - #[must_use] #[inline(always)] #[unstable(feature = "exposed_provenance", issue = "95228")] - pub fn expose_addr(self) -> usize { + pub fn expose_provenance(self) -> usize { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. self.cast::<()>() as usize } diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index 4d2fe999ca6fe..0f1719206c9ce 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -50,9 +50,9 @@ pub trait SimdConstPtr: Copy + Sealed { /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; - /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use - /// in [`Self::with_exposed_provenance`]. - fn expose_addr(self) -> Self::Usize; + /// Exposes the "provenance" part of the pointer for future use in + /// [`Self::with_exposed_provenance`] and returns the "address" portion. + fn expose_provenance(self) -> Self::Usize; /// Convert an address back to a pointer, picking up a previously "exposed" provenance. /// @@ -131,9 +131,9 @@ where } #[inline] - fn expose_addr(self) -> Self::Usize { + fn expose_provenance(self) -> Self::Usize { // Safety: `self` is a pointer vector - unsafe { core::intrinsics::simd::simd_expose_addr(self) } + unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } #[inline] diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index b3437b9c49966..7ba996d149c0c 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -47,9 +47,9 @@ pub trait SimdMutPtr: Copy + Sealed { /// Equivalent to calling [`pointer::with_addr`] on each element. fn with_addr(self, addr: Self::Usize) -> Self; - /// Gets the "address" portion of the pointer, and "exposes" the provenance part for future use - /// in [`Self::with_exposed_provenance`]. - fn expose_addr(self) -> Self::Usize; + /// Exposes the "provenance" part of the pointer for future use in + /// [`Self::with_exposed_provenance`] and returns the "address" portion. + fn expose_provenance(self) -> Self::Usize; /// Convert an address back to a pointer, picking up a previously "exposed" provenance. /// @@ -128,9 +128,9 @@ where } #[inline] - fn expose_addr(self) -> Self::Usize { + fn expose_provenance(self) -> Self::Usize { // Safety: `self` is a pointer vector - unsafe { core::intrinsics::simd::simd_expose_addr(self) } + unsafe { core::intrinsics::simd::simd_expose_provenance(self) } } #[inline] diff --git a/library/portable-simd/crates/core_simd/tests/pointers.rs b/library/portable-simd/crates/core_simd/tests/pointers.rs index 5984fdae2f9b4..90bfc5d5fd6a5 100644 --- a/library/portable-simd/crates/core_simd/tests/pointers.rs +++ b/library/portable-simd/crates/core_simd/tests/pointers.rs @@ -32,10 +32,10 @@ macro_rules! common_tests { ); } - fn expose_addr() { + fn expose_provenance() { test_helpers::test_unary_elementwise( - &Simd::<*$constness u32, LANES>::expose_addr, - &<*$constness u32>::expose_addr, + &Simd::<*$constness u32, LANES>::expose_provenance, + &<*$constness u32>::expose_provenance, &|_| true, ); } diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index 62c76a74cd4dc..40f88e33d4ad3 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -29,7 +29,7 @@ impl Thread { let p = Box::into_raw(Box::new(p)); let tid = abi::spawn2( thread_start, - p.expose_addr(), + p.expose_provenance(), abi::Priority::into(abi::NORMAL_PRIO), stack, core_id, diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 1c66bd79ce4fb..047513a67927a 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -181,7 +181,7 @@ impl Thread { abi::acre_tsk(&abi::T_CTSK { // Activate this task immediately tskatr: abi::TA_ACT, - exinf: p_inner.as_ptr().expose_addr() as abi::EXINF, + exinf: p_inner.as_ptr().expose_provenance() as abi::EXINF, // The entry point task: Some(trampoline), // Inherit the calling task's base priority diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 12b0800599700..325c9bee05782 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -149,7 +149,7 @@ fn check_rvalue<'tcx>( Err((span, "unsizing casts are not allowed in const fn".into())) } }, - Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::DynStar, _, _) => { diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 6b8e1510a6bf7..fec39ec2b8e31 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -18,8 +18,8 @@ use reuse_pool::ReusePool; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ProvenanceMode { - /// We support `expose_addr`/`with_exposed_provenance` via "wildcard" provenance. - /// However, we want on `with_exposed_provenance` to alert the user of the precision loss. + /// We support `expose_provenance`/`with_exposed_provenance` via "wildcard" provenance. + /// However, we warn on `with_exposed_provenance` to alert the user of the precision loss. Default, /// Like `Default`, but without the warning. Permissive, diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index 9d268f09edb57..a2fc4f0f761af 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?; this.write_int(res, &dest)?; } - "cast" | "as" | "cast_ptr" | "expose_addr" | "with_exposed_provenance" => { + "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => { let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -524,7 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let unsafe_cast = intrinsic_name == "cast"; let safe_cast = intrinsic_name == "as"; let ptr_cast = intrinsic_name == "cast_ptr"; - let expose_cast = intrinsic_name == "expose_addr"; + let expose_cast = intrinsic_name == "expose_provenance"; let from_exposed_cast = intrinsic_name == "with_exposed_provenance"; for i in 0..dest_len { @@ -557,7 +557,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.ptr_to_ptr(&op, dest.layout)?, // Ptr/Int casts (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast => - this.pointer_expose_address_cast(&op, dest.layout)?, + this.pointer_expose_provenance_cast(&op, dest.layout)?, (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast => this.pointer_with_exposed_provenance_cast(&op, dest.layout)?, // Error otherwise diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs index 730859684a0ce..512473cd89450 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs @@ -4,6 +4,6 @@ fn main() { let x = 42; let xptr = &x as *const i32; - let xptr_invalid = std::ptr::without_provenance::(xptr.expose_addr()); + let xptr_invalid = std::ptr::without_provenance::(xptr.expose_provenance()); let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer } diff --git a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs index aa05649d550c7..608ab71891942 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -6,7 +6,7 @@ fn main() { let mut x = 0; let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic - let addr = (&x as *const i32).expose_addr(); + let addr = (&x as *const i32).expose_provenance(); let ptr = std::ptr::with_exposed_provenance_mut::(addr); unsafe { *ptr = 0 }; //~ ERROR: /write access using .* no exposed tags have suitable permission in the borrow stack/ } diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs index 3b2d221bd8ea9..096ec78da1a0e 100644 --- a/src/tools/miri/tests/pass/portable-simd-ptrs.rs +++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs @@ -7,6 +7,6 @@ use std::simd::prelude::*; fn main() { // Pointer casts let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast(); - let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr(); + let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_provenance(); let _ptrs = Simd::<*const i32, 4>::with_exposed_provenance(addrs); } diff --git a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs index 8555de986f067..5690d7865bbc3 100644 --- a/src/tools/miri/tests/pass/ptr_int_from_exposed.rs +++ b/src/tools/miri/tests/pass/ptr_int_from_exposed.rs @@ -10,7 +10,7 @@ fn ptr_roundtrip_out_of_bounds() { let x: i32 = 3; let x_ptr = &x as *const i32; - let x_usize = x_ptr.wrapping_offset(128).expose_addr(); + let x_usize = x_ptr.wrapping_offset(128).expose_provenance(); let ptr = ptr::with_exposed_provenance::(x_usize).wrapping_offset(-128); assert_eq!(unsafe { *ptr }, 3); @@ -24,8 +24,8 @@ fn ptr_roundtrip_confusion() { let x_ptr = &x as *const i32; let y_ptr = &y as *const i32; - let x_usize = x_ptr.expose_addr(); - let y_usize = y_ptr.expose_addr(); + let x_usize = x_ptr.expose_provenance(); + let y_usize = y_ptr.expose_provenance(); let ptr = ptr::with_exposed_provenance::(y_usize); let ptr = ptr.with_addr(x_usize); @@ -37,7 +37,7 @@ fn ptr_roundtrip_imperfect() { let x: u8 = 3; let x_ptr = &x as *const u8; - let x_usize = x_ptr.expose_addr() + 128; + let x_usize = x_ptr.expose_provenance() + 128; let ptr = ptr::with_exposed_provenance::(x_usize).wrapping_offset(-128); assert_eq!(unsafe { *ptr }, 3); @@ -48,7 +48,7 @@ fn ptr_roundtrip_null() { let x = &42; let x_ptr = x as *const i32; let x_null_ptr = x_ptr.with_addr(0); // addr 0, but still the provenance of x - let null = x_null_ptr.expose_addr(); + let null = x_null_ptr.expose_provenance(); assert_eq!(null, 0); let x_null_ptr_copy = ptr::with_exposed_provenance::(null); // just a roundtrip, so has provenance of x (angelically) diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs index 5622bf186545b..c89d79b42e31e 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs @@ -17,7 +17,7 @@ fn example(variant: bool) { unsafe { fn not_so_innocent(x: &mut u32) -> usize { let x_raw4 = x as *mut u32; - x_raw4.expose_addr() + x_raw4.expose_provenance() } let mut c = 42u32; @@ -26,7 +26,7 @@ fn example(variant: bool) { // stack: [..., Unique(1)] let x_raw2 = x_unique1 as *mut u32; - let x_raw2_addr = x_raw2.expose_addr(); + let x_raw2_addr = x_raw2.expose_provenance(); // stack: [..., Unique(1), SharedRW(2)] let x_unique3 = &mut *x_raw2; diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs index 6e177a6e4abb3..55356814a1a03 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs @@ -9,7 +9,7 @@ fn main() { // Expose the allocation and use the exposed pointer, creating an unknown bottom unsafe { - let p: *mut u8 = ptr::with_exposed_provenance::(ptr.expose_addr()) as *mut u8; + let p: *mut u8 = ptr::with_exposed_provenance::(ptr.expose_provenance()) as *mut u8; *p = 1; } diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff similarity index 93% rename from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff rename to tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff index 596eb1a9966d3..79a95b618d17f 100644 --- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff @@ -19,7 +19,7 @@ StorageLive(_3); _3 = const main::FOO; _2 = &raw const (*_3); - _1 = move _2 as usize (PointerExposeAddress); + _1 = move _2 as usize (PointerExposeProvenance); StorageDead(_2); StorageDead(_3); StorageLive(_4); diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff similarity index 93% rename from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff rename to tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff index 995f281ecf54d..9d1bcd92fef21 100644 --- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff @@ -19,7 +19,7 @@ StorageLive(_3); _3 = const main::FOO; _2 = &raw const (*_3); - _1 = move _2 as usize (PointerExposeAddress); + _1 = move _2 as usize (PointerExposeProvenance); StorageDead(_2); StorageDead(_3); StorageLive(_4); diff --git a/tests/mir-opt/const_prop/pointer_expose_address.rs b/tests/mir-opt/const_prop/pointer_expose_provenance.rs similarity index 72% rename from tests/mir-opt/const_prop/pointer_expose_address.rs rename to tests/mir-opt/const_prop/pointer_expose_provenance.rs index a6b4f8857c376..840a4d65f3d79 100644 --- a/tests/mir-opt/const_prop/pointer_expose_address.rs +++ b/tests/mir-opt/const_prop/pointer_expose_provenance.rs @@ -4,12 +4,12 @@ #[inline(never)] fn read(_: usize) { } -// EMIT_MIR pointer_expose_address.main.GVN.diff +// EMIT_MIR pointer_expose_provenance.main.GVN.diff fn main() { // CHECK-LABEL: fn main( // CHECK: [[ptr:_.*]] = const main::FOO; // CHECK: [[ref:_.*]] = &raw const (*[[ptr]]); - // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeAddress); + // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeProvenance); // CHECK: = read([[x]]) const FOO: &i32 = &1; let x = FOO as *const i32 as usize; diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff index 2f76e74a3f878..e5786bcf701ef 100644 --- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff +++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff @@ -14,7 +14,7 @@ StorageLive(_2); StorageLive(_3); _3 = main as fn() (PointerCoercion(ReifyFnPointer)); - _2 = move _3 as usize (PointerExposeAddress); + _2 = move _3 as usize (PointerExposeProvenance); StorageDead(_3); _1 = move _2 as *const fn() (PointerWithExposedProvenance); StorageDead(_2); diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs index 4e897d2276803..55dca24f3d2e9 100644 --- a/tests/mir-opt/const_prop/reify_fn_ptr.rs +++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs @@ -4,7 +4,7 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer)); - // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress); + // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance); // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance); let _ = main as usize as *const fn(); } diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff index 9b0dc6b6af670..56d5c24ae1dc4 100644 --- a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff +++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff @@ -19,12 +19,12 @@ StorageLive(_2); StorageLive(_3); _3 = _1; - _2 = move _3 as usize (PointerExposeAddress); + _2 = move _3 as usize (PointerExposeProvenance); StorageDead(_3); StorageLive(_4); StorageLive(_5); _5 = _1; - _4 = move _5 as isize (PointerExposeAddress); + _4 = move _5 as isize (PointerExposeProvenance); StorageDead(_5); _0 = const (); StorageDead(_4); diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs index 96268cd957efa..20517a00489a5 100644 --- a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs +++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs @@ -5,8 +5,8 @@ // EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff fn pointer_to_int(p: *mut i32) { // CHECK-LABEL: fn pointer_to_int( - // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeAddress); - // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeAddress); + // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeProvenance); + // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeProvenance); let _x = p as usize; let _y = p as isize; } diff --git a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff similarity index 54% rename from tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff rename to tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff index 9ebee3df62c66..cc5c642407e9c 100644 --- a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff +++ b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff @@ -1,7 +1,7 @@ -- // MIR for `expose_addr` before SimplifyLocals-before-const-prop -+ // MIR for `expose_addr` after SimplifyLocals-before-const-prop +- // MIR for `expose_provenance` before SimplifyLocals-before-const-prop ++ // MIR for `expose_provenance` after SimplifyLocals-before-const-prop - fn expose_addr(_1: *const usize) -> () { + fn expose_provenance(_1: *const usize) -> () { debug p => _1; let mut _0: (); let _2: usize; @@ -11,7 +11,7 @@ StorageLive(_2); StorageLive(_3); _3 = _1; - _2 = move _3 as usize (PointerExposeAddress); + _2 = move _3 as usize (PointerExposeProvenance); StorageDead(_3); StorageDead(_2); _0 = const (); diff --git a/tests/mir-opt/simplify_locals.rs b/tests/mir-opt/simplify_locals.rs index f95e9185f4481..756679e77e396 100644 --- a/tests/mir-opt/simplify_locals.rs +++ b/tests/mir-opt/simplify_locals.rs @@ -63,8 +63,8 @@ fn t4() -> u32 { unsafe { X + 1 } } -// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff -fn expose_addr(p: *const usize) { +// EMIT_MIR simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff +fn expose_provenance(p: *const usize) { // Used pointer to address cast. Has a side effect of exposing the provenance. p as usize; } @@ -78,5 +78,5 @@ fn main() { t2(); t3(); t4(); - expose_addr(&0); + expose_provenance(&0); } diff --git a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr index aa151fe2d214e..390028b349e5f 100644 --- a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr +++ b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr @@ -4,7 +4,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons LL | let addr: usize = &x as *const u8 as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead note: the lint level is defined here --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9 | @@ -21,7 +21,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons LL | let addr_32bit = &x as *const u8 as u32; | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead help: use `.addr()` to obtain the address of a pointer | LL | let addr_32bit = (&x as *const u8).addr() as u32; @@ -35,7 +35,7 @@ LL | let ptr_addr = ptr as usize; | | | help: use `.addr()` to obtain the address of a pointer: `.addr()` | - = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26 @@ -45,7 +45,7 @@ LL | let ptr_addr_32bit = ptr as u32; | | | help: use `.addr()` to obtain the address of a pointer: `.addr() as u32` | - = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead error: aborting due to 4 previous errors diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs index 628203462414a..0490734b48ac5 100644 --- a/tests/ui/simd/intrinsic/ptr-cast.rs +++ b/tests/ui/simd/intrinsic/ptr-cast.rs @@ -4,7 +4,7 @@ extern "rust-intrinsic" { fn simd_cast_ptr(x: T) -> U; - fn simd_expose_addr(x: T) -> U; + fn simd_expose_provenance(x: T) -> U; fn simd_with_exposed_provenance(x: T) -> U; } @@ -22,7 +22,7 @@ fn main() { // change constness and type let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs); - let exposed_addr: V = simd_expose_addr(const_ptrs); + let exposed_addr: V = simd_expose_provenance(const_ptrs); let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr); From b40ea03f8a9a94c294679b9f261b86ded120454f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Apr 2024 17:49:59 +0300 Subject: [PATCH 17/18] rustc_index: Add a `ZERO` constant to index types It is commonly used. --- compiler/rustc_ast_lowering/src/index.rs | 4 ++-- compiler/rustc_ast_lowering/src/item.rs | 4 ++-- compiler/rustc_ast_lowering/src/lib.rs | 8 ++++---- compiler/rustc_borrowck/src/borrow_set.rs | 2 +- .../src/intrinsics/llvm_x86.rs | 2 +- compiler/rustc_codegen_cranelift/src/vtable.rs | 2 +- .../src/graph/dominators/mod.rs | 8 ++++---- compiler/rustc_hir/src/hir.rs | 5 ++--- compiler/rustc_hir/src/hir_id.rs | 6 +++--- compiler/rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 6 +++--- compiler/rustc_hir_analysis/src/check/intrinsicck.rs | 4 ++-- .../rustc_hir_analysis/src/hir_ty_lowering/errors.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- compiler/rustc_hir_typeck/src/intrinsicck.rs | 2 +- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 5 +---- compiler/rustc_index_macros/src/newtype.rs | 3 +++ compiler/rustc_middle/src/hir/map/mod.rs | 5 ++--- compiler/rustc_middle/src/infer/canonical.rs | 2 +- compiler/rustc_middle/src/mir/coverage.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_middle/src/ty/typeck_results.rs | 4 ++-- compiler/rustc_mir_build/src/build/custom/parse.rs | 2 +- compiler/rustc_mir_build/src/build/expr/as_rvalue.rs | 2 +- compiler/rustc_mir_build/src/build/scope.rs | 2 +- compiler/rustc_mir_dataflow/src/elaborate_drops.rs | 10 +++++----- compiler/rustc_mir_transform/src/coroutine.rs | 10 +++++----- .../rustc_mir_transform/src/elaborate_box_derefs.rs | 12 +++++------- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../rustc_mir_transform/src/known_panics_lint.rs | 12 +++++------- compiler/rustc_mir_transform/src/simplify.rs | 2 +- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 6 +++--- compiler/rustc_span/src/def_id.rs | 2 +- compiler/rustc_span/src/hygiene.rs | 4 ++-- compiler/rustc_span/src/source_map/tests.rs | 2 +- .../rustc_trait_selection/src/traits/coherence.rs | 6 +----- compiler/rustc_ty_utils/src/layout.rs | 2 +- compiler/rustc_type_ir/src/lib.rs | 2 +- 42 files changed, 80 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index a1164008d0daf..aaa1c09148b1e 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::{Span, DUMMY_SP}; @@ -31,7 +31,7 @@ pub(super) fn index_hir<'hir>( bodies: &SortedMap>, num_nodes: usize, ) -> (IndexVec>, LocalDefIdMap) { - let zero_id = ItemLocalId::new(0); + let zero_id = ItemLocalId::ZERO; let err_node = ParentedNode { parent: zero_id, node: Node::Err(item.span()) }; let mut nodes = IndexVec::from_elem_n(err_node, num_nodes); // This node's parent should never be accessed: the owner's parent is computed by the diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c9786328565ba..abfea6078f21c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -11,7 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::PredicateOrigin; -use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -563,7 +563,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs); if let Some(attrs) = attrs { - this.attrs.insert(hir::ItemLocalId::new(0), attrs); + this.attrs.insert(hir::ItemLocalId::ZERO, attrs); } let item = hir::Item { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 833b0e9b5679e..8cf347bfa966c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -157,7 +157,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { attrs: SortedMap::default(), children: Vec::default(), current_hir_id_owner: hir::CRATE_OWNER_ID, - item_local_id_counter: hir::ItemLocalId::new(0), + item_local_id_counter: hir::ItemLocalId::ZERO, node_id_to_local_id: Default::default(), trait_map: Default::default(), @@ -583,7 +583,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. // Always allocate the first `HirId` for the owner itself. - let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0)); + let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); debug_assert_eq!(_old, None); let item = f(self); @@ -677,7 +677,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { v.insert(local_id); self.item_local_id_counter.increment_by(1); - assert_ne!(local_id, hir::ItemLocalId::new(0)); + assert_ne!(local_id, hir::ItemLocalId::ZERO); if let Some(def_id) = self.opt_local_def_id(ast_node_id) { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); } @@ -696,7 +696,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn next_id(&mut self) -> hir::HirId { let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; - assert_ne!(local_id, hir::ItemLocalId::new(0)); + assert_ne!(local_id, hir::ItemLocalId::ZERO); self.item_local_id_counter.increment_by(1); hir::HirId { owner, local_id } } diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 6a683d129ded1..a38dd286be51b 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -159,7 +159,7 @@ impl<'tcx> BorrowSet<'tcx> { } pub(crate) fn indices(&self) -> impl Iterator { - BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len()) + BorrowIndex::ZERO..BorrowIndex::from_usize(self.len()) } pub(crate) fn iter_enumerated(&self) -> impl Iterator)> { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 1615dc5de697b..8df83c706a100 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -1393,7 +1393,7 @@ fn llvm_add_sub<'tcx>( // c + carry -> c + first intermediate carry or borrow respectively let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b); - let c = int0.value_field(fx, FieldIdx::new(0)); + let c = int0.value_field(fx, FieldIdx::ZERO); let cb0 = int0.value_field(fx, FieldIdx::new(1)).load_scalar(fx); // c + carry -> c + second intermediate carry or borrow respectively diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 86ebf37d105f6..04e24320f9131 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -61,7 +61,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( if ty.is_dyn_star() { let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); - let ptr = dyn_star.place_field(fx, FieldIdx::new(0)).to_ptr(); + let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let vtable = dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx); break 'block (ptr, vtable); diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index a45f1dd72a126..30e240cf85b84 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -72,7 +72,7 @@ fn dominators_impl(graph: &G) -> Inner { IndexVec::with_capacity(graph.num_nodes()); let mut stack = vec![PreOrderFrame { - pre_order_idx: PreorderIndex::new(0), + pre_order_idx: PreorderIndex::ZERO, iter: graph.successors(graph.start_node()), }]; let mut pre_order_to_real: IndexVec = @@ -80,8 +80,8 @@ fn dominators_impl(graph: &G) -> Inner { let mut real_to_pre_order: IndexVec> = IndexVec::from_elem_n(None, graph.num_nodes()); pre_order_to_real.push(graph.start_node()); - parent.push(PreorderIndex::new(0)); // the parent of the root node is the root for now. - real_to_pre_order[graph.start_node()] = Some(PreorderIndex::new(0)); + parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now. + real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO); let mut post_order_idx = 0; // Traverse the graph, collecting a number of things: @@ -111,7 +111,7 @@ fn dominators_impl(graph: &G) -> Inner { let reachable_vertices = pre_order_to_real.len(); - let mut idom = IndexVec::from_elem_n(PreorderIndex::new(0), reachable_vertices); + let mut idom = IndexVec::from_elem_n(PreorderIndex::ZERO, reachable_vertices); let mut semi = IndexVec::from_fn_n(std::convert::identity, reachable_vertices); let mut label = semi.clone(); let mut bucket = IndexVec::from_elem_n(vec![], reachable_vertices); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a0f86565929b9..013bb24a7f23a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -846,9 +846,8 @@ pub struct OwnerNodes<'tcx> { impl<'tcx> OwnerNodes<'tcx> { pub fn node(&self) -> OwnerNode<'tcx> { - use rustc_index::Idx; // Indexing must ensure it is an OwnerNode. - self.nodes[ItemLocalId::new(0)].node.as_owner().unwrap() + self.nodes[ItemLocalId::ZERO].node.as_owner().unwrap() } } @@ -856,7 +855,7 @@ impl fmt::Debug for OwnerNodes<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OwnerNodes") // Do not print all the pointers to all the nodes, as it would be unreadable. - .field("node", &self.nodes[ItemLocalId::from_u32(0)]) + .field("node", &self.nodes[ItemLocalId::ZERO]) .field( "parents", &self diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index d339075c171d1..0341a482fa8c1 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -17,7 +17,7 @@ impl Debug for OwnerId { impl From for HirId { fn from(owner: OwnerId) -> HirId { - HirId { owner, local_id: ItemLocalId::from_u32(0) } + HirId { owner, local_id: ItemLocalId::ZERO } } } @@ -110,7 +110,7 @@ impl HirId { #[inline] pub fn make_owner(owner: LocalDefId) -> Self { - Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::from_u32(0) } + Self { owner: OwnerId { def_id: owner }, local_id: ItemLocalId::ZERO } } pub fn index(self) -> (usize, usize) { @@ -172,6 +172,6 @@ unsafe impl StableOrd for ItemLocalId { /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`. pub const CRATE_HIR_ID: HirId = - HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) }; + HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::ZERO }; pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID }; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index a880445a27c1b..739a708699239 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -899,7 +899,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit(); return; } - let e = fields[FieldIdx::from_u32(0)].ty(tcx, args); + let e = fields[FieldIdx::ZERO].ty(tcx, args); if !fields.iter().all(|f| f.ty(tcx, args) == e) { struct_span_code_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous") .with_span_label(sp, "SIMD elements must have the same type") diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 00a0fca490722..0dcd98fdec0ff 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -183,7 +183,7 @@ pub fn check_intrinsic_type( let region = ty::Region::new_bound( tcx, ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }, + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }, ); let env_region = ty::Region::new_bound( tcx, @@ -495,7 +495,7 @@ pub fn check_intrinsic_type( ); let discriminant_def_id = assoc_items[0]; - let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }; + let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }; ( 1, 0, @@ -555,7 +555,7 @@ pub fn check_intrinsic_type( } sym::raw_eq => { - let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }; + let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }; let param_ty_lhs = Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0)); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon }; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index df4db3ec3fbd3..1958a80d47c18 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), ty::Adt(adt, args) if adt.repr().simd() => { let fields = &adt.non_enum_variant().fields; - let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args); + let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args); let (size, ty) = match elem_ty.kind() { ty::Array(ty, len) => { @@ -146,7 +146,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { "expected first field of `MaybeUnit` to be `ManuallyDrop`" ); let fields = &ty.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args); + let ty = fields[FieldIdx::ZERO].ty(self.tcx, args); self.get_asm_ty(ty) } _ => self.get_asm_ty(ty), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 7a0890e50dac8..70f09dd61758e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -628,7 +628,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let projection_ty = pred.skip_binder().projection_ty; let args_with_infer_self = tcx.mk_args_from_iter( - std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) + std::iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into()) .chain(projection_ty.args.iter().skip(1)), ); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 5841392dbcf16..59a043d1d6996 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -182,7 +182,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> ty::Region::new_bound( tcx, ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon }, + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BrAnon }, ), panic_info_ty, ); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 9e3867e630d48..62711e40049a4 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -17,7 +17,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let data_idx; let one = VariantIdx::new(1); - let zero = VariantIdx::new(0); + let zero = VariantIdx::ZERO; if def.variant(zero).fields.is_empty() { data_idx = one; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 12f522d1adcf0..a199f57aad99f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let projection_ty = pred.skip_binder().projection_ty; let args_with_infer_self = tcx.mk_args_from_iter( - iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into()) + iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into()) .chain(projection_ty.args.iter().skip(1)), ); diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 54344adaabd22..72e5b1ed95bf0 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -343,10 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_env_region: ty::Region<'_> = ty::Region::new_bound( self.tcx, ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(0), - kind: ty::BoundRegionKind::BrEnv, - }, + ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv }, ); let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter( self.tcx, diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index e5c2ba424834a..fe9a048734fc7 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -174,6 +174,9 @@ impl Parse for Newtype { /// Maximum value the index can take. #vis const MAX: Self = Self::from_u32(#max); + /// Zero value of the index. + #vis const ZERO: Self = Self::from_u32(0); + /// Creates a new index from a given `usize`. /// /// # Panics diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 53cb05198cd6f..72f849b534a81 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::Visitor; use rustc_hir::*; -use rustc_index::Idx; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -69,7 +68,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { fn next(&mut self) -> Option { if self.current_id.local_id.index() != 0 { - self.current_id.local_id = ItemLocalId::new(0); + self.current_id.local_id = ItemLocalId::ZERO; let node = self.map.tcx.hir_owner_node(self.current_id.owner); return Some((self.current_id.owner, node)); } @@ -133,7 +132,7 @@ impl<'tcx> TyCtxt<'tcx> { /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. pub fn parent_hir_id(self, hir_id: HirId) -> HirId { let HirId { owner, local_id } = hir_id; - if local_id == ItemLocalId::from_u32(0) { + if local_id == ItemLocalId::ZERO { self.hir_owner_parent(owner) } else { let parent_local_id = self.hir_owner_nodes(owner).nodes[local_id].parent; diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 7b65c11bc3c82..acea89e4aabec 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -82,7 +82,7 @@ impl CanonicalVarValues<'_> { } pub fn is_identity_modulo_regions(&self) -> bool { - let mut var = ty::BoundVar::from_u32(0); + let mut var = ty::BoundVar::ZERO; for arg in self.var_values { match arg.unpack() { ty::GenericArgKind::Lifetime(r) => { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index 588aa1f40d79c..0c91dc6d3c684 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -34,7 +34,7 @@ rustc_index::newtype_index! { } impl CounterId { - pub const START: Self = Self::from_u32(0); + pub const START: Self = Self::ZERO; } rustc_index::newtype_index! { @@ -56,7 +56,7 @@ rustc_index::newtype_index! { } impl ExpressionId { - pub const START: Self = Self::from_u32(0); + pub const START: Self = Self::ZERO; } /// Enum that can hold a constant zero value, the ID of an physical coverage diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4e1baaec39ea7..ad59778f58fe9 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1324,7 +1324,7 @@ impl VariantDef { pub fn single_field(&self) -> &FieldDef { assert!(self.fields.len() == 1); - &self.fields[FieldIdx::from_u32(0)] + &self.fields[FieldIdx::ZERO] } /// Returns the last field in this variant, if present. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5ff98dc8c873f..2a898430ce9f9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2589,7 +2589,7 @@ impl<'a, 'tcx> ty::TypeFolder> for RegionFolder<'a, 'tcx> { ty::BrAnon | ty::BrEnv => r, _ => { // Index doesn't matter, since this is just for naming and these never get bound - let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind }; + let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind }; *self .region_map .entry(br) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b5e619f1e2a3c..765f65a04db56 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1954,7 +1954,7 @@ impl<'tcx> Ty<'tcx> { Adt(def, args) => { assert!(def.repr().simd(), "`simd_size_and_type` called on non-SIMD type"); let variant = def.non_enum_variant(); - let f0_ty = variant.fields[FieldIdx::from_u32(0)].ty(tcx, args); + let f0_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); match f0_ty.kind() { // If the first field is an array, we assume it is the only field and its diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index d60926bf796d9..0d74524276fa7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -19,7 +19,7 @@ use rustc_hir::{ hir_id::OwnerId, BindingAnnotation, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability, }; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; @@ -680,7 +680,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { return false; } - iter::zip(user_args.args, BoundVar::new(0)..).all(|(kind, cvar)| { + iter::zip(user_args.args, BoundVar::ZERO..).all(|(kind, cvar)| { match kind.unpack() { GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index a6f9caada2d19..0384b9bc154e2 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -215,7 +215,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { fn parse_local_decls(&mut self, mut stmts: impl Iterator) -> PResult<()> { let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?; - self.local_map.insert(ret_var, Local::from_u32(0)); + self.local_map.insert(ret_var, Local::ZERO); for stmt in stmts { let (var, ty, span) = self.parse_let_statement(stmt)?; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 00600f354ca5a..260ab058e600c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -573,7 +573,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { result_value, Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))), ); - let val_fld = FieldIdx::new(0); + let val_fld = FieldIdx::ZERO; let of_fld = FieldIdx::new(1); let tcx = self.tcx; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 9ac8c1b44174b..2d31e84aba7da 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -190,7 +190,7 @@ rustc_index::newtype_index! { struct DropIdx {} } -const ROOT_NODE: DropIdx = DropIdx::from_u32(0); +const ROOT_NODE: DropIdx = DropIdx::ZERO; /// A tree of drops that we have deferred lowering. It's used for: /// diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 256add3153c9c..d63db6ea8edd8 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -420,14 +420,14 @@ where ) -> BasicBlock { // drop glue is sent straight to codegen // box cannot be directly dereferenced - let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), args); + let unique_ty = adt.non_enum_variant().fields[FieldIdx::ZERO].ty(self.tcx(), args); let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant(); - let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), args); + let nonnull_ty = unique_variant.fields[FieldIdx::ZERO].ty(self.tcx(), args); let ptr_ty = Ty::new_imm_ptr(self.tcx(), args[0].expect_ty()); - let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty); - let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty); - let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::new(0), ptr_ty); + let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty); + let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty); + let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty); let interior = self.tcx().mk_place_deref(ptr_place); let interior_path = self.elaborator.deref_subpath(self.path); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index c3f175f150d21..e2a911f0dc7d9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -168,7 +168,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { Place { local: SELF_ARG, projection: self.tcx().mk_place_elems(&[ProjectionElem::Field( - FieldIdx::new(0), + FieldIdx::ZERO, self.ref_coroutine_ty, )]), }, @@ -267,7 +267,7 @@ impl<'tcx> TransformVisitor<'tcx> { Rvalue::Aggregate( Box::new(AggregateKind::Adt( option_def_id, - VariantIdx::from_usize(0), + VariantIdx::ZERO, self.tcx.mk_args(&[self.old_yield_ty.into()]), None, None, @@ -329,7 +329,7 @@ impl<'tcx> TransformVisitor<'tcx> { Rvalue::Aggregate( Box::new(AggregateKind::Adt( poll_def_id, - VariantIdx::from_usize(0), + VariantIdx::ZERO, args, None, None, @@ -358,7 +358,7 @@ impl<'tcx> TransformVisitor<'tcx> { Rvalue::Aggregate( Box::new(AggregateKind::Adt( option_def_id, - VariantIdx::from_usize(0), + VariantIdx::ZERO, args, None, None, @@ -420,7 +420,7 @@ impl<'tcx> TransformVisitor<'tcx> { Rvalue::Aggregate( Box::new(AggregateKind::Adt( coroutine_state_def_id, - VariantIdx::from_usize(0), + VariantIdx::ZERO, args, None, None, diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 96943435bab89..318674f24e7ab 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -3,7 +3,6 @@ //! Box is not actually a pointer so it is incorrect to dereference it directly. use rustc_hir::def_id::DefId; -use rustc_index::Idx; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::*; @@ -32,9 +31,9 @@ pub fn build_projection<'tcx>( ptr_ty: Ty<'tcx>, ) -> [PlaceElem<'tcx>; 3] { [ - PlaceElem::Field(FieldIdx::new(0), unique_ty), - PlaceElem::Field(FieldIdx::new(0), nonnull_ty), - PlaceElem::Field(FieldIdx::new(0), ptr_ty), + PlaceElem::Field(FieldIdx::ZERO, unique_ty), + PlaceElem::Field(FieldIdx::ZERO, nonnull_ty), + PlaceElem::Field(FieldIdx::ZERO, ptr_ty), ] } @@ -91,15 +90,14 @@ pub struct ElaborateBoxDerefs; impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if let Some(def_id) = tcx.lang_items().owned_box() { - let unique_did = - tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::from_u32(0)].did; + let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did; let Some(nonnull_def) = tcx.type_of(unique_did).instantiate_identity().ty_adt_def() else { span_bug!(tcx.def_span(unique_did), "expected Box to contain Unique") }; - let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::from_u32(0)].did; + let nonnull_did = nonnull_def.non_enum_variant().fields[FieldIdx::ZERO].did; let patch = MirPatch::new(body); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 59d6d89cf1fec..d4f736d2a50f6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -355,7 +355,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn insert_tuple(&mut self, values: Vec) -> VnIndex { - self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::from_u32(0), values)) + self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values)) } #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index a20958e74dffe..2218154ea5e78 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -13,7 +13,7 @@ use rustc_const_eval::interpret::{ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::HirId; -use rustc_index::{bit_set::BitSet, Idx, IndexVec}; +use rustc_index::{bit_set::BitSet, IndexVec}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; @@ -124,10 +124,8 @@ impl<'tcx> Value<'tcx> { fields.ensure_contains_elem(*idx, || Value::Uninit) } (PlaceElem::Field(..), val @ Value::Uninit) => { - *val = Value::Aggregate { - variant: VariantIdx::new(0), - fields: Default::default(), - }; + *val = + Value::Aggregate { variant: VariantIdx::ZERO, fields: Default::default() }; val.project_mut(&[*proj])? } _ => return None, @@ -572,7 +570,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?; let overflowed = ImmTy::from_bool(overflowed, self.tcx); Value::Aggregate { - variant: VariantIdx::new(0), + variant: VariantIdx::ZERO, fields: [Value::from(val), overflowed.into()].into_iter().collect(), } } @@ -607,7 +605,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | AggregateKind::Tuple | AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) - | AggregateKind::CoroutineClosure(_, _) => VariantIdx::new(0), + | AggregateKind::CoroutineClosure(_, _) => VariantIdx::ZERO, }, } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 14772080ce5f0..5bbe3bb747fd9 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -415,7 +415,7 @@ fn make_local_map( used_locals: &UsedLocals, ) -> IndexVec> { let mut map: IndexVec> = IndexVec::from_elem(None, local_decls); - let mut used = Local::new(0); + let mut used = Local::ZERO; for alive_index in local_decls.indices() { // `is_used` treats the `RETURN_PLACE` and arguments as used. diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 9f067273f3580..f223f64f2c5d0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -40,7 +40,7 @@ rustc_index::newtype_index! { } impl DepNodeIndex { - const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0); + const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::ZERO; pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 48711f435186d..76fe36a77cb8a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -532,7 +532,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut seen_spans = FxHashSet::default(); let mut errors = vec![]; - let mut prev_root_id: NodeId = NodeId::from_u32(0); + let mut prev_root_id: NodeId = NodeId::ZERO; let determined_imports = mem::take(&mut self.determined_imports); let indeterminate_imports = mem::take(&mut self.indeterminate_imports); @@ -556,8 +556,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - if prev_root_id.as_u32() != 0 - && prev_root_id.as_u32() != import.root_id.as_u32() + if prev_root_id != NodeId::ZERO + && prev_root_id != import.root_id && !errors.is_empty() { // In the case of a new import line, throw a diagnostic message diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 8f721bac95140..8925b7a42d485 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -22,7 +22,7 @@ rustc_index::newtype_index! { /// Item definitions in the currently-compiled crate would have the `CrateNum` /// `LOCAL_CRATE` in their `DefId`. -pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0); +pub const LOCAL_CRATE: CrateNum = CrateNum::ZERO; impl CrateNum { #[inline] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 37fea6c122c7a..1df2b357ac128 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -165,7 +165,7 @@ pub enum Transparency { impl LocalExpnId { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. - pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0); + pub const ROOT: LocalExpnId = LocalExpnId::ZERO; #[inline] fn from_raw(idx: ExpnIndex) -> LocalExpnId { @@ -242,7 +242,7 @@ impl ExpnId { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. /// Invariant: we do not create any ExpnId with local_id == 0 and krate != 0. pub const fn root() -> ExpnId { - ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::from_u32(0) } + ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO } } #[inline] diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 81a9e4706883f..dcb02da371921 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -243,7 +243,7 @@ fn t10() { src_hash, stable_id, source_len.to_u32(), - CrateNum::new(0), + CrateNum::ZERO, FreezeLock::new(lines.read().clone()), multibyte_chars, non_narrow_chars, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 6e768b23ef8c8..90e337a53b655 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -554,11 +554,7 @@ fn plug_infer_with_placeholders<'tcx>( } } - value.visit_with(&mut PlugInferWithPlaceholder { - infcx, - universe, - var: ty::BoundVar::from_u32(0), - }); + value.visit_with(&mut PlugInferWithPlaceholder { infcx, universe, var: ty::BoundVar::ZERO }); } fn try_prove_negated_where_clause<'tcx>( diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 331970ac36233..dd1f2322c4140 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -377,7 +377,7 @@ fn layout_of_uncached<'tcx>( } // Type of the first ADT field: - let f0_ty = fields[FieldIdx::from_u32(0)].ty(tcx, args); + let f0_ty = fields[FieldIdx::ZERO].ty(tcx, args); // Heterogeneous SIMD vectors are not supported: // (should be caught by typeck) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c01baa58ae784..45e22b12a8b06 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -314,7 +314,7 @@ rustc_index::newtype_index! { } impl UniverseIndex { - pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0); + pub const ROOT: UniverseIndex = UniverseIndex::ZERO; /// Returns the "next" universe index in order -- this new index /// is considered to extend all previous universes. This From 6edb021fd3655df3848f590005e3a688147d2164 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 4 Apr 2024 01:31:04 +0900 Subject: [PATCH 18/18] Fix target name in NetBSD platform-support doc --- src/doc/rustc/src/platform-support/netbsd.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index 3891d6d3148da..ef9337befa643 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -13,7 +13,7 @@ are currently defined running NetBSD: | Target name | NetBSD Platform | |--------------------------------|-----------------| -| `amd64-unknown-netbsd` | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) | +| `x86_64-unknown-netbsd` | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) | | `armv7-unknown-netbsd-eabihf` | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) | | `armv6-unknown-netbsd-eabihf` | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) | | `aarch64-unknown-netbsd` | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) | @@ -22,7 +22,7 @@ are currently defined running NetBSD: | `i686-unknown-netbsd` | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) | | `mipsel-unknown-netbsd` | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) | | `powerpc-unknown-netbsd` | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) | -| `riscv64gc-unknown-netbsd` | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) +| `riscv64gc-unknown-netbsd` | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) | | `sparc64-unknown-netbsd` | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) | All use the "native" `stdc++` library which goes along with the natively @@ -43,7 +43,7 @@ bug reporting system. ## Requirements -The `amd64-unknown-netbsd` artifacts is being distributed by the +The `x86_64-unknown-netbsd` artifacts is being distributed by the rust project. The other targets are built by the designated developers (see above), @@ -95,7 +95,7 @@ capable systems we build and test `firefox` (amd64, i386, aarch64). ## Building Rust programs -Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd` +Rust ships pre-compiled artifacts for the `x86_64-unknown-netbsd` target. For the other systems mentioned above, using the `pkgsrc` route is