From 6a16638de6449fd30b804e55f3cc2c142e32f55e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 12 Mar 2024 00:33:48 +0000 Subject: [PATCH 01/38] std::rand: fix dragonflybsd after #121942. --- library/std/src/sys/pal/unix/rand.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs index c9ed6825f6c21..d52c3254e5ebf 100644 --- a/library/std/src/sys/pal/unix/rand.rs +++ b/library/std/src/sys/pal/unix/rand.rs @@ -62,17 +62,23 @@ mod imp { unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } - #[cfg(any( - target_os = "espidf", - target_os = "horizon", - target_os = "freebsd", - target_os = "dragonfly", - netbsd10 - ))] + #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } } + #[cfg(target_os = "dragonfly")] + fn getrandom(buf: &mut [u8]) -> libc::ssize_t { + extern "C" { + fn getrandom( + buf: *mut libc::c_void, + buflen: libc::size_t, + flags: libc::c_uint, + ) -> libc::ssize_t; + } + unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } + } + #[cfg(not(any( target_os = "linux", target_os = "android", From df933640571861bcc2854431823cd9d4803b9f88 Mon Sep 17 00:00:00 2001 From: Steven Trotter Date: Sun, 25 Feb 2024 16:36:26 +0000 Subject: [PATCH 02/38] 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 03/38] 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 04/38] 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 05/38] 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 06/38] 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 07/38] 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 08/38] 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 09/38] 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 10/38] 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 11/38] 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 12/38] 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 13/38] 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 14/38] 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 93c2bace58b36ba297f06505b55aef5b8eba954f Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Tue, 2 Apr 2024 18:23:28 +0000 Subject: [PATCH 15/38] CFI: Switch sense of type erasure flag Previously, we had `NO_SELF_TYPE_ERASURE`, a negative configuration. Now we have `ERASE_SELF_TYPE`, a positive configuration. --- compiler/rustc_codegen_llvm/src/declare.rs | 6 ++++-- compiler/rustc_symbol_mangling/src/typeid.rs | 6 +++--- .../src/typeid/typeid_itanium_cxx_abi.rs | 2 +- ...e-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 3ef8538ced3a5..f58dd4066ad71 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -147,7 +147,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { for options in [ TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS, - TypeIdOptions::NO_SELF_TYPE_ERASURE, + TypeIdOptions::ERASE_SELF_TYPE, ] .into_iter() .powerset() @@ -173,7 +173,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if self.tcx.sess.is_sanitizer_kcfi_enabled() { // LLVM KCFI does not support multiple !kcfi_type attachments - let mut options = TypeIdOptions::empty(); + // Default to erasing the self type. If we need the concrete type, there will be a + // hint in the instance. + let mut options = TypeIdOptions::ERASE_SELF_TYPE; if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { options.insert(TypeIdOptions::GENERALIZE_POINTERS); } diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index fc1e8e46e8de5..11657b3b303af 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -24,9 +24,9 @@ bitflags! { /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM /// CFI and KCFI support. const NORMALIZE_INTEGERS = 4; - /// Do not perform self type erasure for attaching a secondary type id to methods with their - /// concrete self so they can be used as function pointers. - const NO_SELF_TYPE_ERASURE = 8; + /// Generalize the instance by erasing the concrete `Self` type where possible. + /// Only has an effect on `{kcfi_,}typeid_for_instance`. + const ERASE_SELF_TYPE = 8; } } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 5963bd7c5f16c..25194e2c87ed3 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -1172,7 +1172,7 @@ pub fn typeid_for_instance<'tcx>( instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); } - if !options.contains(EncodeTyOptions::NO_SELF_TYPE_ERASURE) { + if options.contains(EncodeTyOptions::ERASE_SELF_TYPE) { if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) { diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs index 671db563dde78..999fd292fe7e4 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-method-secondary-typeid.rs @@ -18,5 +18,5 @@ impl Trait1 for Type1 { } -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type1EE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} From 6aa89f684e4427a9d08e35b572f9071705105140 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 25 Mar 2024 19:27:43 +0000 Subject: [PATCH 16/38] Track reason for creating a `ReifyShim` KCFI needs to be able to tell which kind of `ReifyShim` it is examining in order to decide whether to use a concrete type (`FnPtr` case) or an abstract case (`Vtable` case). You can *almost* tell this from context, but there is one case where you can't - if a trait has a method which is *not* `#[track_caller]`, with an impl that *is* `#[track_caller]`, both the vtable and a function pointer created from that method will be `ReifyShim(def_id)`. Currently, the reason is optional to ensure no additional unique `ReifyShim`s are added without KCFI on. However, the case in which an extra `ReifyShim` is created is sufficiently rare that this may be worth revisiting to reduce complexity. --- compiler/rustc_middle/src/mir/visit.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 48 +++++++++++++++---- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 1 + compiler/rustc_mir_transform/src/inline.rs | 2 +- .../rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_symbol_mangling/src/legacy.rs | 12 +++-- compiler/rustc_symbol_mangling/src/v0.rs | 8 ++-- 9 files changed, 60 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3835bd371d996..4f7b2f7cbe48b 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -341,7 +341,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::Intrinsic(_def_id) | ty::InstanceDef::VTableShim(_def_id) | - ty::InstanceDef::ReifyShim(_def_id) | + ty::InstanceDef::ReifyShim(_def_id, _) | ty::InstanceDef::Virtual(_def_id, _) | ty::InstanceDef::ThreadLocalShim(_def_id) | ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4fec5653a798c..e5625c8a5c634 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -31,6 +31,28 @@ pub struct Instance<'tcx> { pub args: GenericArgsRef<'tcx>, } +/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to +/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a +/// function pointer from a vtable entry. +/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two +/// `ReifyShim`s differently. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(TyEncodable, TyDecodable, HashStable)] +pub enum ReifyReason { + /// The `ReifyShim` was created to produce a function pointer. This happens when: + /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a + /// method on a `dyn` object). + /// * A function with `#[track_caller]` is converted to a function pointer + /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait. + /// This includes the case of converting `::call`-like methods on closure-likes to function + /// pointers. + FnPtr, + /// This `ReifyShim` was created to populate a vtable. Currently, this happens when a + /// `#[track_caller]` mismatch occurs between the implementation of a method and the method. + /// This includes the case of `::call`-like methods in closure-likes' vtables. + Vtable, +} + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum InstanceDef<'tcx> { @@ -67,7 +89,13 @@ pub enum InstanceDef<'tcx> { /// Because this is a required part of the function's ABI but can't be tracked /// as a property of the function pointer, we use a single "caller location" /// (the definition of the function itself). - ReifyShim(DefId), + /// + /// The second field encodes *why* this shim was created. This allows distinguishing between + /// a `ReifyShim` that appears in a vtable vs one that appears as a function pointer. + /// + /// This field will only be populated if we are compiling in a mode that needs these shims + /// to be separable, currently only when KCFI is enabled. + ReifyShim(DefId, Option), /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// @@ -194,7 +222,7 @@ impl<'tcx> InstanceDef<'tcx> { match self { InstanceDef::Item(def_id) | InstanceDef::VTableShim(def_id) - | InstanceDef::ReifyShim(def_id) + | InstanceDef::ReifyShim(def_id, _) | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) @@ -354,7 +382,9 @@ fn fmt_instance( match instance.def { InstanceDef::Item(_) => Ok(()), InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), - InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), + InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"), + InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), + InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), @@ -476,15 +506,16 @@ impl<'tcx> Instance<'tcx> { debug!("resolve(def_id={:?}, args={:?})", def_id, args); // Use either `resolve_closure` or `resolve_for_vtable` assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def); + resolved.def = InstanceDef::ReifyShim(def, reason); } InstanceDef::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id); + resolved.def = InstanceDef::ReifyShim(def_id, reason); } _ => {} } @@ -508,6 +539,7 @@ impl<'tcx> Instance<'tcx> { debug!(" => associated item with unsizeable self: Self"); Some(Instance { def: InstanceDef::VTableShim(def_id), args }) } else { + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) => { @@ -544,18 +576,18 @@ impl<'tcx> Instance<'tcx> { // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a // trait. - resolved = Instance { def: InstanceDef::ReifyShim(def_id), args }; + resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }; } else { debug!( " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceDef::ReifyShim(def); + resolved.def = InstanceDef::ReifyShim(def, reason); } } } InstanceDef::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id); + resolved.def = InstanceDef::ReifyShim(def_id, reason) } _ => {} } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4e1baaec39ea7..eef623d77b06c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -88,7 +88,7 @@ pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::List; pub use self::parameterized::ParameterizedOverTcx; pub use self::predicate::{ diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a62379def534e..0e7010e67d7dc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -449,6 +449,7 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, + crate::ty::instance::ReifyReason, interpret::AllocId, interpret::CtfeProvenance, interpret::Scalar, diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 5f74841151cda..ab9fa165a200a 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -324,7 +324,7 @@ impl<'tcx> Inliner<'tcx> { // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(_) + | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index f2b6dcac58632..7a1340f3a5527 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -84,7 +84,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(_) + | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::ConstructCoroutineInClosureShim { .. } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index b60ee7649b24a..eaef2b80c860c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -55,7 +55,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::InstanceDef::ReifyShim(def_id) => { + ty::InstanceDef::ReifyShim(def_id, _) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 1c62ce2d214b7..f68668a91e688 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use std::fmt::{self, Write}; @@ -71,8 +71,14 @@ pub(super) fn mangle<'tcx>( ty::InstanceDef::VTableShim(..) => { printer.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceDef::ReifyShim(..) => { - printer.write_str("{{reify-shim}}").unwrap(); + ty::InstanceDef::ReifyShim(_, reason) => { + printer.write_str("{{reify-shim").unwrap(); + match reason { + Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(), + Some(ReifyReason::Vtable) => printer.write_str("-vtable").unwrap(), + None => (), + } + printer.write_str("}}").unwrap(); } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4369f020d27a3..8cb5370bb4a87 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -8,8 +8,8 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, PrintError, Printer}; use rustc_middle::ty::{ - self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, - UintTy, + self, EarlyBinder, FloatTy, Instance, IntTy, ReifyReason, Ty, TyCtxt, TypeVisitable, + TypeVisitableExt, UintTy, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::kw; @@ -44,7 +44,9 @@ pub(super) fn mangle<'tcx>( let shim_kind = match instance.def { ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), ty::InstanceDef::VTableShim(_) => Some("vtable"), - ty::InstanceDef::ReifyShim(_) => Some("reify"), + ty::InstanceDef::ReifyShim(_, None) => Some("reify"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"), + ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"), ty::InstanceDef::ConstructCoroutineInClosureShim { .. } | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), From 473a70de8457645df7a49558d6ba27405f966ee0 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 25 Mar 2024 17:23:55 +0000 Subject: [PATCH 17/38] CFI: Support function pointers for trait methods Adds support for both CFI and KCFI for attaching concrete and abstract types to functions. KCFI does this through generation of `ReifyShim` on any function pointer that could go in a vtable, and checking the `ReifyReason` when emitting the instance. CFI does this by attaching both the concrete and abstract type to every instance. TypeID codegen tests are switched to be anchored on the left rather than the right in order to allow emission of additional type attachments. Fixes #115953 --- compiler/rustc_middle/src/ty/instance.rs | 18 +++++++++ compiler/rustc_symbol_mangling/src/typeid.rs | 9 ++++- tests/ui/sanitizer/cfi-closures.rs | 4 -- tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs | 42 ++++++++++++++++++-- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e5625c8a5c634..4a7720b38f850 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -517,6 +517,24 @@ impl<'tcx> Instance<'tcx> { debug!(" => fn pointer created for virtual call"); resolved.def = InstanceDef::ReifyShim(def_id, reason); } + // Reify `Trait::method` implementations if KCFI is enabled + // FIXME(maurer) only reify it if it is a vtable-safe function + _ if tcx.sess.is_sanitizer_kcfi_enabled() + && tcx.associated_item(def_id).trait_item_def_id.is_some() => + { + // If this function could also go in a vtable, we need to `ReifyShim` it with + // KCFI because it can only attach one type per function. + resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason) + } + // Reify `::call`-like method implementations if KCFI is enabled + _ if tcx.sess.is_sanitizer_kcfi_enabled() + && tcx.is_closure_like(resolved.def_id()) => + { + // Reroute through a reify via the *unresolved* instance. The resolved one can't + // be directly reified because it's closure-like. The reify can handle the + // unresolved instance. + resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args } + } _ => {} } diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index 11657b3b303af..862ba285db807 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -4,7 +4,7 @@ /// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, /// see design document in the tracking issue #89653. use bitflags::bitflags; -use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; use twox_hash::XxHash64; @@ -67,8 +67,13 @@ pub fn kcfi_typeid_for_fnabi<'tcx>( pub fn kcfi_typeid_for_instance<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - options: TypeIdOptions, + mut options: TypeIdOptions, ) -> u32 { + // If we receive a `ReifyShim` intended to produce a function pointer, we need to remain + // concrete - abstraction is for vtables. + if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { + options.remove(TypeIdOptions::ERASE_SELF_TYPE); + } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) let mut hash: XxHash64 = Default::default(); diff --git a/tests/ui/sanitizer/cfi-closures.rs b/tests/ui/sanitizer/cfi-closures.rs index 54f1cc035bc5b..f3d9be3571664 100644 --- a/tests/ui/sanitizer/cfi-closures.rs +++ b/tests/ui/sanitizer/cfi-closures.rs @@ -15,7 +15,6 @@ #![feature(fn_traits)] #![feature(unboxed_closures)] -#![feature(cfg_sanitize)] fn foo<'a, T>() -> Box &'a T> { Box::new(|x| x) @@ -72,9 +71,6 @@ fn use_closure(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 { } #[test] -// FIXME after KCFI reify support is added, remove this -// It will appear to work if you test locally, set -C opt-level=0 to see it fail. -#[cfg_attr(sanitize = "kcfi", ignore)] fn closure_addr_taken() { let x = 3i32; let f = || x; diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs index 273b8785faeed..8f79de1174883 100644 --- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs @@ -1,11 +1,41 @@ // Verifies that casting a method to a function pointer works. -// -// FIXME(#122848): Remove only-linux when fixed. + +//@ revisions: cfi kcfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C opt-level=0 -C codegen-units=1 -C lto +//@ [cfi] compile-flags: -C prefer-dynamic=off +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi +//@ [kcfi] compile-flags: -C panic=abort -C prefer-dynamic=off //@ run-pass +trait Foo { + fn foo(&self); + fn bar(&self); +} + +struct S; + +impl Foo for S { + fn foo(&self) {} + #[track_caller] + fn bar(&self) {} +} + +struct S2 { + f: fn(&S) +} + +impl S2 { + fn foo(&self, s: &S) { + (self.f)(s) + } +} + trait Trait1 { fn foo(&self); } @@ -20,4 +50,8 @@ fn main() { let type1 = Type1 {}; let f = ::foo; f(&type1); + // Check again with different optimization barriers + S2 { f: ::foo }.foo(&S); + // Check mismatched #[track_caller] + S2 { f: ::bar }.foo(&S) } From ab821aed0c048964a86285d534ca93203d61af89 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Apr 2024 19:30:32 -0400 Subject: [PATCH 18/38] 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 19/38] 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 2d47cd77ac7b41a08f5c2ebc22035ed2f39dc076 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 3 Apr 2024 12:55:40 +1100 Subject: [PATCH 20/38] Check `x86_64` size assertions on `aarch64`, too This makes it easier for contributors on aarch64 workstations (e.g. Macs) to notice when these assertions have been violated. --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/token.rs | 2 +- compiler/rustc_ast/src/tokenstream.rs | 2 +- compiler/rustc_const_eval/src/interpret/operand.rs | 2 +- compiler/rustc_const_eval/src/interpret/place.rs | 2 +- compiler/rustc_errors/src/lib.rs | 4 ++-- compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_index/src/bit_set.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_infer/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 2 +- compiler/rustc_middle/src/mir/interpret/error.rs | 2 +- compiler/rustc_middle/src/mir/interpret/value.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/query.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 2 +- compiler/rustc_middle/src/mir/tcx.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 4 ++-- compiler/rustc_middle/src/thir.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/consts/kind.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 2 +- compiler/rustc_parse/src/parser/attr_wrapper.rs | 2 +- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 2 +- compiler/rustc_target/src/abi/call/mod.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/traits/fulfill.rs | 2 +- 33 files changed, 36 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index aba94f4d817d7..4ba298902a93f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3341,7 +3341,7 @@ impl TryFrom for ForeignItemKind { pub type ForeignItem = Item; // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index f49eb2f22c50b..5060bbec42169 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -1021,7 +1021,7 @@ where } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 239735456ad53..f3249f3e5a8b5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -768,7 +768,7 @@ impl DelimSpacing { } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 831787a92c869..842fb6d204c29 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -792,7 +792,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 1a2f1194f89a2..e32aea39fc597 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -1058,7 +1058,7 @@ where } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7b40954e735db..c47abf5e988ee 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -102,9 +102,9 @@ pub type PResult<'a, T> = Result>; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index a31be05ccc4d2..9fff00ffeae17 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -266,7 +266,7 @@ struct MatcherPos { } // This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(MatcherPos, 16); impl MatcherPos { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a0f86565929b9..f6d63a293ba22 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3762,7 +3762,7 @@ impl<'hir> Node<'hir> { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; // tidy-alphabetical-start diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 12f8e42c78f94..c7e563035fc33 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -400,7 +400,7 @@ enum Chunk { } // This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] crate::static_assert_size!(Chunk, 16); impl ChunkedBitSet { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 339c8ac10b33a..3e89327d20fdf 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -483,7 +483,7 @@ pub enum SubregionOrigin<'tcx> { } // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(SubregionOrigin<'_>, 32); impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ee9ce842d00af..0444cbe2ee413 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -32,7 +32,7 @@ #[macro_use] extern crate rustc_macros; -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] #[macro_use] extern crate rustc_data_structures; #[macro_use] diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 616f5cc04564a..94ad0f5b1c863 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -112,7 +112,7 @@ impl<'tcx> PolyTraitObligation<'tcx> { } // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(PredicateObligation<'_>, 48); pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2663a6b551eca..155af06201273 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -70,7 +70,7 @@ pub enum ConstValue<'tcx> { }, } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(ConstValue<'_>, 24); impl<'tcx> ConstValue<'tcx> { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index c86970635a55f..e9be26d058b48 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -88,7 +88,7 @@ pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; /// This is needed in `thir::pattern::lower_inline_const`. pub type EvalToValTreeResult<'tcx> = Result>, ErrorHandled>; -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(InterpErrorInfo<'_>, 8); /// Packages the kind of error we got from the const code interpreter diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 24d4a79c7d795..9f9433e483bc0 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -37,7 +37,7 @@ pub enum Scalar { Ptr(Pointer, u8), } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(Scalar, 24); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e5a650c5ac4ae..e046f076389b7 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1881,7 +1881,7 @@ impl DefLocation { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 731e050ca9b76..0a567e2781dce 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -276,7 +276,7 @@ pub struct ClosureOutlivesRequirement<'tcx> { } // Make sure this enum doesn't unintentionally grow -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// Outlives-constraints can be categorized to determine whether and why they diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1f6165babdfb0..eae6ef8c396a4 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1453,7 +1453,7 @@ pub enum BinOp { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; // tidy-alphabetical-start diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 74c2aef8fcc20..b86aa601ce8e3 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -14,7 +14,7 @@ pub struct PlaceTy<'tcx> { } // At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(PlaceTy<'_>, 16); impl<'tcx> PlaceTy<'tcx> { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index e3588a7afdc16..8cb4ee7bd41e0 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -339,7 +339,7 @@ macro_rules! define_callbacks { pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache>; // Ensure that keys grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { if mem::size_of::>() > 64 { panic!("{}", concat!( @@ -353,7 +353,7 @@ macro_rules! define_callbacks { }; // Ensure that values grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { if mem::size_of::>() > 64 { panic!("{}", concat!( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 05f6fbbbfa33b..9bb38a893eb6a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1204,7 +1204,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; // tidy-alphabetical-start diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index efea2a66bb21f..ee81679191978 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -550,7 +550,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { } // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(ObligationCauseCode<'_>, 48); #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 3713883eb00d7..49b806b8369f8 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -59,7 +59,7 @@ pub struct ConstData<'tcx> { pub kind: ConstKind<'tcx>, } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(ConstData<'_>, 40); impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ea02faca5f398..94e41709f5da6 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -71,8 +71,8 @@ pub enum Expr<'tcx> { Cast(CastKind, Const<'tcx>, Ty<'tcx>), } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(Expr<'_>, 24); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(super::ConstKind<'_>, 32); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4e1baaec39ea7..191cdafacb6bc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2168,7 +2168,7 @@ pub struct DestructuredConst<'tcx> { } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b5e619f1e2a3c..fb511f2275fe5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2699,7 +2699,7 @@ impl<'tcx> VarianceDiagInfo<'tcx> { } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 63b2b47630b29..69b48bf0aff71 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -30,7 +30,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; // // This assertion is in this crate, rather than in `rustc_lexer`, because that // crate cannot depend on `rustc_data_structures`. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); #[derive(Clone, Debug)] diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index a1dd7d6f67345..baaed5ec37b7f 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -454,7 +454,7 @@ fn make_token_stream( } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1971591364d34..09bc00403f388 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -179,7 +179,7 @@ pub struct Parser<'a> { // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(Parser<'_>, 264); /// Stores span information about a closure. diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 2bb4b09e337cb..ccda43c827c57 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -1087,7 +1087,7 @@ fn unescape_string(string: &str) -> Option { } // Assert a reasonable size for `Piece` -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] rustc_index::static_assert_size!(Piece<'_>, 16); #[cfg(test)] diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 486afc5f8f30a..706a7a310f2bf 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -927,7 +927,7 @@ impl FromStr for Conv { } // Some types are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index e14fc62cd6f06..b5fb710e4cc42 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -30,7 +30,7 @@ #[macro_use] extern crate rustc_macros; -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] #[macro_use] extern crate rustc_data_structures; #[macro_use] diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 34c891d400e45..b5be9a2bcb35e 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -72,7 +72,7 @@ pub struct PendingPredicateObligation<'tcx> { } // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))] static_assert_size!(PendingPredicateObligation<'_>, 72); impl<'tcx> FulfillmentContext<'tcx> { From f6b51c10f3c23a1079d59e01c5a2c2b92955378f Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 3 Apr 2024 07:59:15 +0200 Subject: [PATCH 21/38] Add Why Rust? section to the README.md and mention our tools --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 6d6383351caf7..2efaab2c290aa 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,19 @@ If you wish to _contribute_ to the compiler, you should read +## Why Rust? + +- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages. + +- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time. + +- **Productivity:** Comprehensive documentation, a compiler committed to providing great diagnostics, and advanced tooling including package manager and build tool ([Cargo]), auto-formatter ([rustfmt]), linter ([Clippy]) and editor support ([rust-analyzer]). + +[Cargo]: https://github.com/rust-lang/cargo +[rustfmt]: https://github.com/rust-lang/rustfmt +[Clippy]: https://github.com/rust-lang/rust-clippy +[rust-analyzer]: https://github.com/rust-lang/rust-analyzer + ## Quick Start Read ["Installation"] from [The Book]. From 120c6b16845c4f70601a0ee1ffe2172f1b0c8c95 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 26 Mar 2024 13:30:46 +0100 Subject: [PATCH 22/38] Add nice header to our README.md --- README.md | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 2efaab2c290aa..c3b72062d8838 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,23 @@ -# The Rust Programming Language - -[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community) +
+ + + + The Rust Programming Language: A language empowering everyone to build reliable and efficient software + + +[Website][Rust] | [Getting started] | [Learn] | [Documentation] | [Contributing] +
This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. [Rust]: https://www.rust-lang.org/ - -**Note: this README is for _users_ rather than _contributors_.** -If you wish to _contribute_ to the compiler, you should read -[CONTRIBUTING.md](CONTRIBUTING.md) instead. - -
-Table of Contents - -- [Quick Start](#quick-start) -- [Installing from Source](#installing-from-source) -- [Getting Help](#getting-help) -- [Contributing](#contributing) -- [License](#license) -- [Trademark](#trademark) - -
+[Getting Started]: https://www.rust-lang.org/learn/get-started +[Learn]: https://www.rust-lang.org/learn +[Documentation]: https://www.rust-lang.org/learn#learn-use +[Contributing]: CONTRIBUTING.md ## Why Rust? From 989660c3e6efc1c5eb2e822f68863df7d06cbcb4 Mon Sep 17 00:00:00 2001 From: joboet Date: Wed, 3 Apr 2024 15:17:00 +0200 Subject: [PATCH 23/38] 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 44b36024786a5e00d55111c1a43a0c8388caefcb Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Apr 2024 17:23:08 +0300 Subject: [PATCH 24/38] hir: Drop owner's own item-local id (zero) from parenting tables --- compiler/rustc_ast_lowering/src/index.rs | 4 +++- compiler/rustc_middle/src/hir/mod.rs | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index a1164008d0daf..6e09632d0e337 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -112,7 +112,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } fn insert_nested(&mut self, item: LocalDefId) { - self.parenting.insert(item, self.parent_node); + if self.parent_node.as_u32() != 0 { + self.parenting.insert(item, self.parent_node); + } } } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 28f7574f66fc7..42a06c968c754 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -174,8 +174,12 @@ pub fn provide(providers: &mut Providers) { let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner; HirId { owner: parent_owner_id, - local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting - [&owner_id.def_id], + local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id] + .unwrap() + .parenting + .get(&owner_id.def_id) + .copied() + .unwrap_or(ItemLocalId::from_u32(0)), } }) }; From e3025d6a55b1381802e8d6a85cbd4491dcaaa81d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Mar 2024 12:03:29 -0400 Subject: [PATCH 25/38] Stop chopping off args for no reason --- .../rustc_trait_selection/src/traits/util.rs | 2 -- .../in-trait/span-bug-issue-121457.rs | 1 + .../in-trait/span-bug-issue-121457.stderr | 19 ++++++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 466a53d8ce029..50cc0ed90fb2f 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -381,8 +381,6 @@ pub fn check_args_compatible<'tcx>( } let generics = tcx.generics_of(assoc_item.def_id); - // Chop off any additional args (RPITIT) args - let args = &args[0..generics.count().min(args.len())]; check_args_compatible_inner(tcx, generics, args) } diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs index ab21dae7dc50d..7a51037324f28 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs @@ -14,6 +14,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR `()` is not an iterator + //~| WARNING impl trait in impl method signature does not match trait method signature } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr index d8a2eef94a180..67c4df0f3a9eb 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr @@ -32,7 +32,24 @@ LL | fn iter(&self) -> impl for<'missing> Iterator $DIR/span-bug-issue-121457.rs:13:51 + | +LL | fn iter(&self) -> impl Iterator; + | ------------- return type from trait method defined here +... +LL | fn iter(&self) -> impl for<'missing> Iterator> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 for more information + = note: `#[warn(refining_impl_trait_reachable)]` on by default +help: replace the return type so that it matches the trait + | +LL | fn iter(&self) -> impl Iterator {} + | ~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0195, E0277, E0582. For more information about an error, try `rustc --explain E0195`. From c9f852979359779ec1c91b91eb477272308a864f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Mar 2024 12:05:14 -0400 Subject: [PATCH 26/38] Uplift and start using check_args_compatible more liberally --- compiler/rustc_middle/src/ty/context.rs | 93 +++++++++++++++---- compiler/rustc_middle/src/ty/sty.rs | 34 +++---- .../src/solve/normalizes_to/mod.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 8 +- .../src/traits/project.rs | 3 +- .../rustc_trait_selection/src/traits/util.rs | 40 -------- compiler/rustc_ty_utils/src/opaque_types.rs | 3 +- 7 files changed, 95 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 23881c4b124da..df792b87056c0 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1961,33 +1961,90 @@ impl<'tcx> TyCtxt<'tcx> { if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } + pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool { + self.check_args_compatible_inner(def_id, args, false) + } + + fn check_args_compatible_inner( + self, + def_id: DefId, + args: &'tcx [ty::GenericArg<'tcx>], + nested: bool, + ) -> bool { + let generics = self.generics_of(def_id); + + // IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs + // (namely: opaques, i.e. ATPITs) do not. + let own_args = if !nested + && let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + if generics.params.len() + 1 != args.len() { + return false; + } + + if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) { + return false; + } + + &args[1..] + } else { + if generics.count() != args.len() { + return false; + } + + let (parent_args, own_args) = args.split_at(generics.parent_count); + + if let Some(parent) = generics.parent + && !self.check_args_compatible_inner(parent, parent_args, true) + { + return false; + } + + own_args + }; + + for (param, arg) in std::iter::zip(&generics.params, own_args) { + match (¶m.kind, arg.unpack()) { + (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) + | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) + | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + _ => return false, + } + } + + true + } + + pub fn assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { + if !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!() + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); + } + } + } + #[inline(always)] pub(crate) fn check_and_mk_args( self, _def_id: DefId, args: impl IntoIterator>>, ) -> GenericArgsRef<'tcx> { - let args = args.into_iter().map(Into::into); + let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); #[cfg(debug_assertions)] { - let generics = self.generics_of(_def_id); - - let n = if let DefKind::AssocTy = self.def_kind(_def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id)) - { - // If this is an inherent projection. - generics.params.len() + 1 - } else { - generics.count() - }; - assert_eq!( - (n, Some(n)), - args.size_hint(), - "wrong number of generic parameters for {_def_id:?}: {:?}", - args.collect::>(), - ); + self.assert_args_compatible(_def_id, args); } - self.mk_args_from_iter(args) + args } #[inline] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b5e619f1e2a3c..dc1ad1da7e1fb 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1624,13 +1624,9 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { - debug_assert_eq!( - tcx.generics_of(def.did()).count(), - args.len(), - "wrong number of args for ADT: {:#?} vs {:#?}", - tcx.generics_of(def.did()).params, - args - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def.did(), args); + } Ty::new(tcx, Adt(def, args)) } @@ -1711,11 +1707,9 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, - "closure constructed with incorrect generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, closure_args); + } Ty::new(tcx, Closure(def_id, closure_args)) } @@ -1725,11 +1719,9 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, - "closure constructed with incorrect generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, closure_args); + } Ty::new(tcx, CoroutineClosure(def_id, closure_args)) } @@ -1739,11 +1731,9 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, coroutine_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - coroutine_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, - "coroutine constructed with incorrect number of generic parameters" - ); + if cfg!(debug_assertions) { + tcx.assert_args_compatible(def_id, coroutine_args); + } Ty::new(tcx, Coroutine(def_id, coroutine_args)) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 6668889323512..d8aeadd07b3d9 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -1,4 +1,4 @@ -use crate::traits::{check_args_compatible, specialization_graph}; +use crate::traits::specialization_graph; use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; @@ -247,7 +247,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { assoc_def.defining_node, ); - if !check_args_compatible(tcx, assoc_def.item, args) { + if !tcx.check_args_compatible(assoc_def.item.def_id, args) { return error_response( ecx, "associated item has mismatched generic item arguments", diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 3ab4872fffee8..2c8116b779b45 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -61,12 +61,12 @@ pub use self::specialize::{ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; -pub use self::util::{ - check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds, - transitive_bounds_that_define_assoc_item, SupertraitDefIds, -}; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{ + supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, + SupertraitDefIds, +}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; pub use rustc_infer::traits::*; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c33e24b1094d4..9d744d9a03214 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2,7 +2,6 @@ use std::ops::ControlFlow; -use super::check_args_compatible; use super::specialization_graph; use super::translate_args; use super::util; @@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { ty.map_bound(|ty| ty.into()) }; - if !check_args_compatible(tcx, assoc_ty.item, args) { + if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( tcx, obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 50cc0ed90fb2f..d29fc7921bcbd 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -344,46 +344,6 @@ pub enum TupleArgumentsFlag { No, } -// Verify that the trait item and its implementation have compatible args lists -pub fn check_args_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - assoc_item: ty::AssocItem, - args: ty::GenericArgsRef<'tcx>, -) -> bool { - fn check_args_compatible_inner<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> bool { - if generics.count() != args.len() { - return false; - } - - let (parent_args, own_args) = args.split_at(generics.parent_count); - - if let Some(parent) = generics.parent - && let parent_generics = tcx.generics_of(parent) - && !check_args_compatible_inner(tcx, parent_generics, parent_args) - { - return false; - } - - for (param, arg) in std::iter::zip(&generics.params, own_args) { - match (¶m.kind, arg.unpack()) { - (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} - _ => return false, - } - } - - true - } - - let generics = tcx.generics_of(assoc_item.def_id); - check_args_compatible_inner(tcx, generics, args) -} - /// Executes `f` on `value` after replacing all escaping bound variables with placeholders /// and then replaces these placeholders with the original bound variables in the result. /// diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index fc16edc6d1309..a652bb781161c 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -7,7 +7,6 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_trait_selection::traits::check_args_compatible; use crate::errors::{DuplicateArg, NotParam}; @@ -250,7 +249,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { ty::GenericArgs::identity_for_item(self.tcx, parent), ); - if check_args_compatible(self.tcx, assoc, impl_args) { + if self.tcx.check_args_compatible(assoc.def_id, impl_args) { self.tcx .type_of(assoc.def_id) .instantiate(self.tcx, impl_args) From 657dadf2cc20d7d48643a300c23388ef026c8c83 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Mar 2024 12:10:47 -0400 Subject: [PATCH 27/38] Simplify some cfging --- compiler/rustc_middle/src/ty/context.rs | 12 +++++++----- compiler/rustc_middle/src/ty/sty.rs | 16 ++++------------ 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index df792b87056c0..09fae0fdd3515 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2016,7 +2016,12 @@ impl<'tcx> TyCtxt<'tcx> { true } - pub fn assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { + pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { + #[cfg(not(debug_assertions))] + { + return; + } + if !self.check_args_compatible(def_id, args) { if let DefKind::AssocTy = self.def_kind(def_id) && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) @@ -2040,10 +2045,7 @@ impl<'tcx> TyCtxt<'tcx> { args: impl IntoIterator>>, ) -> GenericArgsRef<'tcx> { let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); - #[cfg(debug_assertions)] - { - self.assert_args_compatible(_def_id, args); - } + self.debug_assert_args_compatible(_def_id, args); args } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index dc1ad1da7e1fb..30997d1350d9d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1624,9 +1624,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { - if cfg!(debug_assertions) { - tcx.assert_args_compatible(def.did(), args); - } + tcx.debug_assert_args_compatible(def.did(), args); Ty::new(tcx, Adt(def, args)) } @@ -1707,9 +1705,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - if cfg!(debug_assertions) { - tcx.assert_args_compatible(def_id, closure_args); - } + tcx.debug_assert_args_compatible(def_id, closure_args); Ty::new(tcx, Closure(def_id, closure_args)) } @@ -1719,9 +1715,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - if cfg!(debug_assertions) { - tcx.assert_args_compatible(def_id, closure_args); - } + tcx.debug_assert_args_compatible(def_id, closure_args); Ty::new(tcx, CoroutineClosure(def_id, closure_args)) } @@ -1731,9 +1725,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, coroutine_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - if cfg!(debug_assertions) { - tcx.assert_args_compatible(def_id, coroutine_args); - } + tcx.debug_assert_args_compatible(def_id, coroutine_args); Ty::new(tcx, Coroutine(def_id, coroutine_args)) } From 03163ef9d99a2717edd976174a847293b6f1c8cb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Mar 2024 12:17:21 -0400 Subject: [PATCH 28/38] Don't fill non-ty args with ty::Error --- .../src/hir_ty_lowering/object_safety.rs | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index d3ca35ba481e3..97ba946b7e013 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -6,9 +6,10 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{DynKind, ToPredicate}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; @@ -228,12 +229,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if arg == dummy_self.into() { let param = &generics.params[index]; missing_type_params.push(param.name); - return Ty::new_misc_error(tcx).into(); + Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { references_self = true; - return Ty::new_misc_error(tcx).into(); + let guar = tcx.dcx().span_delayed_bug( + span, + "trait object trait bounds reference `Self`", + ); + replace_dummy_self_with_error(tcx, arg, guar) + } else { + arg } - arg }) .collect(); let args = tcx.mk_args(&args); @@ -288,18 +294,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let guar = tcx .dcx() .span_delayed_bug(span, "trait object projection bounds reference `Self`"); - let args: Vec<_> = b - .projection_ty - .args - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return Ty::new_error(tcx, guar).into(); - } - arg - }) - .collect(); - b.projection_ty.args = tcx.mk_args(&args); + b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar); } ty::ExistentialProjection::erase_self_ty(tcx, b) @@ -357,3 +352,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } } + +fn replace_dummy_self_with_error<'tcx, T: TypeFoldable>>( + tcx: TyCtxt<'tcx>, + t: T, + guar: ErrorGuaranteed, +) -> T { + t.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| { + if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty } + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }) +} From bd8ca780a513a42fe635c6d099ec6f4ba5c22221 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Mar 2024 12:34:15 -0400 Subject: [PATCH 29/38] Fix up error message for debug_assert_args_compat for IATs --- compiler/rustc_middle/src/ty/context.rs | 50 +++++++++++++++---------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 09fae0fdd3515..b8d68c1b8be4b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2016,24 +2016,36 @@ impl<'tcx> TyCtxt<'tcx> { true } + /// With `cfg(debug_assertions)`, assert that args are compatible with their generics, + /// and print out the args if not. pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { - #[cfg(not(debug_assertions))] - { - return; - } - - if !self.check_args_compatible(def_id, args) { - if let DefKind::AssocTy = self.def_kind(def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) - { - bug!() - } else { - bug!( - "args not compatible with generics for {}: args={:#?}, generics={:#?}", - self.def_path_str(def_id), - args, - ty::GenericArgs::identity_for_item(self, def_id) - ); + if cfg!(debug_assertions) { + if !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + // Make `[Self, GAT_ARGS...]` (this could be simplified) + self.mk_args_from_iter( + [self.types.self_param.into()].into_iter().chain( + self.generics_of(def_id) + .own_args(ty::GenericArgs::identity_for_item(self, def_id)) + .iter() + .copied() + ) + ) + ); + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); + } } } } @@ -2041,11 +2053,11 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub(crate) fn check_and_mk_args( self, - _def_id: DefId, + def_id: DefId, args: impl IntoIterator>>, ) -> GenericArgsRef<'tcx> { let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); - self.debug_assert_args_compatible(_def_id, args); + self.debug_assert_args_compatible(def_id, args); args } From b40ea03f8a9a94c294679b9f261b86ded120454f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Apr 2024 17:49:59 +0300 Subject: [PATCH 30/38] 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 31/38] 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 From ce4cc9df960ec5c0a840d75e7e57284bfd80d25d Mon Sep 17 00:00:00 2001 From: Zander Milroy Date: Tue, 2 Apr 2024 20:05:01 -0400 Subject: [PATCH 32/38] Use SVG logos in the README.md. These should likely eventually reference the rust-lang.org site instead of raw.githubusercontent.com --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c3b72062d8838..3690a9c93c528 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@
- - + + The Rust Programming Language: A language empowering everyone to build reliable and efficient software From 9a7b1762279eaa95d0289760d3b859fbbc9221f1 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 31 Mar 2024 19:23:57 -0500 Subject: [PATCH 33/38] Update f16 and f128 tests to run on both 2015 and 2018 editions Reproduce the bug from that indicates this feature gate hits edition-dependent resolution paths. Resolution changed in edition 2018, so test that as well. --- ....stderr => feature-gate-f128.e2015.stderr} | 10 ++-- .../feature-gate-f128.e2018.stderr | 53 +++++++++++++++++++ tests/ui/feature-gates/feature-gate-f128.rs | 4 ++ ...6.stderr => feature-gate-f16.e2015.stderr} | 10 ++-- .../feature-gate-f16.e2018.stderr | 53 +++++++++++++++++++ tests/ui/feature-gates/feature-gate-f16.rs | 4 ++ .../primitive-f16-f128-shadowed-mod.rs | 19 +++++++ .../ui/resolve/primitive-f16-f128-shadowed.rs | 3 ++ 8 files changed, 146 insertions(+), 10 deletions(-) rename tests/ui/feature-gates/{feature-gate-f128.stderr => feature-gate-f128.e2015.stderr} (91%) create mode 100644 tests/ui/feature-gates/feature-gate-f128.e2018.stderr rename tests/ui/feature-gates/{feature-gate-f16.stderr => feature-gate-f16.e2015.stderr} (91%) create mode 100644 tests/ui/feature-gates/feature-gate-f16.e2018.stderr create mode 100644 tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs diff --git a/tests/ui/feature-gates/feature-gate-f128.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr similarity index 91% rename from tests/ui/feature-gates/feature-gate-f128.stderr rename to tests/ui/feature-gates/feature-gate-f128.e2015.stderr index 299375c9aed90..a1b28f5b9bd14 100644 --- a/tests/ui/feature-gates/feature-gate-f128.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:3:10 + --> $DIR/feature-gate-f128.rs:11:10 | LL | const A: f128 = 10.0; | ^^^^ @@ -9,7 +9,7 @@ LL | const A: f128 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:6:12 + --> $DIR/feature-gate-f128.rs:14:12 | LL | let a: f128 = 100.0; | ^^^^ @@ -19,7 +19,7 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:11:11 + --> $DIR/feature-gate-f128.rs:19:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:14:8 + --> $DIR/feature-gate-f128.rs:22:8 | LL | a: f128, | ^^^^ @@ -39,7 +39,7 @@ LL | a: f128, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:7:13 + --> $DIR/feature-gate-f128.rs:15:13 | LL | let b = 0.0f128; | ^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr new file mode 100644 index 0000000000000..a1b28f5b9bd14 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -0,0 +1,53 @@ +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:11:10 + | +LL | const A: f128 = 10.0; + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:14:12 + | +LL | let a: f128 = 100.0; + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:19:11 + | +LL | fn foo(a: f128) {} + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:22:8 + | +LL | a: f128, + | ^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f128` is unstable + --> $DIR/feature-gate-f128.rs:15:13 + | +LL | let b = 0.0f128; + | ^^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f128)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f128.rs b/tests/ui/feature-gates/feature-gate-f128.rs index 7f60fb6afa080..d25b6dde4ee47 100644 --- a/tests/ui/feature-gates/feature-gate-f128.rs +++ b/tests/ui/feature-gates/feature-gate-f128.rs @@ -1,3 +1,7 @@ +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + #![allow(unused)] const A: f128 = 10.0; //~ ERROR the type `f128` is unstable diff --git a/tests/ui/feature-gates/feature-gate-f16.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr similarity index 91% rename from tests/ui/feature-gates/feature-gate-f16.stderr rename to tests/ui/feature-gates/feature-gate-f16.e2015.stderr index e54b54a47bde6..b58331b2782b3 100644 --- a/tests/ui/feature-gates/feature-gate-f16.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:3:10 + --> $DIR/feature-gate-f16.rs:11:10 | LL | const A: f16 = 10.0; | ^^^ @@ -9,7 +9,7 @@ LL | const A: f16 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:6:12 + --> $DIR/feature-gate-f16.rs:14:12 | LL | let a: f16 = 100.0; | ^^^ @@ -19,7 +19,7 @@ LL | let a: f16 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:11:11 + --> $DIR/feature-gate-f16.rs:19:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:14:8 + --> $DIR/feature-gate-f16.rs:22:8 | LL | a: f16, | ^^^ @@ -39,7 +39,7 @@ LL | a: f16, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:7:13 + --> $DIR/feature-gate-f16.rs:15:13 | LL | let b = 0.0f16; | ^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr new file mode 100644 index 0000000000000..b58331b2782b3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -0,0 +1,53 @@ +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:11:10 + | +LL | const A: f16 = 10.0; + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:14:12 + | +LL | let a: f16 = 100.0; + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:19:11 + | +LL | fn foo(a: f16) {} + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:22:8 + | +LL | a: f16, + | ^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the type `f16` is unstable + --> $DIR/feature-gate-f16.rs:15:13 + | +LL | let b = 0.0f16; + | ^^^^^^ + | + = note: see issue #116909 for more information + = help: add `#![feature(f16)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-f16.rs b/tests/ui/feature-gates/feature-gate-f16.rs index 31d8f87f3ba6d..af906d71f5fe2 100644 --- a/tests/ui/feature-gates/feature-gate-f16.rs +++ b/tests/ui/feature-gates/feature-gate-f16.rs @@ -1,3 +1,7 @@ +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + #![allow(unused)] const A: f16 = 10.0; //~ ERROR the type `f16` is unstable diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs new file mode 100644 index 0000000000000..93f518201013a --- /dev/null +++ b/tests/ui/resolve/primitive-f16-f128-shadowed-mod.rs @@ -0,0 +1,19 @@ +//@ compile-flags: --crate-type=lib +//@ check-pass +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 + +// Verify that gates for the `f16` and `f128` features do not apply to user modules +// See + +mod f16 { + pub fn a16() {} +} + +mod f128 { + pub fn a128() {} +} + +pub use f128::a128; +pub use f16::a16; diff --git a/tests/ui/resolve/primitive-f16-f128-shadowed.rs b/tests/ui/resolve/primitive-f16-f128-shadowed.rs index ed3fb44b256df..38c7e15bf5a20 100644 --- a/tests/ui/resolve/primitive-f16-f128-shadowed.rs +++ b/tests/ui/resolve/primitive-f16-f128-shadowed.rs @@ -1,5 +1,8 @@ //@ compile-flags: --crate-type=lib //@ check-pass +//@ revisions: e2015 e2018 +// +//@[e2018] edition:2018 // Verify that gates for the `f16` and `f128` features do not apply to user types From 5afe072ead1154f9817ee610e3e60345507c7625 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 3 Apr 2024 14:17:23 -0400 Subject: [PATCH 34/38] Fix f16 and f128 feature gates in editions other than 2015 Fixes https://github.com/rust-lang/rust/issues/123282 Co-authored-by: Vadim Petrochenkov --- compiler/rustc_resolve/src/ident.rs | 2 ++ tests/ui/feature-gates/feature-gate-f128.e2015.stderr | 10 +++++----- tests/ui/feature-gates/feature-gate-f128.e2018.stderr | 10 +++++----- tests/ui/feature-gates/feature-gate-f16.e2015.stderr | 10 +++++----- tests/ui/feature-gates/feature-gate-f16.e2018.stderr | 10 +++++----- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b24ed573ff97d..43a43e01a9adf 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -605,6 +605,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && !this.tcx.features().f16 && !ident.span.allows_unstable(sym::f16) && finalize.is_some() + && innermost_result.is_none() { feature_err( this.tcx.sess, @@ -618,6 +619,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && !this.tcx.features().f128 && !ident.span.allows_unstable(sym::f128) && finalize.is_some() + && innermost_result.is_none() { feature_err( this.tcx.sess, diff --git a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr index a1b28f5b9bd14..771aee79dce16 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:11:10 + --> $DIR/feature-gate-f128.rs:7:10 | LL | const A: f128 = 10.0; | ^^^^ @@ -9,7 +9,7 @@ LL | const A: f128 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:14:12 + --> $DIR/feature-gate-f128.rs:10:12 | LL | let a: f128 = 100.0; | ^^^^ @@ -19,7 +19,7 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:19:11 + --> $DIR/feature-gate-f128.rs:15:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:22:8 + --> $DIR/feature-gate-f128.rs:18:8 | LL | a: f128, | ^^^^ @@ -39,7 +39,7 @@ LL | a: f128, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:15:13 + --> $DIR/feature-gate-f128.rs:11:13 | LL | let b = 0.0f128; | ^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr index a1b28f5b9bd14..771aee79dce16 100644 --- a/tests/ui/feature-gates/feature-gate-f128.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f128.e2018.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:11:10 + --> $DIR/feature-gate-f128.rs:7:10 | LL | const A: f128 = 10.0; | ^^^^ @@ -9,7 +9,7 @@ LL | const A: f128 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:14:12 + --> $DIR/feature-gate-f128.rs:10:12 | LL | let a: f128 = 100.0; | ^^^^ @@ -19,7 +19,7 @@ LL | let a: f128 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:19:11 + --> $DIR/feature-gate-f128.rs:15:11 | LL | fn foo(a: f128) {} | ^^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f128) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:22:8 + --> $DIR/feature-gate-f128.rs:18:8 | LL | a: f128, | ^^^^ @@ -39,7 +39,7 @@ LL | a: f128, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f128` is unstable - --> $DIR/feature-gate-f128.rs:15:13 + --> $DIR/feature-gate-f128.rs:11:13 | LL | let b = 0.0f128; | ^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr index b58331b2782b3..2bb3b59465a08 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2015.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2015.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:11:10 + --> $DIR/feature-gate-f16.rs:7:10 | LL | const A: f16 = 10.0; | ^^^ @@ -9,7 +9,7 @@ LL | const A: f16 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:14:12 + --> $DIR/feature-gate-f16.rs:10:12 | LL | let a: f16 = 100.0; | ^^^ @@ -19,7 +19,7 @@ LL | let a: f16 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:15:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:18:8 | LL | a: f16, | ^^^ @@ -39,7 +39,7 @@ LL | a: f16, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:15:13 + --> $DIR/feature-gate-f16.rs:11:13 | LL | let b = 0.0f16; | ^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr index b58331b2782b3..2bb3b59465a08 100644 --- a/tests/ui/feature-gates/feature-gate-f16.e2018.stderr +++ b/tests/ui/feature-gates/feature-gate-f16.e2018.stderr @@ -1,5 +1,5 @@ error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:11:10 + --> $DIR/feature-gate-f16.rs:7:10 | LL | const A: f16 = 10.0; | ^^^ @@ -9,7 +9,7 @@ LL | const A: f16 = 10.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:14:12 + --> $DIR/feature-gate-f16.rs:10:12 | LL | let a: f16 = 100.0; | ^^^ @@ -19,7 +19,7 @@ LL | let a: f16 = 100.0; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:19:11 + --> $DIR/feature-gate-f16.rs:15:11 | LL | fn foo(a: f16) {} | ^^^ @@ -29,7 +29,7 @@ LL | fn foo(a: f16) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:22:8 + --> $DIR/feature-gate-f16.rs:18:8 | LL | a: f16, | ^^^ @@ -39,7 +39,7 @@ LL | a: f16, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the type `f16` is unstable - --> $DIR/feature-gate-f16.rs:15:13 + --> $DIR/feature-gate-f16.rs:11:13 | LL | let b = 0.0f16; | ^^^^^^ From 4fa5fb684e891978303db0b8f100fab1e19eb06d Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 3 Apr 2024 22:27:13 +0100 Subject: [PATCH 35/38] move leak check out of candidate evaluation this prevents higher ranked goals from guiding selection --- .../src/traits/select/mod.rs | 76 +++++++++--- .../candidate-from-env-universe-err-1.rs | 28 +++++ .../candidate-from-env-universe-err-1.stderr | 26 ++++ ...ate-from-env-universe-err-2.current.stderr | 25 ++++ ...didate-from-env-universe-err-2.next.stderr | 19 +++ ...ndidate-from-env-universe-err-2.old.stderr | 26 ++++ .../candidate-from-env-universe-err-2.rs | 20 +++ ...om-env-universe-err-project.current.stderr | 54 ++++++++ ...-from-env-universe-err-project.next.stderr | 67 ++++++++++ ...candidate-from-env-universe-err-project.rs | 61 +++++++++ .../leak-check-in-selection-1.rs} | 0 .../leak-check-in-selection-2.next.stderr | 23 ++++ .../leak-check-in-selection-2.old.stderr | 23 ++++ .../leak-check/leak-check-in-selection-2.rs | 18 +++ .../leak-check-in-selection-3.next.stderr | 35 ++++++ .../leak-check-in-selection-3.old.stderr | 48 ++++++++ .../leak-check/leak-check-in-selection-3.rs | 39 ++++++ .../leak-check-in-selection-4-hr-nested.rs | 29 +++++ ...igher-ranker-supertraits-transitive.stderr | 22 +--- .../hrtb-higher-ranker-supertraits.rs | 32 ++--- .../hrtb-higher-ranker-supertraits.stderr | 86 +++++-------- .../{issue-30786.rs => issue-30786-1.rs} | 20 +-- .../trait-bounds/issue-30786-1.stderr | 27 ++++ .../trait-bounds/issue-30786-2.rs | 116 ++++++++++++++++++ .../trait-bounds/issue-30786-2.stderr | 27 ++++ .../trait-bounds/issue-30786.stderr | 51 -------- tests/ui/implied-bounds/issue-100690.rs | 11 +- tests/ui/implied-bounds/issue-100690.stderr | 49 +++++--- 28 files changed, 865 insertions(+), 193 deletions(-) create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr create mode 100644 tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs rename tests/ui/higher-ranked/{leak-check-in-selection.rs => leak-check/leak-check-in-selection-1.rs} (100%) create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs create mode 100644 tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs rename tests/ui/higher-ranked/trait-bounds/{issue-30786.rs => issue-30786-1.rs} (86%) create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3fbe8e39d1e3f..926044bd6a803 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths; mod candidate_assembly; mod confirmation; +/// Whether to consider the binder of higher ranked goals for the `leak_check` when +/// evaluating higher-ranked goals. See #119820 for more info. +/// +/// While this is a bit hacky, it is necessary to match the behavior of the new solver: +/// We eagerly instantiate binders in the new solver, outside of candidate selection, so +/// the leak check inside of candidates does not consider any bound vars from the higher +/// ranked goal. However, we do exit the binder once we're completely finished with a goal, +/// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail. +#[derive(Debug, Copy, Clone)] +enum LeakCheckHigherRankedGoal { + No, + Yes, +} + #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum IntercrateAmbiguityCause<'tcx> { DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, @@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, c)?.may_apply() { + if self + .evaluate_candidate(stack, c, LeakCheckHigherRankedGoal::No)? + .may_apply() + { no_candidates_apply = false; break; } @@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { + .map(|c| match self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::No) { Ok(eval) if eval.may_apply() => { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } @@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { debug_assert!(!self.infcx.next_trait_solver()); - self.evaluation_probe(|this| { + self.evaluation_probe(|this, _outer_universe| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); let mut result = this.evaluate_predicate_recursively( @@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Computes the evaluation result of `op`, discarding any constraints. + /// + /// This also runs for leak check to allow higher ranked region errors to impact + /// selection. By default it checks for leaks from all universes created inside of + /// `op`, but this can be overwritten if necessary. fn evaluation_probe( &mut self, - op: impl FnOnce(&mut Self) -> Result, + op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result, ) -> Result { self.infcx.probe(|snapshot| -> Result { - let outer_universe = self.infcx.universe(); - let result = op(self)?; + let mut outer_universe = self.infcx.universe(); + let result = op(self, &mut outer_universe)?; match self.infcx.leak_check(outer_universe, Some(snapshot)) { Ok(()) => {} @@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - /// Evaluates the predicates in `predicates` recursively. Note that - /// this applies projections in the predicates, and therefore + /// Evaluates the predicates in `predicates` recursively. This may + /// guide inference. If this is not desired, run it inside of a /// is run within an inference probe. + /// `probe`. #[instrument(skip(self, stack), level = "debug")] fn evaluate_predicates_recursively<'o, I>( &mut self, @@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(Some(c)) => self.evaluate_candidate(stack, &c, LeakCheckHigherRankedGoal::Yes), Ok(None) => Ok(EvaluatedToAmbig), Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), Err(..) => Ok(EvaluatedToErr), @@ -1219,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Further evaluates `candidate` to decide whether all type parameters match and whether nested /// obligations are met. Returns whether `candidate` remains viable after this further /// scrutiny. + /// + /// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal + /// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for + /// more info. #[instrument( level = "debug", skip(self, stack), @@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, + leak_check_higher_ranked_goal: LeakCheckHigherRankedGoal, ) -> Result { - let mut result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { + let mut result = self.evaluation_probe(|this, outer_universe| { + // We eagerly instantiate higher ranked goals to prevent universe errors + // from impacting candidate selection. This matches the behavior of the new + // solver. This slightly weakens type inference. + // + // In case there are no unresolved type or const variables this + // should still not be necessary to select a unique impl as any overlap + // relying on a universe error from higher ranked goals should have resulted + // in an overlap error in coherence. + let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + match leak_check_higher_ranked_goal { + LeakCheckHigherRankedGoal::No => *outer_universe = self.infcx.universe(), + LeakCheckHigherRankedGoal::Yes => {} + } + + match this.confirm_candidate(&obligation, candidate.clone()) { Ok(selection) => { debug!(?selection); this.evaluate_predicates_recursively( @@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.evaluation_probe(|this, outer_universe| { + // Eagerly instantiate higher ranked goals. + // + // See the comment in `evaluate_candidate` to see why. + let p = self.infcx.enter_forall_and_leak_universe(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + *outer_universe = self.infcx.universe(); + match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) { Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations), Err(()) => Ok(EvaluatedToErr), } diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs new file mode 100644 index 0000000000000..b448f0bdc7778 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.rs @@ -0,0 +1,28 @@ +// cc #119820 + +trait Trait {} + +impl Trait for &T {} +impl Trait for u32 {} + +fn hr_bound() +where + for<'a> &'a T: Trait, +{ +} + +fn foo() +where + T: Trait, + for<'a> &'a &'a T: Trait, +{ + // We get a universe error when using the `param_env` candidate + // but are able to successfully use the impl candidate. Without + // the leak check both candidates may apply and we prefer the + // `param_env` candidate in winnowing. + hr_bound::<&T>(); + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR implementation of `Trait` is not general enough +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr new file mode 100644 index 0000000000000..febe252d7d1d5 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-1.stderr @@ -0,0 +1,26 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/candidate-from-env-universe-err-1.rs:23:5 + | +LL | hr_bound::<&T>(); + | ^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | T: Trait + 'static, + | +++++++++ + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-1.rs:23:5 + | +LL | hr_bound::<&T>(); + | ^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `Trait` would have to be implemented for the type `&'0 &T`, for any lifetime `'0`... + = note: ...but `Trait` is actually implemented for the type `&'1 &'1 T`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr new file mode 100644 index 0000000000000..22ce87c024861 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.current.stderr @@ -0,0 +1,25 @@ +error: lifetime may not live long enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + | -- lifetime `'a` defined here +LL | impl_hr::(); + | ^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0, '_>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'1, '_>`, for some specific lifetime `'1` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr new file mode 100644 index 0000000000000..a61bc748bea2d --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a, '_>` is not implemented for `T` + | +note: required by a bound in `impl_hr` + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr` +help: consider further restricting this bound + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() { + | +++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr new file mode 100644 index 0000000000000..29a72b1c1b641 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.old.stderr @@ -0,0 +1,26 @@ +error: lifetime may not live long enough + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + | -- lifetime `'a` defined here +LL | impl_hr::(); + | ^^^^^^^^^^^^ requires that `'a` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/candidate-from-env-universe-err-2.rs:11:19 + | +LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-2.rs:14:5 + | +LL | impl_hr::(); + | ^^^^^^^^^^^^ one type is more general than the other + | + = note: expected trait `for<'a> Trait<'a, '_>` + found trait `for<'b> Trait<'_, 'b>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs new file mode 100644 index 0000000000000..56fa70469ccf8 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.rs @@ -0,0 +1,20 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver + +// cc #119820 + +trait Trait<'a, 'b> {} + +trait OtherTrait<'b> {} +impl<'a, 'b, T: OtherTrait<'b>> Trait<'a, 'b> for T {} + +fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} + +fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static>>() { + impl_hr::(); + //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a, '_>` is not satisfied + //[current]~^^ERROR lifetime may not live long enough + //[current]~| ERROR implementation of `Trait` is not general enough +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr new file mode 100644 index 0000000000000..16a6f549882e5 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr @@ -0,0 +1,54 @@ +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-project.rs:31:5 + | +LL | trait_bound::(); + | ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'static>` + +error: implementation of `Trait` is not general enough + --> $DIR/candidate-from-env-universe-err-project.rs:41:5 + | +LL | projection_bound::(); + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough + | + = note: `T` must implement `Trait<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Trait<'static>` + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:41:5 + | +LL | projection_bound::(); + | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` +note: the lifetime requirement is introduced here + --> $DIR/candidate-from-env-universe-err-project.rs:21:42 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` + +error[E0308]: mismatched types + --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `>::Assoc` + found associated type `>::Assoc` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr new file mode 100644 index 0000000000000..57f2184b611e9 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -0,0 +1,67 @@ +error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied + --> $DIR/candidate-from-env-universe-err-project.rs:31:19 + | +LL | trait_bound::(); + | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` + | +note: required by a bound in `trait_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:20:19 + | +LL | fn trait_bound Trait<'a>>() {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound` +help: consider further restricting this bound + | +LL | fn function1 + for<'a> Trait<'a>>() { + | +++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied + --> $DIR/candidate-from-env-universe-err-project.rs:41:24 + | +LL | projection_bound::(); + | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` + | +note: required by a bound in `projection_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:21:24 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` +help: consider further restricting this bound + | +LL | fn function2 + for<'a> Trait<'a>>() { + | +++++++++++++++++++ + +error[E0271]: type mismatch resolving `>::Assoc == usize` + --> $DIR/candidate-from-env-universe-err-project.rs:41:24 + | +LL | projection_bound::(); + | ^ type mismatch resolving `>::Assoc == usize` + | +note: types differ + --> $DIR/candidate-from-env-universe-err-project.rs:17:18 + | +LL | type Assoc = usize; + | ^^^^^ +note: required by a bound in `projection_bound` + --> $DIR/candidate-from-env-universe-err-project.rs:21:42 + | +LL | fn projection_bound Trait<'a, Assoc = usize>>() {} + | ^^^^^^^^^^^^^ required by this bound in `projection_bound` + +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + | +LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs new file mode 100644 index 0000000000000..7e5e5f3a8472c --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -0,0 +1,61 @@ +//@ revisions: next current +//@[next] compile-flags: -Znext-solver + +// cc #119820 the previous behavior here was inconsistent as we discarded +// the where-bound candidate for trait goals due to the leak check, but did +// not do so for projection candidates and during normalization. +// +// FIXME(-Znext-solver): We currently prefer the impl over the where-bound +// for trait goals because the impl does not result in any constraints. +// +// This results in an inconsistency between `Trait` and `Projection` goals as +// normalizing always constraints the normalized-to term. +trait Trait<'a> { + type Assoc; +} +impl<'a, T> Trait<'a> for T { + type Assoc = usize; +} + +fn trait_bound Trait<'a>>() {} +fn projection_bound Trait<'a, Assoc = usize>>() {} + +// We use a function with a trivial where-bound which is more +// restrictive than the impl. +fn function1>() { + // ok + // + // Proving `for<'a> T: Trait<'a>` using the where-bound results + // in a leak check failure, so we use the more general impl, + // causing this to succeed. + trait_bound::(); + //[current]~^ ERROR mismatched types +} + +fn function2>() { + // err + // + // Proving the `Projection` goal `for<'a> T: Trait<'a, Assoc = usize>` + // does not use the leak check when trying the where-bound, causing us + // to prefer it over the impl, resulting in a placeholder error. + projection_bound::(); + //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` + //[current]~^^ ERROR mismatched types + //[current]~| ERROR mismatched types +} + +fn function3>() { + // err + // + // Trying to normalize the type `for<'a> fn(>::Assoc)` + // only gets to `>::Assoc` once `'a` has been already + // instantiated, causing us to prefer the where-bound over the impl + // resulting in a placeholder error. Even if were were to also use the + // leak check during candidate selection for normalization, this + // case would still not compile. + let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); + //[current]~^ ERROR mismatched types + //[current]~| ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs similarity index 100% rename from tests/ui/higher-ranked/leak-check-in-selection.rs rename to tests/ui/higher-ranked/leak-check/leak-check-in-selection-1.rs diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr new file mode 100644 index 0000000000000..a840304e49c1f --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.next.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-2.rs:16:5 + | +LL | impls_trait::<(), _>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found + --> $DIR/leak-check-in-selection-2.rs:9:1 + | +LL | impl<'a> Trait<&'a str, &'a str> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl<'a> Trait<&'a str, String> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-2.rs:13:19 + | +LL | fn impls_trait Trait<&'a str, U>, U>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr new file mode 100644 index 0000000000000..a840304e49c1f --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.old.stderr @@ -0,0 +1,23 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-2.rs:16:5 + | +LL | impls_trait::<(), _>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `impls_trait` + | +note: multiple `impl`s satisfying `for<'a> (): Trait<&'a str, _>` found + --> $DIR/leak-check-in-selection-2.rs:9:1 + | +LL | impl<'a> Trait<&'a str, &'a str> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | impl<'a> Trait<&'a str, String> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_trait` + --> $DIR/leak-check-in-selection-2.rs:13:19 + | +LL | fn impls_trait Trait<&'a str, U>, U>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs new file mode 100644 index 0000000000000..48dd569f201b9 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-2.rs @@ -0,0 +1,18 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// cc #119820 + +trait Trait {} + +// using this impl results in a higher-ranked region error. +impl<'a> Trait<&'a str, &'a str> for () {} + +impl<'a> Trait<&'a str, String> for () {} + +fn impls_trait Trait<&'a str, U>, U>() {} + +fn main() { + impls_trait::<(), _>(); + //~^ ERROR type annotations needed +} diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr new file mode 100644 index 0000000000000..8a8118dea859b --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.next.stderr @@ -0,0 +1,35 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:18:5 + | +LL | impls_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_leak` + --> $DIR/leak-check-in-selection-3.rs:12:18 + | +LL | fn impls_leak Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak` + +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:35:5 + | +LL | impls_indirect_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak` + | + = note: cannot satisfy `for<'a> Box<_>: IndirectLeak<'a>` +note: required by a bound in `impls_indirect_leak` + --> $DIR/leak-check-in-selection-3.rs:25:27 + | +LL | fn impls_indirect_leak IndirectLeak<'a>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr new file mode 100644 index 0000000000000..662a06537401a --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.old.stderr @@ -0,0 +1,48 @@ +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:18:5 + | +LL | impls_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_leak` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impls_leak` + --> $DIR/leak-check-in-selection-3.rs:12:18 + | +LL | fn impls_leak Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impls_leak` + +error[E0283]: type annotations needed + --> $DIR/leak-check-in-selection-3.rs:35:5 + | +LL | impls_indirect_leak::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls_indirect_leak` + | +note: multiple `impl`s satisfying `Box<_>: Leak<'_>` found + --> $DIR/leak-check-in-selection-3.rs:9:1 + | +LL | impl Leak<'_> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required for `Box<_>` to implement `for<'a> IndirectLeak<'a>` + --> $DIR/leak-check-in-selection-3.rs:23:23 + | +LL | impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} + | -------- ^^^^^^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `impls_indirect_leak` + --> $DIR/leak-check-in-selection-3.rs:25:27 + | +LL | fn impls_indirect_leak IndirectLeak<'a>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impls_indirect_leak` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs new file mode 100644 index 0000000000000..9e99b6c527d9d --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-3.rs @@ -0,0 +1,39 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver + +// cc #119820, the previous behavior here was inconsistent, +// using the leak check to guide inference for `for<'a> Box<_>: Leak<'a>` +// but not for `for<'a> Box<_>: IndirectLeak<'a>` + +trait Leak<'a> {} +impl Leak<'_> for Box {} +impl Leak<'static> for Box {} + +fn impls_leak Leak<'a>>() {} +fn direct() { + // ok + // + // The `Box` impls fails the leak check, + // meaning that we apply the `Box` impl. + impls_leak::>(); + //~^ ERROR type annotations needed +} + +trait IndirectLeak<'a> {} +impl<'a, T: Leak<'a>> IndirectLeak<'a> for T {} + +fn impls_indirect_leak IndirectLeak<'a>>() {} +fn indirect() { + // error: type annotations needed + // + // While the `Box` impl would fail the leak check + // we have already instantiated the binder while applying + // the generic `IndirectLeak` impl, so during candidate + // selection of `Leak` we do not detect the placeholder error. + // Evaluation of `Box<_>: Leak<'!a>` is therefore ambiguous, + // resulting in `for<'a> Box<_>: Leak<'a>` also being ambiguous. + impls_indirect_leak::>(); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs new file mode 100644 index 0000000000000..8d87bdd064a06 --- /dev/null +++ b/tests/ui/higher-ranked/leak-check/leak-check-in-selection-4-hr-nested.rs @@ -0,0 +1,29 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ check-pass + +// cc #119820. While the leak check does not consider the binder +// of the current goal, leaks from higher-ranked nested goals are +// considered. +// +// We enter and exit the binder of the nested goal while evaluating +// the candidate. + +trait LeakCheckFailure<'a> {} +impl LeakCheckFailure<'static> for () {} + +trait Trait {} +impl Trait for () where for<'a> (): LeakCheckFailure<'a> {} +impl Trait for () {} +fn impls_trait, U>() {} +fn main() { + // ok + // + // It does not matter whether candidate assembly + // considers the placeholders from higher-ranked goal. + // + // Either `for<'a> (): LeakCheckFailure<'a>` has no applicable + // candidate or it has a single applicable candidate which then later + // results in an error. This allows us to infer `U` to `u16`. + impls_trait::<(), _>() +} diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr index e10da26665ebb..be19bf85bd2f3 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,23 +1,11 @@ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | -note: required by a bound in `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15 - | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function -LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | where B : Qux + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ + = note: `B` must implement `Bar<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<'static>` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs index 33e0ec4635b66..70ce580258d43 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs @@ -1,43 +1,37 @@ // Test a trait (`Bar`) with a higher-ranked supertrait. +#![allow(unconditional_recursion)] -trait Foo<'tcx> -{ +trait Foo<'tcx> { fn foo(&'tcx self) -> &'tcx isize; } -trait Bar<'ccx> - : for<'tcx> Foo<'tcx> -{ +trait Bar<'ccx>: for<'tcx> Foo<'tcx> { fn bar(&'ccx self) -> &'ccx isize; } -fn want_foo_for_some_tcx<'x,F>(f: &'x F) - where F : Foo<'x> -{ +fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { want_foo_for_some_tcx(f); - want_foo_for_any_tcx(f); //~ ERROR not satisfied + want_foo_for_any_tcx(f); + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `Foo` is not general enough } -fn want_foo_for_any_tcx(f: &F) //~ WARN cannot return without recursing - where F : for<'tcx> Foo<'tcx> -{ +fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { want_foo_for_some_tcx(f); want_foo_for_any_tcx(f); } -fn want_bar_for_some_ccx<'x,B>(b: &B) - where B : Bar<'x> -{ +fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); want_bar_for_some_ccx(b); - want_bar_for_any_ccx(b); //~ ERROR not satisfied + want_bar_for_any_ccx(b); + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `Bar` is not general enough } -fn want_bar_for_any_ccx(b: &B) //~ WARN cannot return without recursing - where B : for<'ccx> Bar<'ccx> -{ +fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index f220ba6f33893..dd760926ea117 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr @@ -1,68 +1,50 @@ -error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 | +LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { + | -- lifetime `'x` defined here +LL | want_foo_for_some_tcx(f); LL | want_foo_for_any_tcx(f); - | -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` | -note: required by a bound in `want_foo_for_any_tcx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15 +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28 | -LL | fn want_foo_for_any_tcx(f: &F) - | -------------------- required by a bound in this function -LL | where F : for<'tcx> Foo<'tcx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx` -help: consider further restricting this bound - | -LL | where F : Foo<'x> + for<'tcx> Foo<'tcx> - | +++++++++++++++++++++ +LL | fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { + | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26 - | -LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call +error: implementation of `Foo` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 | -note: required by a bound in `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15 - | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function -LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound +LL | want_foo_for_any_tcx(f); + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough | -LL | where B : Bar<'x> + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ + = note: `F` must implement `Foo<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Foo<'1>`, for some specific lifetime `'1` -warning: function cannot return without recursing - --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 | -LL | / fn want_foo_for_any_tcx(f: &F) -LL | | where F : for<'tcx> Foo<'tcx> - | |_________________________________^ cannot return without recursing +LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { + | -- lifetime `'x` defined here ... -LL | want_foo_for_any_tcx(f); - | ----------------------- recursive call site +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` + | +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28 | - = help: a `loop` may express intention better if this is on purpose - = note: `#[warn(unconditional_recursion)]` on by default +LL | fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { + | ^^^^^^^^^^^^^^^^^^^ -warning: function cannot return without recursing - --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1 +error: implementation of `Bar` is not general enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 | -LL | / fn want_bar_for_any_ccx(b: &B) -LL | | where B : for<'ccx> Bar<'ccx> - | |_________________________________^ cannot return without recursing -... -LL | want_bar_for_any_ccx(b); - | ----------------------- recursive call site +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough | - = help: a `loop` may express intention better if this is on purpose + = note: `B` must implement `Bar<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Bar<'1>`, for some specific lifetime `'1` -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs similarity index 86% rename from tests/ui/higher-ranked/trait-bounds/issue-30786.rs rename to tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs index ffb2b306ae76a..799df8cae9fd7 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs @@ -1,6 +1,6 @@ //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream &'b mut A: Stream` // should act as assertion that item does not borrow from its stream; // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does // have such an item. @@ -97,10 +97,6 @@ where impl StreamExt for T where for<'a> &'a mut T: Stream {} -fn identity(x: &T) -> &T { - x -} - fn variant1() { let source = Repeat(10); @@ -118,19 +114,7 @@ fn variant1() { // guess. let map = source.mapx(|x: &_| x); let filter = map.filterx(|x: &_| true); - //~^ ERROR the method -} - -fn variant2() { - let source = Repeat(10); - - // Here, we use a function, which is not subject to the vagaries - // of closure signature inference. In this case, we get the error - // on `countx` as, I think, the test originally expected. - let map = source.mapx(identity); - let filter = map.filterx(|x: &_| true); - let count = filter.countx(); - //~^ ERROR the method + //~^ ERROR the method `filterx` exists for struct } fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr new file mode 100644 index 0000000000000..56dfd124c5c3a --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr @@ -0,0 +1,27 @@ +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/issue-30786-1.rs:116:22 + | +LL | pub struct Map { + | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` +... +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + `&'a mut Map: Stream` + --> $DIR/issue-30786-1.rs:98:50 + | +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `filterx`, perhaps you need to implement it + --> $DIR/issue-30786-1.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs new file mode 100644 index 0000000000000..92e2e7f796eaa --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs @@ -0,0 +1,116 @@ +//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" + +// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream Option; +} + +// Example stream +pub struct Repeat(u64); + +impl<'a> Stream for &'a mut Repeat { + type Item = &'a u64; + fn next(self) -> Option { + Some(&self.0) + } +} + +pub struct Map { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Map +where + &'a mut A: Stream, + F: FnMut(<&'a mut A as Stream>::Item) -> T, +{ + type Item = T; + fn next(self) -> Option { + match self.stream.next() { + Some(item) => Some((self.func)(item)), + None => None, + } + } +} + +pub struct Filter { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Filter +where + for<'b> &'b mut A: Stream, // <---- BAD + F: FnMut(&T) -> bool, +{ + type Item = <&'a mut A as Stream>::Item; + fn next(self) -> Option { + while let Some(item) = self.stream.next() { + if (self.func)(&item) { + return Some(item); + } + } + None + } +} + +pub trait StreamExt +where + for<'b> &'b mut Self: Stream, +{ + fn mapx(self, func: F) -> Map + where + Self: Sized, + for<'a> &'a mut Map: Stream, + { + Map { func: func, stream: self } + } + + fn filterx(self, func: F) -> Filter + where + Self: Sized, + for<'a> &'a mut Filter: Stream, + { + Filter { func: func, stream: self } + } + + fn countx(mut self) -> usize + where + Self: Sized, + { + let mut count = 0; + while let Some(_) = self.next() { + count += 1; + } + count + } +} + +impl StreamExt for T where for<'a> &'a mut T: Stream {} + +fn identity(x: &T) -> &T { + x +} + +fn variant2() { + let source = Repeat(10); + + // Here, we use a function, which is not subject to the vagaries + // of closure signature inference. In this case, we get the error + // on `countx` as, I think, the test originally expected. + let map = source.mapx(identity); + let filter = map.filterx(|x: &_| true); + let count = filter.countx(); + //~^ ERROR the method +} + +fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr new file mode 100644 index 0000000000000..36e420ce0a37f --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr @@ -0,0 +1,27 @@ +error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786-2.rs:111:30}>`, but its trait bounds were not satisfied + --> $DIR/issue-30786-2.rs:112:24 + | +LL | pub struct Filter { + | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` +... +LL | let count = filter.countx(); + | ^^^^^^ method cannot be called due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + --> $DIR/issue-30786-2.rs:98:50 + | +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `StreamExt` defines an item `countx`, perhaps you need to implement it + --> $DIR/issue-30786-2.rs:66:1 + | +LL | pub trait StreamExt + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr deleted file mode 100644 index 699a4ecc42bb9..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:120:22 - | -LL | pub struct Map { - | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - `&'a mut Map: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - = help: items from traits can only be used if the trait is implemented and in scope -note: `StreamExt` defines an item `filterx`, perhaps you need to implement it - --> $DIR/issue-30786.rs:66:1 - | -LL | pub trait StreamExt - | ^^^^^^^^^^^^^^^^^^^ - -error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:132:24 - | -LL | pub struct Filter { - | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let count = filter.countx(); - | ^^^^^^ method cannot be called due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - = help: items from traits can only be used if the trait is implemented and in scope -note: `StreamExt` defines an item `countx`, perhaps you need to implement it - --> $DIR/issue-30786.rs:66:1 - | -LL | pub trait StreamExt - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs index ea33c9f423b77..041c687ec9430 100644 --- a/tests/ui/implied-bounds/issue-100690.rs +++ b/tests/ui/implied-bounds/issue-100690.rs @@ -4,11 +4,8 @@ use std::io; fn real_dispatch(f: F) -> Result<(), io::Error> -//~^ NOTE required by a bound in this where F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - //~^ NOTE required by this bound in `real_dispatch` - //~| NOTE required by a bound in `real_dispatch` { todo!() } @@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, { real_dispatch(f) - //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected a closure with arguments - //~| NOTE required by a bound introduced by this call + //~^ ERROR lifetime may not live long enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR mismatched types + // } } diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index df069d875cebc..2cfd028f2559b 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -1,22 +1,41 @@ -error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - --> $DIR/issue-100690.rs:37:23 +error: lifetime may not live long enough + --> $DIR/issue-100690.rs:34:9 | +LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle { + | -- lifetime `'a` defined here +... LL | real_dispatch(f) - | ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | - = note: expected a closure with arguments `(&mut UIView<'a, _>,)` - found a closure with arguments `(&mut UIView<'_, _>,)` -note: required by a bound in `real_dispatch` - --> $DIR/issue-100690.rs:9:8 +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-100690.rs:8:8 + | +LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-100690.rs:34:9 + | +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: `F` must implement `FnOnce<(&mut UIView<'0, T>,)>`, for any lifetime `'0`... + = note: ...but it actually implements `FnOnce<(&mut UIView<'1, T>,)>`, for some specific lifetime `'1` + +error[E0308]: mismatched types + --> $DIR/issue-100690.rs:34:9 + | +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `,)>>::Output` + found associated type `,)>>::Output` +note: the lifetime requirement is introduced here + --> $DIR/issue-100690.rs:8:34 | -LL | fn real_dispatch(f: F) -> Result<(), io::Error> - | ------------- required by a bound in this function -... LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch` + | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. From f090de88759ed9abc65074ff9926e03a3d550d77 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 3 Apr 2024 22:48:48 +0100 Subject: [PATCH 36/38] rebase oddity --- src/tools/tidy/src/issues.txt | 1 - ...om-env-universe-err-project.current.stderr | 12 +++++------ ...-from-env-universe-err-project.next.stderr | 18 ++++++++-------- ...candidate-from-env-universe-err-project.rs | 21 ++++++++++--------- ...0786-1.rs => hrtb-doesnt-borrow-self-1.rs} | 0 ...tderr => hrtb-doesnt-borrow-self-1.stderr} | 16 +++++++------- ...0786-2.rs => hrtb-doesnt-borrow-self-2.rs} | 0 ...tderr => hrtb-doesnt-borrow-self-2.stderr} | 14 ++++++------- 8 files changed, 41 insertions(+), 41 deletions(-) rename tests/ui/higher-ranked/trait-bounds/{issue-30786-1.rs => hrtb-doesnt-borrow-self-1.rs} (100%) rename tests/ui/higher-ranked/trait-bounds/{issue-30786-1.stderr => hrtb-doesnt-borrow-self-1.stderr} (57%) rename tests/ui/higher-ranked/trait-bounds/{issue-30786-2.rs => hrtb-doesnt-borrow-self-2.rs} (100%) rename tests/ui/higher-ranked/trait-bounds/{issue-30786-2.stderr => hrtb-doesnt-borrow-self-2.stderr} (66%) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index f6b1d45ee94ef..6b0573f5a3ff2 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1129,7 +1129,6 @@ "ui/generics/issue-98432.rs", "ui/higher-ranked/trait-bounds/issue-100689.rs", "ui/higher-ranked/trait-bounds/issue-102899.rs", -"ui/higher-ranked/trait-bounds/issue-30786.rs", "ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs", "ui/higher-ranked/trait-bounds/issue-39292.rs", "ui/higher-ranked/trait-bounds/issue-42114.rs", diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr index 16a6f549882e5..bb0b2de788e83 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr @@ -1,5 +1,5 @@ error: implementation of `Trait` is not general enough - --> $DIR/candidate-from-env-universe-err-project.rs:31:5 + --> $DIR/candidate-from-env-universe-err-project.rs:28:5 | LL | trait_bound::(); | ^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough @@ -8,7 +8,7 @@ LL | trait_bound::(); = note: ...but it actually implements `Trait<'static>` error: implementation of `Trait` is not general enough - --> $DIR/candidate-from-env-universe-err-project.rs:41:5 + --> $DIR/candidate-from-env-universe-err-project.rs:39:5 | LL | projection_bound::(); | ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough @@ -17,7 +17,7 @@ LL | projection_bound::(); = note: ...but it actually implements `Trait<'static>` error[E0308]: mismatched types - --> $DIR/candidate-from-env-universe-err-project.rs:41:5 + --> $DIR/candidate-from-env-universe-err-project.rs:39:5 | LL | projection_bound::(); | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other @@ -25,13 +25,13 @@ LL | projection_bound::(); = note: expected associated type `>::Assoc` found associated type `>::Assoc` note: the lifetime requirement is introduced here - --> $DIR/candidate-from-env-universe-err-project.rs:21:42 + --> $DIR/candidate-from-env-universe-err-project.rs:18:42 | LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other @@ -40,7 +40,7 @@ LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); found associated type `>::Assoc` error[E0308]: mismatched types - --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index 57f2184b611e9..2804d5bbe9408 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied - --> $DIR/candidate-from-env-universe-err-project.rs:31:19 + --> $DIR/candidate-from-env-universe-err-project.rs:28:19 | LL | trait_bound::(); | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` | note: required by a bound in `trait_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:20:19 + --> $DIR/candidate-from-env-universe-err-project.rs:17:19 | LL | fn trait_bound Trait<'a>>() {} | ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound` @@ -15,13 +15,13 @@ LL | fn function1 + for<'a> Trait<'a>>() { | +++++++++++++++++++ error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied - --> $DIR/candidate-from-env-universe-err-project.rs:41:24 + --> $DIR/candidate-from-env-universe-err-project.rs:39:24 | LL | projection_bound::(); | ^ the trait `for<'a> Trait<'a>` is not implemented for `T` | note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:21:24 + --> $DIR/candidate-from-env-universe-err-project.rs:18:24 | LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` @@ -31,30 +31,30 @@ LL | fn function2 + for<'a> Trait<'a>>() { | +++++++++++++++++++ error[E0271]: type mismatch resolving `>::Assoc == usize` - --> $DIR/candidate-from-env-universe-err-project.rs:41:24 + --> $DIR/candidate-from-env-universe-err-project.rs:39:24 | LL | projection_bound::(); | ^ type mismatch resolving `>::Assoc == usize` | note: types differ - --> $DIR/candidate-from-env-universe-err-project.rs:17:18 + --> $DIR/candidate-from-env-universe-err-project.rs:14:18 | LL | type Assoc = usize; | ^^^^^ note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:21:42 + --> $DIR/candidate-from-env-universe-err-project.rs:18:42 | LL | fn projection_bound Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^ required by this bound in `projection_bound` error: higher-ranked subtype error - --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error - --> $DIR/candidate-from-env-universe-err-project.rs:56:30 + --> $DIR/candidate-from-env-universe-err-project.rs:55:30 | LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs index 7e5e5f3a8472c..2f53bd019b78c 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -5,9 +5,6 @@ // the where-bound candidate for trait goals due to the leak check, but did // not do so for projection candidates and during normalization. // -// FIXME(-Znext-solver): We currently prefer the impl over the where-bound -// for trait goals because the impl does not result in any constraints. -// // This results in an inconsistency between `Trait` and `Projection` goals as // normalizing always constraints the normalized-to term. trait Trait<'a> { @@ -23,13 +20,14 @@ fn projection_bound Trait<'a, Assoc = usize>>() {} // We use a function with a trivial where-bound which is more // restrictive than the impl. fn function1>() { - // ok + // err // - // Proving `for<'a> T: Trait<'a>` using the where-bound results - // in a leak check failure, so we use the more general impl, - // causing this to succeed. + // Proving `for<'a> T: Trait<'a>` using the where-bound does not + // result in a leak check failure even though it does not apply. + // We prefer env candidates over impl candidatescausing this to succeed. trait_bound::(); - //[current]~^ ERROR mismatched types + //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied + //[current]~^^ ERROR implementation of `Trait` is not general enough } fn function2>() { @@ -40,7 +38,8 @@ fn function2>() { // to prefer it over the impl, resulting in a placeholder error. projection_bound::(); //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` - //[current]~^^ ERROR mismatched types + //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied + //[current]~^^^ ERROR implementation of `Trait` is not general enough //[current]~| ERROR mismatched types } @@ -54,7 +53,9 @@ fn function3>() { // leak check during candidate selection for normalization, this // case would still not compile. let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); - //[current]~^ ERROR mismatched types + //[next]~^ ERROR higher-ranked subtype error + //[next]~| ERROR higher-ranked subtype error + //[current]~^^^ ERROR mismatched types //[current]~| ERROR mismatched types } diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs similarity index 100% rename from tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.rs diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr similarity index 57% rename from tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr index 56dfd124c5c3a..ae364de8cc061 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-1.stderr @@ -1,23 +1,23 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786-1.rs:116:22 +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/hrtb-doesnt-borrow-self-1.rs:116:22 | LL | pub struct Map { | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` ... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - `&'a mut Map: Stream` - --> $DIR/issue-30786-1.rs:98:50 + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + `&'a mut Map: Stream` + --> $DIR/hrtb-doesnt-borrow-self-1.rs:98:50 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here = help: items from traits can only be used if the trait is implemented and in scope note: `StreamExt` defines an item `filterx`, perhaps you need to implement it - --> $DIR/issue-30786-1.rs:66:1 + --> $DIR/hrtb-doesnt-borrow-self-1.rs:66:1 | LL | pub trait StreamExt | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs similarity index 100% rename from tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.rs diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr similarity index 66% rename from tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr rename to tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr index 36e420ce0a37f..eeb4e12fa8b31 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-doesnt-borrow-self-2.stderr @@ -1,5 +1,5 @@ -error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786-2.rs:111:30}>`, but its trait bounds were not satisfied - --> $DIR/issue-30786-2.rs:112:24 +error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@hrtb-doesnt-borrow-self-2.rs:111:30}>`, but its trait bounds were not satisfied + --> $DIR/hrtb-doesnt-borrow-self-2.rs:112:24 | LL | pub struct Filter { | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` @@ -8,16 +8,16 @@ LL | let count = filter.countx(); | ^^^^^^ method cannot be called due to unsatisfied trait bounds | note: the following trait bounds were not satisfied: - `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` - `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` - `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` - --> $DIR/issue-30786-2.rs:98:50 + `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/hrtb-doesnt-borrow-self-2.rs:111:30: 111:37}>: Stream` + --> $DIR/hrtb-doesnt-borrow-self-2.rs:98:50 | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here = help: items from traits can only be used if the trait is implemented and in scope note: `StreamExt` defines an item `countx`, perhaps you need to implement it - --> $DIR/issue-30786-2.rs:66:1 + --> $DIR/hrtb-doesnt-borrow-self-2.rs:66:1 | LL | pub trait StreamExt | ^^^^^^^^^^^^^^^^^^^ From 2b67f0104a9fcdb3a6aa41bceb33e62e609e6b6c Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 4 Sep 2023 17:35:51 +0200 Subject: [PATCH 37/38] check `FnDef` return type for WF --- .../rustc_trait_selection/src/traits/wf.rs | 28 +++++++++--- tests/ui/fn/fn-item-lifetime-bounds.rs | 37 ---------------- tests/ui/wf/wf-fn-def-check-sig-1.rs | 44 +++++++++++++++++++ tests/ui/wf/wf-fn-def-check-sig-1.stderr | 14 ++++++ tests/ui/wf/wf-fn-def-check-sig-2.rs | 44 +++++++++++++++++++ tests/ui/wf/wf-fn-def-check-sig-2.stderr | 15 +++++++ 6 files changed, 138 insertions(+), 44 deletions(-) delete mode 100644 tests/ui/fn/fn-item-lifetime-bounds.rs create mode 100644 tests/ui/wf/wf-fn-def-check-sig-1.rs create mode 100644 tests/ui/wf/wf-fn-def-check-sig-1.stderr create mode 100644 tests/ui/wf/wf-fn-def-check-sig-2.rs create mode 100644 tests/ui/wf/wf-fn-def-check-sig-2.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 7941a8fe95c8e..9b078e45c8558 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { fn visit_ty(&mut self, t: as ty::Interner>::Ty) -> Self::Result { debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); + let tcx = self.tcx(); + match *t.kind() { ty::Bool | ty::Char @@ -707,6 +709,16 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::FnDef(did, args) => { + // HACK: Check the return type of function definitions for + // well-formedness to mostly fix #84533. This is still not + // perfect and there may be ways to abuse the fact that we + // ignore requirements with escaping bound vars. That's a + // more general issue however. + // + // FIXME(eddyb) add the type to `walker` instead of recursing. + let fn_sig = tcx.fn_sig(did).instantiate(tcx, args); + fn_sig.output().skip_binder().visit_with(self); + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } @@ -716,7 +728,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { let cause = self.cause(traits::ReferenceOutlivesReferent(t)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -805,12 +817,12 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; + let defer_to_coercion = tcx.features().object_safe_for_dispatch; if !defer_to_coercion { if let Some(principal) = data.principal_def_id() { self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, self.cause(traits::WellFormed(None)), self.recursion_depth, self.param_env, @@ -835,7 +847,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Infer(_) => { let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -850,6 +862,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } fn visit_const(&mut self, c: as ty::Interner>::Const) -> Self::Result { + let tcx = self.tcx(); + match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { @@ -861,7 +875,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -873,7 +887,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, @@ -895,7 +909,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); let cause = self.cause(traits::WellFormed(None)); self.out.push(traits::Obligation::with_depth( - self.tcx(), + tcx, cause, self.recursion_depth, self.param_env, diff --git a/tests/ui/fn/fn-item-lifetime-bounds.rs b/tests/ui/fn/fn-item-lifetime-bounds.rs deleted file mode 100644 index b80b7eade23d1..0000000000000 --- a/tests/ui/fn/fn-item-lifetime-bounds.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ check-pass -//@ known-bug: #84533 - -// Should fail. Lifetimes are checked correctly when `foo` is called, but NOT -// when only the lifetime parameters are instantiated. - -use std::marker::PhantomData; - -#[allow(dead_code)] -fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { - PhantomData -} - -#[allow(dead_code)] -#[allow(path_statements)] -fn caller<'b, 'a>() { - foo::<'b, 'a>; -} - -// In contrast to above, below code correctly does NOT compile. -// fn caller<'b, 'a>() { -// foo::<'b, 'a>(); -// } - -// error: lifetime may not live long enough -// --> src/main.rs:22:5 -// | -// 21 | fn caller<'b, 'a>() { -// | -- -- lifetime `'a` defined here -// | | -// | lifetime `'b` defined here -// 22 | foo::<'b, 'a>(); -// | ^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` -// | -// = help: consider adding the following bound: `'a: 'b` - -fn main() {} diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.rs b/tests/ui/wf/wf-fn-def-check-sig-1.rs new file mode 100644 index 0000000000000..621d1ac3fc1be --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-1.rs @@ -0,0 +1,44 @@ +// Regression test for #84533. + +use std::marker::PhantomData; + +fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { + PhantomData +} + +fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + let f = foo::<'b, 'a>; + //~^ ERROR lifetime may not live long enough + f.baz(x) +} + +trait Foo<'a, 'b, T: ?Sized> { + fn baz(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F +where + F: Fn() -> R, + R: ProofForConversion<'a, 'b, T>, +{ + fn baz(self, s: &'a T) -> &'b T { + self().convert(s) + } +} + +trait ProofForConversion<'a, 'b, T: ?Sized> { + fn convert(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> { + fn convert(self, s: &'a T) -> &'b T { + s + } +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = extend_lifetime(&x); + } + println!("{}", d); +} diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.stderr b/tests/ui/wf/wf-fn-def-check-sig-1.stderr new file mode 100644 index 0000000000000..9501d6de8b528 --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-1.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/wf-fn-def-check-sig-1.rs:10:13 + | +LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let f = foo::<'b, 'a>; + | ^^^^^^^^^^^^^ requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.rs b/tests/ui/wf/wf-fn-def-check-sig-2.rs new file mode 100644 index 0000000000000..51740dca8e9be --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-2.rs @@ -0,0 +1,44 @@ +// Regression test for #84533 involving higher-ranked regions +// in the return type. +use std::marker::PhantomData; + +fn foo<'c, 'b, 'a>(_: &'c ()) -> (&'c (), PhantomData<&'b &'a ()>) { + (&(), PhantomData) +} + +fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + let f = foo; + f.baz(x) + //~^ ERROR lifetime may not live long enough +} + +trait Foo<'a, 'b, T: ?Sized> { + fn baz(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, R, F, T: ?Sized> Foo<'a, 'b, T> for F +where + F: for<'c> Fn(&'c ()) -> (&'c (), R), + R: ProofForConversion<'a, 'b, T>, +{ + fn baz(self, s: &'a T) -> &'b T { + self(&()).1.convert(s) + } +} + +trait ProofForConversion<'a, 'b, T: ?Sized> { + fn convert(self, s: &'a T) -> &'b T; +} +impl<'a, 'b, T: ?Sized> ProofForConversion<'a, 'b, T> for PhantomData<&'b &'a ()> { + fn convert(self, s: &'a T) -> &'b T { + s + } +} + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = extend_lifetime(&x); + } + println!("{}", d); +} diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.stderr b/tests/ui/wf/wf-fn-def-check-sig-2.stderr new file mode 100644 index 0000000000000..70c0fd32e1bd2 --- /dev/null +++ b/tests/ui/wf/wf-fn-def-check-sig-2.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/wf-fn-def-check-sig-2.rs:11:5 + | +LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let f = foo; +LL | f.baz(x) + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + From 82789763c7c5c09c6b0481d18cf00ef67b4b6fa3 Mon Sep 17 00:00:00 2001 From: Boxy Date: Thu, 4 Apr 2024 02:14:52 +0100 Subject: [PATCH 38/38] rebase --- compiler/rustc_trait_selection/src/traits/wf.rs | 4 ++-- tests/ui/proc-macro/bad-projection.rs | 1 + tests/ui/proc-macro/bad-projection.stderr | 14 +++++++++++++- tests/ui/wf/wf-fn-def-check-sig-1.rs | 2 +- tests/ui/wf/wf-fn-def-check-sig-1.stderr | 7 ++++--- tests/ui/wf/wf-fn-def-check-sig-2.stderr | 2 +- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9b078e45c8558..19ca147d3ad63 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -718,7 +718,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // FIXME(eddyb) add the type to `walker` instead of recursing. let fn_sig = tcx.fn_sig(did).instantiate(tcx, args); fn_sig.output().skip_binder().visit_with(self); - + let obligations = self.nominal_obligations(did, args); self.out.extend(obligations); } @@ -863,7 +863,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { fn visit_const(&mut self, c: as ty::Interner>::Const) -> Self::Result { let tcx = self.tcx(); - + match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs index e633191bd310f..0769a7f08c127 100644 --- a/tests/ui/proc-macro/bad-projection.rs +++ b/tests/ui/proc-macro/bad-projection.rs @@ -15,4 +15,5 @@ pub fn uwu() -> <() as Project>::Assoc {} //~^ ERROR the trait bound `(): Project` is not satisfied //~| ERROR the trait bound `(): Project` is not satisfied //~| ERROR the trait bound `(): Project` is not satisfied +//~| ERROR the trait bound `(): Project` is not satisfied //~| ERROR function is expected to take 1 argument, but it takes 0 arguments diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr index 8e0d8461849b4..2e8668f60de74 100644 --- a/tests/ui/proc-macro/bad-projection.stderr +++ b/tests/ui/proc-macro/bad-projection.stderr @@ -35,6 +35,18 @@ help: this trait has no implementations, consider adding one LL | trait Project { | ^^^^^^^^^^^^^ +error[E0277]: the trait bound `(): Project` is not satisfied + --> $DIR/bad-projection.rs:14:1 + | +LL | pub fn uwu() -> <() as Project>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/bad-projection.rs:9:1 + | +LL | trait Project { + | ^^^^^^^^^^^^^ + error[E0277]: the trait bound `(): Project` is not satisfied --> $DIR/bad-projection.rs:14:40 | @@ -47,7 +59,7 @@ help: this trait has no implementations, consider adding one LL | trait Project { | ^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0277, E0593. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.rs b/tests/ui/wf/wf-fn-def-check-sig-1.rs index 621d1ac3fc1be..6d9e1f38f8d3e 100644 --- a/tests/ui/wf/wf-fn-def-check-sig-1.rs +++ b/tests/ui/wf/wf-fn-def-check-sig-1.rs @@ -8,8 +8,8 @@ fn foo<'b, 'a>() -> PhantomData<&'b &'a ()> { fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { let f = foo::<'b, 'a>; - //~^ ERROR lifetime may not live long enough f.baz(x) + //~^ ERROR lifetime may not live long enough } trait Foo<'a, 'b, T: ?Sized> { diff --git a/tests/ui/wf/wf-fn-def-check-sig-1.stderr b/tests/ui/wf/wf-fn-def-check-sig-1.stderr index 9501d6de8b528..a93449ad3c63e 100644 --- a/tests/ui/wf/wf-fn-def-check-sig-1.stderr +++ b/tests/ui/wf/wf-fn-def-check-sig-1.stderr @@ -1,14 +1,15 @@ error: lifetime may not live long enough - --> $DIR/wf-fn-def-check-sig-1.rs:10:13 + --> $DIR/wf-fn-def-check-sig-1.rs:11:5 | LL | fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here LL | let f = foo::<'b, 'a>; - | ^^^^^^^^^^^^^ requires that `'a` must outlive `'b` +LL | f.baz(x) + | ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` | = help: consider adding the following bound: `'a: 'b` -error: aborting due to previous error +error: aborting due to 1 previous error diff --git a/tests/ui/wf/wf-fn-def-check-sig-2.stderr b/tests/ui/wf/wf-fn-def-check-sig-2.stderr index 70c0fd32e1bd2..404d3cc4513bc 100644 --- a/tests/ui/wf/wf-fn-def-check-sig-2.stderr +++ b/tests/ui/wf/wf-fn-def-check-sig-2.stderr @@ -11,5 +11,5 @@ LL | f.baz(x) | = help: consider adding the following bound: `'a: 'b` -error: aborting due to previous error +error: aborting due to 1 previous error