diff options
47 files changed, 691 insertions, 310 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 7f5f9f03868..bda22255705 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -7,7 +7,9 @@ use std::{env, iter, mem, str}; use cc::windows_registry; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; -use rustc_metadata::{find_native_static_library, try_find_native_static_library}; +use rustc_metadata::{ + find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, +}; use rustc_middle::bug; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols; @@ -876,7 +878,13 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + // On MSVC-like targets rustc supports import libraries using alternative naming + // scheme (`libfoo.a`) unsupported by linker, search for such libraries manually. + if let Some(path) = try_find_native_dynamic_library(self.sess, name, verbatim) { + self.link_arg(path); + } else { + self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } } fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { diff --git a/compiler/rustc_error_codes/src/error_codes/E0799.md b/compiler/rustc_error_codes/src/error_codes/E0799.md new file mode 100644 index 00000000000..38ebc840604 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0799.md @@ -0,0 +1,19 @@ +Something other than a type or const parameter has been used when one was +expected. + +Erroneous code example: + +```compile_fail,E0799 +fn bad1() -> impl Sized + use<main> {} + +fn bad2(x: ()) -> impl Sized + use<x> {} + +fn main() {} +``` + +In the given examples, for `bad1`, the name `main` corresponds to a function +rather than a type or const parameter. In `bad2`, the name `x` corresponds to +a function argument rather than a type or const parameter. + +Only type and const parameters, including `Self`, may be captured by +`use<...>` precise capturing bounds. diff --git a/compiler/rustc_error_codes/src/error_codes/E0800.md b/compiler/rustc_error_codes/src/error_codes/E0800.md new file mode 100644 index 00000000000..3e08cd499b7 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0800.md @@ -0,0 +1,11 @@ +A type or const parameter of the given name is not in scope. + +Erroneous code examples: + +```compile_fail,E0800 +fn missing() -> impl Sized + use<T> {} +``` + +To fix this error, please verify you didn't misspell the type or const +parameter, or double-check if you forgot to declare the parameter in +the list of generics. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 150f99a3ee7..d6f0206b0de 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -538,6 +538,8 @@ E0795: 0795, E0796: 0796, E0797: 0797, E0798: 0798, +E0799: 0799, +E0800: 0800, ); ) } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 388e02b36e0..cc7a0dff34e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -726,7 +726,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( num_trait_args, num_impl_args, def_id, - impl_def_id: impl_m.container_id(tcx), + impl_m_def_id: impl_m.def_id, ty, return_span, }) { @@ -844,12 +844,18 @@ where struct RemapHiddenTyRegions<'tcx> { tcx: TyCtxt<'tcx>, + /// Map from early/late params of the impl to identity regions of the RPITIT (GAT) + /// in the trait. map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>, num_trait_args: usize, num_impl_args: usize, + /// Def id of the RPITIT (GAT) in the *trait*. def_id: DefId, - impl_def_id: DefId, + /// Def id of the impl method which owns the opaque hidden type we're remapping. + impl_m_def_id: DefId, + /// The hidden type we're remapping. Useful for diagnostics. ty: Ty<'tcx>, + /// Span of the return type. Useful for diagnostics. return_span: Span, } @@ -885,8 +891,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { ty::ReLateParam(_) => {} // Remap early-bound regions as long as they don't come from the `impl` itself, // in which case we don't really need to renumber them. - ty::ReEarlyParam(ebr) - if ebr.index >= self.tcx.generics_of(self.impl_def_id).count() as u32 => {} + ty::ReEarlyParam(ebr) if ebr.index as usize >= self.num_impl_args => {} _ => return Ok(region), } @@ -899,7 +904,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> { ); } } else { - let guar = match region.opt_param_def_id(self.tcx, self.tcx.parent(self.def_id)) { + let guar = match region.opt_param_def_id(self.tcx, self.impl_m_def_id) { Some(def_id) => { let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() { self.tcx.def_span(opaque_ty.def_id) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index b4cbd1f309c..53dcede91c3 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -584,7 +584,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | Res::SelfTyParam { trait_: def_id } => { self.resolve_type_ref(def_id.expect_local(), param.hir_id); } - Res::Err => {} Res::SelfTyAlias { alias_to, .. } => { self.tcx.dcx().emit_err(errors::PreciseCaptureSelfAlias { span: param.ident.span, @@ -593,11 +592,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } res => { - self.tcx.dcx().emit_err(errors::BadPreciseCapture { - span: param.ident.span, - kind: "type or const", - found: res.descr().to_string(), - }); + self.tcx.dcx().span_delayed_bug( + param.ident.span, + format!("expected type or const param, found {res:?}"), + ); } }, } diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index af2bb053c0a..b6cffb90805 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -1,3 +1,4 @@ +use rustc_errors::E0799; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -43,7 +44,7 @@ pub(crate) struct BadPreciseCapture { } #[derive(Diagnostic)] -#[diag(hir_analysis_precise_capture_self_alias)] +#[diag(hir_analysis_precise_capture_self_alias, code = E0799)] pub(crate) struct PreciseCaptureSelfAlias { #[primary_span] pub span: Span, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 3bada1de148..fca7babea30 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// trait or region sub-obligations. (presumably we could, but it's not /// particularly important for diagnostics...) pub(crate) fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<'tcx>> { - self.autoderef(DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| { + self.autoderef(DUMMY_SP, expr_ty).silence_errors().nth(1).and_then(|(deref_ty, _)| { self.infcx .type_implements_trait( self.tcx.lang_items().deref_mut_trait()?, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6fd509ed32f..821a90d7a8c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2864,13 +2864,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expr_t, "") }; for (found_fields, args) in - self.get_field_candidates_considering_privacy(span, ty, mod_id, id) + self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id) { let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>(); let mut candidate_fields: Vec<_> = found_fields .into_iter() .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( + self.check_for_nested_field_satisfying_condition_for_diag( span, &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, @@ -2933,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .with_span_label(field.span, "private field") } - pub(crate) fn get_field_candidates_considering_privacy( + pub(crate) fn get_field_candidates_considering_privacy_for_diag( &self, span: Span, base_ty: Ty<'tcx>, @@ -2942,7 +2942,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> { debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - self.autoderef(span, base_ty) + let mut autoderef = self.autoderef(span, base_ty).silence_errors(); + let deref_chain: Vec<_> = autoderef.by_ref().collect(); + + // Don't probe if we hit the recursion limit, since it may result in + // quadratic blowup if we then try to further deref the results of this + // function. This is a best-effort method, after all. + if autoderef.reached_recursion_limit() { + return vec![]; + } + + deref_chain + .into_iter() .filter_map(move |(base_t, _)| { match base_t.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { @@ -2975,7 +2986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field - pub(crate) fn check_for_nested_field_satisfying( + pub(crate) fn check_for_nested_field_satisfying_condition_for_diag( &self, span: Span, matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, @@ -3000,20 +3011,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if matches(candidate_field, field_ty) { return Some(field_path); } else { - for (nested_fields, subst) in - self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id) + for (nested_fields, subst) in self + .get_field_candidates_considering_privacy_for_diag( + span, field_ty, mod_id, hir_id, + ) { // recursively search fields of `candidate_field` if it's a ty::Adt for field in nested_fields { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - mod_id, - hir_id, - ) { + if let Some(field_path) = self + .check_for_nested_field_satisfying_condition_for_diag( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + hir_id, + ) + { return Some(field_path); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8348c6e9a16..8810f14aaa9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2619,9 +2619,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_method: bool, ) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> { let fn_node = self.tcx.hir().get_if_local(def_id)?; + let fn_decl = fn_node.fn_decl()?; - let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node - .fn_decl()? + let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_decl .inputs .into_iter() .skip(if is_method { 1 } else { 0 }) @@ -2642,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect(); - let params: Vec<&hir::Param<'_>> = self + let mut params: Vec<&hir::Param<'_>> = self .tcx .hir() .body(fn_node.body_id()?) @@ -2651,7 +2651,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .skip(if is_method { 1 } else { 0 }) .collect(); - Some(generic_params.into_iter().zip_eq(params).collect()) + // The surrounding code expects variadic functions to not have a parameter representing + // the "..." parameter. This is already true of the FnDecl but not of the body params, so + // we drop it if it exists. + + if fn_decl.c_variadic { + params.pop(); + } + + debug_assert_eq!(params.len(), generic_params.len()); + Some(generic_params.into_iter().zip(params).collect()) } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3ba3429cbb3..5dc341653e5 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If our autoderef loop had reached the recursion limit, // report an overflow error, but continue going on with // the truncated autoderef list. - if steps.reached_recursion_limit { + if steps.reached_recursion_limit && !is_suggestion.0 { self.probe(|_| { let ty = &steps .steps diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ede809ead2..deabf693af2 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -62,14 +62,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // It might seem that we can use `predicate_must_hold_modulo_regions`, // but since a Dummy binder is used to fill in the FnOnce trait's arguments, // type resolution always gives a "maybe" here. - if self.autoderef(span, ty).any(|(ty, _)| { + if self.autoderef(span, ty).silence_errors().any(|(ty, _)| { info!("check deref {:?} error", ty); matches!(ty.kind(), ty::Error(_) | ty::Infer(_)) }) { return false; } - self.autoderef(span, ty).any(|(ty, _)| { + self.autoderef(span, ty).silence_errors().any(|(ty, _)| { info!("check deref {:?} impl FnOnce", ty); self.probe(|_| { let trait_ref = @@ -90,7 +90,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.autoderef(span, ty).any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) + self.autoderef(span, ty) + .silence_errors() + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) } fn impl_into_iterator_should_be_iterator( @@ -672,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut ty_str_reported = ty_str.clone(); if let ty::Adt(_, generics) = rcvr_ty.kind() { if generics.len() > 0 { - let mut autoderef = self.autoderef(span, rcvr_ty); + let mut autoderef = self.autoderef(span, rcvr_ty).silence_errors(); let candidate_found = autoderef.any(|(ty, _)| { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx @@ -2237,6 +2239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let impl_ty = self.tcx.type_of(*impl_did).instantiate_identity(); let target_ty = self .autoderef(sugg_span, rcvr_ty) + .silence_errors() .find(|(rcvr_ty, _)| { DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty) }) @@ -2352,17 +2355,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diag<'_>, ) -> bool { let tcx = self.tcx; - let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { - ty::Adt(def, args) if !def.is_enum() => { - let variant = &def.non_enum_variant(); - tcx.find_field_index(item_name, variant).map(|index| { - let field = &variant.fields[index]; - let field_ty = field.ty(tcx, args); - (field, field_ty) - }) - } - _ => None, - }); + let field_receiver = + self.autoderef(span, rcvr_ty).silence_errors().find_map(|(ty, _)| match ty.kind() { + ty::Adt(def, args) if !def.is_enum() => { + let variant = &def.non_enum_variant(); + tcx.find_field_index(item_name, variant).map(|index| { + let field = &variant.fields[index]; + let field_ty = field.ty(tcx, args); + (field, field_ty) + }) + } + _ => None, + }); if let Some((field, field_ty)) = field_receiver { let scope = tcx.parent_module_from_def_id(self.body_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); @@ -2675,9 +2679,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if let SelfSource::MethodCall(expr) = source { let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); - for (fields, args) in - self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id) - { + for (fields, args) in self.get_field_candidates_considering_privacy_for_diag( + span, + actual, + mod_id, + expr.hir_id, + ) { let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)); let lang_items = self.tcx.lang_items(); @@ -2693,7 +2700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut candidate_fields: Vec<_> = fields .into_iter() .filter_map(|candidate_field| { - self.check_for_nested_field_satisfying( + self.check_for_nested_field_satisfying_condition_for_diag( span, &|_, field_ty| { self.lookup_probe_for_diagnostic( @@ -3195,7 +3202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let SelfSource::QPath(ty) = self_source else { return; }; - for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).skip(1) { + for (deref_ty, _) in self.autoderef(DUMMY_SP, rcvr_ty).silence_errors().skip(1) { if let Ok(pick) = self.probe_for_name( Mode::Path, item_name, @@ -4221,7 +4228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return is_local(rcvr_ty); } - self.autoderef(span, rcvr_ty).any(|(ty, _)| is_local(ty)) + self.autoderef(span, rcvr_ty).silence_errors().any(|(ty, _)| is_local(ty)) } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c8c95ddcfce..45a6efc7a6a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2533,6 +2533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("the semantics of slice patterns changed recently; see issue #62254"); } else if self .autoderef(span, expected_ty) + .silence_errors() .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) && let Some(span) = ti.span && let Some(_) = ti.origin_expr diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 58b352f263d..02a9ce455b2 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -37,7 +37,8 @@ pub mod locator; pub use creader::{load_symbol_from_dylib, DylibError}; pub use fs::{emit_wrapper_file, METADATA_FILENAME}; pub use native_libs::{ - find_native_static_library, try_find_native_static_library, walk_native_lib_search_dirs, + find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, + walk_native_lib_search_dirs, }; pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER}; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index a6ad449cb53..0329a193d89 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -109,6 +109,44 @@ pub fn try_find_native_static_library( .break_value() } +pub fn try_find_native_dynamic_library( + sess: &Session, + name: &str, + verbatim: bool, +) -> Option<PathBuf> { + let formats = if verbatim { + vec![("".into(), "".into())] + } else { + // While the official naming convention for MSVC import libraries + // is foo.lib... + let os = (sess.target.staticlib_prefix.clone(), sess.target.staticlib_suffix.clone()); + // ... Meson follows the libfoo.dll.a convention to + // disambiguate .a for static libraries + let meson = ("lib".into(), ".dll.a".into()); + // and MinGW uses .a altogether + let mingw = ("lib".into(), ".a".into()); + vec![os, meson, mingw] + }; + + walk_native_lib_search_dirs( + sess, + LinkSelfContainedComponents::empty(), + None, + |dir, is_framework| { + if !is_framework { + for (prefix, suffix) in &formats { + let test = dir.join(format!("{prefix}{name}{suffix}")); + if test.exists() { + return ControlFlow::Break(test); + } + } + } + ControlFlow::Continue(()) + }, + ) + .break_value() +} + pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> PathBuf { try_find_native_static_library(sess, name, verbatim) .unwrap_or_else(|| sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim))) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index bbc696e0f08..5f9a89c3a5b 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -255,7 +255,9 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Lifetime => param, - _ => bug!("expected lifetime parameter, but found another generic parameter"), + _ => { + bug!("expected lifetime parameter, but found another generic parameter: {param:#?}") + } } } @@ -264,7 +266,7 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Type { .. } => param, - _ => bug!("expected type parameter, but found another generic parameter"), + _ => bug!("expected type parameter, but found another generic parameter: {param:#?}"), } } @@ -273,7 +275,7 @@ impl<'tcx> Generics { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Const { .. } => param, - _ => bug!("expected const parameter, but found another generic parameter"), + _ => bug!("expected const parameter, but found another generic parameter: {param:#?}"), } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index d70ff8258d0..a0262f12cb5 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -571,7 +571,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if `def_id` refers to a definition that does not have its own /// type-checking context, i.e. closure, coroutine or inline const. pub fn is_typeck_child(self, def_id: DefId) -> bool { - matches!(self.def_kind(def_id), DefKind::Closure | DefKind::InlineConst) + matches!( + self.def_kind(def_id), + DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody + ) } /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 7e3ecad1bce..ef4031c5c03 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -95,11 +95,33 @@ impl CoverageCounters { this } - fn make_counter(&mut self, site: CounterIncrementSite) -> BcbCounter { + /// Shared helper used by [`Self::make_phys_node_counter`] and + /// [`Self::make_phys_edge_counter`]. Don't call this directly. + fn make_counter_inner(&mut self, site: CounterIncrementSite) -> BcbCounter { let id = self.counter_increment_sites.push(site); BcbCounter::Counter { id } } + /// Creates a new physical counter attached a BCB node. + /// The node must not already have a counter. + fn make_phys_node_counter(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { + let counter = self.make_counter_inner(CounterIncrementSite::Node { bcb }); + debug!(?bcb, ?counter, "node gets a physical counter"); + self.set_bcb_counter(bcb, counter) + } + + /// Creates a new physical counter attached to a BCB edge. + /// The edge must not already have a counter. + fn make_phys_edge_counter( + &mut self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + ) -> BcbCounter { + let counter = self.make_counter_inner(CounterIncrementSite::Edge { from_bcb, to_bcb }); + debug!(?from_bcb, ?to_bcb, ?counter, "edge gets a physical counter"); + self.set_bcb_edge_counter(from_bcb, to_bcb, counter) + } + fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { let new_expr = BcbExpression { lhs, op, rhs }; *self @@ -294,25 +316,27 @@ impl<'a> MakeBcbCounters<'a> { let successors = self.basic_coverage_blocks.successors[from_bcb].as_slice(); - // If this node doesn't have multiple out-edges, or all of its out-edges - // already have counters, then we don't need to create edge counters. - let needs_out_edge_counters = successors.len() > 1 - && successors.iter().any(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)); - if !needs_out_edge_counters { + // If this node's out-edges won't sum to the node's counter, + // then there's no reason to create edge counters here. + if !self.basic_coverage_blocks[from_bcb].is_out_summable { return; } - if tracing::enabled!(tracing::Level::DEBUG) { - let _span = - debug_span!("node has some out-edges without counters", ?from_bcb).entered(); - for &to_bcb in successors { - debug!(?to_bcb, counter=?self.edge_counter(from_bcb, to_bcb)); - } - } + // Determine the set of out-edges that don't yet have edge counters. + let candidate_successors = self.basic_coverage_blocks.successors[from_bcb] + .iter() + .copied() + .filter(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)) + .collect::<Vec<_>>(); + debug!(?candidate_successors); - // Of the out-edges that don't have counters yet, one can be given an expression - // (computed from the other out-edges) instead of a dedicated counter. - let expression_to_bcb = self.choose_out_edge_for_expression(traversal, from_bcb); + // If there are out-edges without counters, choose one to be given an expression + // (computed from this node and the other out-edges) instead of a physical counter. + let Some(expression_to_bcb) = + self.choose_out_edge_for_expression(traversal, &candidate_successors) + else { + return; + }; // For each out-edge other than the one that was chosen to get an expression, // ensure that it has a counter (existing counter/expression or a new counter), @@ -324,10 +348,11 @@ impl<'a> MakeBcbCounters<'a> { .filter(|&to_bcb| to_bcb != expression_to_bcb) .map(|to_bcb| self.get_or_make_edge_counter(from_bcb, to_bcb)) .collect::<Vec<_>>(); - let sum_of_all_other_out_edges: BcbCounter = self - .coverage_counters - .make_sum(&other_out_edge_counters) - .expect("there must be at least one other out-edge"); + let Some(sum_of_all_other_out_edges) = + self.coverage_counters.make_sum(&other_out_edge_counters) + else { + return; + }; // Now create an expression for the chosen edge, by taking the counter // for its source node and subtracting the sum of its sibling out-edges. @@ -338,10 +363,13 @@ impl<'a> MakeBcbCounters<'a> { ); debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); - if self.basic_coverage_blocks.bcb_has_multiple_in_edges(expression_to_bcb) { - self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); - } else { + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(expression_to_bcb) { + // This edge normally wouldn't get its own counter, so attach the expression + // to its target node instead, so that `edge_has_no_counter` can see it. + assert_eq!(sole_pred, from_bcb); self.coverage_counters.set_bcb_counter(expression_to_bcb, expression); + } else { + self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); } } @@ -353,28 +381,21 @@ impl<'a> MakeBcbCounters<'a> { return counter_kind; } - // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). - // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the - // program results in a tight infinite loop, but it should still compile. - let one_path_to_target = !self.basic_coverage_blocks.bcb_has_multiple_in_edges(bcb); - if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { - let counter_kind = - self.coverage_counters.make_counter(CounterIncrementSite::Node { bcb }); - if one_path_to_target { - debug!("{bcb:?} gets a new counter: {counter_kind:?}"); - } else { - debug!( - "{bcb:?} has itself as its own predecessor. It can't be part of its own \ - Expression sum, so it will get its own new counter: {counter_kind:?}. \ - (Note, the compiled code will generate an infinite loop.)", - ); - } - return self.coverage_counters.set_bcb_counter(bcb, counter_kind); + let predecessors = self.basic_coverage_blocks.predecessors[bcb].as_slice(); + + // Handle cases where we can't compute a node's count from its in-edges: + // - START_BCB has no in-edges, so taking the sum would panic (or be wrong). + // - For nodes with one in-edge, or that directly loop to themselves, + // trying to get the in-edge counts would require this node's counter, + // leading to infinite recursion. + if predecessors.len() <= 1 || predecessors.contains(&bcb) { + debug!(?bcb, ?predecessors, "node has <=1 predecessors or is its own predecessor"); + return self.coverage_counters.make_phys_node_counter(bcb); } // A BCB with multiple incoming edges can compute its count by ensuring that counters // exist for each of those edges, and then adding them up to get a total count. - let in_edge_counters = self.basic_coverage_blocks.predecessors[bcb] + let in_edge_counters = predecessors .iter() .copied() .map(|from_bcb| self.get_or_make_edge_counter(from_bcb, bcb)) @@ -394,16 +415,19 @@ impl<'a> MakeBcbCounters<'a> { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> BcbCounter { - // If the target BCB has only one in-edge (i.e. this one), then create - // a node counter instead, since it will have the same value. - if !self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { - assert_eq!([from_bcb].as_slice(), self.basic_coverage_blocks.predecessors[to_bcb]); + // If the target node has exactly one in-edge (i.e. this one), then just + // use the node's counter, since it will have the same value. + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + assert_eq!(sole_pred, from_bcb); + // This call must take care not to invoke `get_or_make_edge` for + // this edge, since that would result in infinite recursion! return self.get_or_make_node_counter(to_bcb); } - // If the source BCB has only one successor (assumed to be the given target), an edge - // counter is unnecessary. Just get or make a counter for the source BCB. - if self.bcb_successors(from_bcb).len() == 1 { + // If the source node has exactly one out-edge (i.e. this one) and would have + // the same execution count as that edge, then just use the node's counter. + if let Some(simple_succ) = self.basic_coverage_blocks.simple_successor(from_bcb) { + assert_eq!(simple_succ, to_bcb); return self.get_or_make_node_counter(from_bcb); } @@ -416,118 +440,81 @@ impl<'a> MakeBcbCounters<'a> { } // Make a new counter to count this edge. - let counter_kind = - self.coverage_counters.make_counter(CounterIncrementSite::Edge { from_bcb, to_bcb }); - debug!("Edge {from_bcb:?}->{to_bcb:?} gets a new counter: {counter_kind:?}"); - self.coverage_counters.set_bcb_edge_counter(from_bcb, to_bcb, counter_kind) + self.coverage_counters.make_phys_edge_counter(from_bcb, to_bcb) } - /// Choose one of the out-edges of `from_bcb` to receive an expression - /// instead of a physical counter, and returns that edge's target node. - /// - /// - Precondition: The node must have at least one out-edge without a counter. - /// - Postcondition: The selected edge does not have an edge counter. + /// Given a set of candidate out-edges (represented by their successor node), + /// choose one to be given a counter expression instead of a physical counter. fn choose_out_edge_for_expression( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, - ) -> BasicCoverageBlock { - if let Some(reloop_target) = self.find_good_reloop_edge(traversal, from_bcb) { - assert!(self.edge_has_no_counter(from_bcb, reloop_target)); + candidate_successors: &[BasicCoverageBlock], + ) -> Option<BasicCoverageBlock> { + // Try to find a candidate that leads back to the top of a loop, + // because reloop edges tend to be executed more times than loop-exit edges. + if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) { debug!("Selecting reloop target {reloop_target:?} to get an expression"); - return reloop_target; + return Some(reloop_target); } - // We couldn't identify a "good" edge, so just choose any edge that - // doesn't already have a counter. - let arbitrary_target = self - .bcb_successors(from_bcb) - .iter() - .copied() - .find(|&to_bcb| self.edge_has_no_counter(from_bcb, to_bcb)) - .expect("precondition: at least one out-edge without a counter"); + // We couldn't identify a "good" edge, so just choose an arbitrary one. + let arbitrary_target = candidate_successors.first().copied()?; debug!(?arbitrary_target, "selecting arbitrary out-edge to get an expression"); - arbitrary_target + Some(arbitrary_target) } - /// Tries to find an edge that leads back to the top of a loop, and that - /// doesn't already have a counter. Such edges are good candidates to - /// be given an expression (instead of a physical counter), because they - /// will tend to be executed more times than a loop-exit edge. + /// Given a set of candidate out-edges (represented by their successor node), + /// tries to find one that leads back to the top of a loop. + /// + /// Reloop edges are good candidates for counter expressions, because they + /// will tend to be executed more times than a loop-exit edge, so it's nice + /// for them to be able to avoid a physical counter increment. fn find_good_reloop_edge( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - from_bcb: BasicCoverageBlock, + candidate_successors: &[BasicCoverageBlock], ) -> Option<BasicCoverageBlock> { - let successors = self.bcb_successors(from_bcb); + // If there are no candidates, avoid iterating over the loop stack. + if candidate_successors.is_empty() { + return None; + } // Consider each loop on the current traversal context stack, top-down. for reloop_bcbs in traversal.reloop_bcbs_per_loop() { - let mut all_edges_exit_this_loop = true; - - // Try to find an out-edge that doesn't exit this loop and doesn't - // already have a counter. - for &target_bcb in successors { + // Try to find a candidate edge that doesn't exit this loop. + for &target_bcb in candidate_successors { // An edge is a reloop edge if its target dominates any BCB that has // an edge back to the loop header. (Otherwise it's an exit edge.) let is_reloop_edge = reloop_bcbs.iter().any(|&reloop_bcb| { self.basic_coverage_blocks.dominates(target_bcb, reloop_bcb) }); - if is_reloop_edge { - all_edges_exit_this_loop = false; - if self.edge_has_no_counter(from_bcb, target_bcb) { - // We found a good out-edge to be given an expression. - return Some(target_bcb); - } - // Keep looking for another reloop edge without a counter. - } else { - // This edge exits the loop. + // We found a good out-edge to be given an expression. + return Some(target_bcb); } } - if !all_edges_exit_this_loop { - // We found one or more reloop edges, but all of them already - // have counters. Let the caller choose one of the other edges. - debug!("All reloop edges had counters; skipping the other loops"); - return None; - } - - // All of the out-edges exit this loop, so keep looking for a good - // reloop edge for one of the outer loops. + // All of the candidate edges exit this loop, so keep looking + // for a good reloop edge for one of the outer loops. } None } #[inline] - fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { - &self.basic_coverage_blocks.predecessors[bcb] - } - - #[inline] - fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &[BasicCoverageBlock] { - &self.basic_coverage_blocks.successors[bcb] - } - - #[inline] fn edge_has_no_counter( &self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> bool { - self.edge_counter(from_bcb, to_bcb).is_none() - } + let edge_counter = + if let Some(sole_pred) = self.basic_coverage_blocks.sole_predecessor(to_bcb) { + assert_eq!(sole_pred, from_bcb); + self.coverage_counters.bcb_counters[to_bcb] + } else { + self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)).copied() + }; - fn edge_counter( - &self, - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - ) -> Option<&BcbCounter> { - if self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { - self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) - } else { - self.coverage_counters.bcb_counters[to_bcb].as_ref() - } + edge_counter.is_none() } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 0d874a6c8ba..743aa679058 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -87,7 +87,11 @@ impl CoverageGraph { for &bb in basic_blocks.iter() { bb_to_bcb[bb] = Some(bcb); } - let bcb_data = BasicCoverageBlockData::from(basic_blocks); + + let is_out_summable = basic_blocks.last().map_or(false, |&bb| { + bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable() + }); + let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable }; debug!("adding bcb{}: {:?}", bcb.index(), bcb_data); bcbs.push(bcb_data); }; @@ -161,23 +165,33 @@ impl CoverageGraph { self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } - /// Returns true if the given node has 2 or more in-edges, i.e. 2 or more - /// predecessors. - /// - /// This property is interesting to code that assigns counters to nodes and - /// edges, because if a node _doesn't_ have multiple in-edges, then there's - /// no benefit in having a separate counter for its in-edge, because it - /// would have the same value as the node's own counter. - /// - /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? - #[inline(always)] - pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { - // Even though bcb0 conceptually has an extra virtual in-edge due to - // being the entry point, we've already asserted that it has no _other_ - // in-edges, so there's no possibility of it having _multiple_ in-edges. - // (And since its virtual in-edge doesn't exist in the graph, that edge - // can't have a separate counter anyway.) - self.predecessors[bcb].len() > 1 + /// Returns the source of this node's sole in-edge, if it has exactly one. + /// That edge can be assumed to have the same execution count as the node + /// itself (in the absence of panics). + pub(crate) fn sole_predecessor( + &self, + to_bcb: BasicCoverageBlock, + ) -> Option<BasicCoverageBlock> { + // Unlike `simple_successor`, there is no need for extra checks here. + if let &[from_bcb] = self.predecessors[to_bcb].as_slice() { Some(from_bcb) } else { None } + } + + /// Returns the target of this node's sole out-edge, if it has exactly + /// one, but only if that edge can be assumed to have the same execution + /// count as the node itself (in the absence of panics). + pub(crate) fn simple_successor( + &self, + from_bcb: BasicCoverageBlock, + ) -> Option<BasicCoverageBlock> { + // If a node's count is the sum of its out-edges, and it has exactly + // one out-edge, then that edge has the same count as the node. + if self.bcbs[from_bcb].is_out_summable + && let &[to_bcb] = self.successors[from_bcb].as_slice() + { + Some(to_bcb) + } else { + None + } } } @@ -266,14 +280,16 @@ rustc_index::newtype_index! { #[derive(Debug, Clone)] pub(crate) struct BasicCoverageBlockData { pub(crate) basic_blocks: Vec<BasicBlock>, + + /// If true, this node's execution count can be assumed to be the sum of the + /// execution counts of all of its **out-edges** (assuming no panics). + /// + /// Notably, this is false for a node ending with [`TerminatorKind::Yield`], + /// because the yielding coroutine might not be resumed. + pub(crate) is_out_summable: bool, } impl BasicCoverageBlockData { - fn from(basic_blocks: Vec<BasicBlock>) -> Self { - assert!(basic_blocks.len() > 0); - Self { basic_blocks } - } - #[inline(always)] pub(crate) fn leader_bb(&self) -> BasicBlock { self.basic_blocks[0] @@ -295,6 +311,9 @@ enum CoverageSuccessors<'a> { Chainable(BasicBlock), /// The block cannot be combined into the same BCB as its successor(s). NotChainable(&'a [BasicBlock]), + /// Yield terminators are not chainable, and their execution count can also + /// differ from the execution count of their out-edge. + Yield(BasicBlock), } impl CoverageSuccessors<'_> { @@ -302,6 +321,17 @@ impl CoverageSuccessors<'_> { match self { Self::Chainable(_) => true, Self::NotChainable(_) => false, + Self::Yield(_) => false, + } + } + + /// Returns true if the terminator itself is assumed to have the same + /// execution count as the sum of its out-edges (assuming no panics). + fn is_out_summable(&self) -> bool { + match self { + Self::Chainable(_) => true, + Self::NotChainable(_) => true, + Self::Yield(_) => false, } } } @@ -312,7 +342,9 @@ impl IntoIterator for CoverageSuccessors<'_> { fn into_iter(self) -> Self::IntoIter { match self { - Self::Chainable(bb) => Some(bb).into_iter().chain((&[]).iter().copied()), + Self::Chainable(bb) | Self::Yield(bb) => { + Some(bb).into_iter().chain((&[]).iter().copied()) + } Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()), } } @@ -331,7 +363,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera // A yield terminator has exactly 1 successor, but should not be chained, // because its resume edge has a different execution count. - Yield { ref resume, .. } => CoverageSuccessors::NotChainable(std::slice::from_ref(resume)), + Yield { resume, .. } => CoverageSuccessors::Yield(resume), // These terminators have exactly one coverage-relevant successor, // and can be chained into it. @@ -341,15 +373,15 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera | FalseUnwind { real_target: target, .. } | Goto { target } => CoverageSuccessors::Chainable(target), - // A call terminator can normally be chained, except when they have no - // successor because they are known to diverge. + // A call terminator can normally be chained, except when it has no + // successor because it is known to diverge. Call { target: maybe_target, .. } => match maybe_target { Some(target) => CoverageSuccessors::Chainable(target), None => CoverageSuccessors::NotChainable(&[]), }, - // An inline asm terminator can normally be chained, except when it diverges or uses asm - // goto. + // An inline asm terminator can normally be chained, except when it + // diverges or uses asm goto. InlineAsm { ref targets, .. } => { if let [target] = targets[..] { CoverageSuccessors::Chainable(target) diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f1bd803d835..47d04d8a00b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1070,19 +1070,26 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let locals = local_decls_for_sig(&sig, span); let mut fields = vec![]; + + // Move all of the closure args. for idx in 1..sig.inputs().len() { fields.push(Operand::Move(Local::from_usize(idx + 1).into())); } + for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() { if receiver_by_ref { // The only situation where it's possible is when we capture immuatable references, // since those don't need to be reborrowed with the closure's env lifetime. Since // references are always `Copy`, just emit a copy. - assert_matches!( - ty.kind(), - ty::Ref(_, _, hir::Mutability::Not), - "field should be captured by immutable ref if we have an `Fn` instance" - ); + if !matches!(ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) { + // This copy is only sound if it's a `&T`. This may be + // reachable e.g. when eagerly computing the `Fn` instance + // of an async closure that doesn't borrowck. + tcx.dcx().delayed_bug(format!( + "field should be captured by immutable ref if we have \ + an `Fn` instance, but it was: {ty}" + )); + } fields.push(Operand::Copy(tcx.mk_place_field( self_local, FieldIdx::from_usize(idx), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0aa351cad40..4bf2cc287da 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -402,6 +402,8 @@ pub(crate) enum PathSource<'a> { TraitItem(Namespace), // Paths in delegation item Delegation, + /// An arg in a `use<'a, N>` precise-capturing bound. + PreciseCapturingArg(Namespace), } impl<'a> PathSource<'a> { @@ -413,6 +415,7 @@ impl<'a> PathSource<'a> { | PathSource::TupleStruct(..) | PathSource::Delegation => ValueNS, PathSource::TraitItem(ns) => ns, + PathSource::PreciseCapturingArg(ns) => ns, } } @@ -423,7 +426,10 @@ impl<'a> PathSource<'a> { | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct(..) => true, - PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation => false, + PathSource::Trait(_) + | PathSource::TraitItem(..) + | PathSource::Delegation + | PathSource::PreciseCapturingArg(..) => false, } } @@ -466,6 +472,7 @@ impl<'a> PathSource<'a> { _ => "value", }, PathSource::Delegation => "function", + PathSource::PreciseCapturingArg(..) => "type or const parameter", } } @@ -534,6 +541,15 @@ impl<'a> PathSource<'a> { _ => false, }, PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)), + PathSource::PreciseCapturingArg(ValueNS) => { + matches!(res, Res::Def(DefKind::ConstParam, _)) + } + // We allow `SelfTyAlias` here so we can give a more descriptive error later. + PathSource::PreciseCapturingArg(TypeNS) => matches!( + res, + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } + ), + PathSource::PreciseCapturingArg(MacroNS) => false, } } @@ -551,6 +567,8 @@ impl<'a> PathSource<'a> { (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531, (PathSource::TraitItem(..), true) => E0575, (PathSource::TraitItem(..), false) => E0576, + (PathSource::PreciseCapturingArg(..), true) => E0799, + (PathSource::PreciseCapturingArg(..), false) => E0800, } } } @@ -1077,9 +1095,19 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }; // Like `Ty::Param`, we try resolving this as both a const and a type. if !check_ns(TypeNS) && check_ns(ValueNS) { - self.smart_resolve_path(*id, &None, path, PathSource::Expr(None)); + self.smart_resolve_path( + *id, + &None, + path, + PathSource::PreciseCapturingArg(ValueNS), + ); } else { - self.smart_resolve_path(*id, &None, path, PathSource::Type); + self.smart_resolve_path( + *id, + &None, + path, + PathSource::PreciseCapturingArg(TypeNS), + ); } } } @@ -1889,7 +1917,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); let inferred = match source { - PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => false, + PathSource::Trait(..) + | PathSource::TraitItem(..) + | PathSource::Type + | PathSource::PreciseCapturingArg(..) => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct @@ -3982,7 +4013,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { Applicability::MaybeIncorrect, )) } else if res.is_none() - && let PathSource::Type | PathSource::Expr(_) = source + && let PathSource::Type + | PathSource::Expr(_) + | PathSource::PreciseCapturingArg(..) = source { this.suggest_adding_generic_parameter(path, source) } else { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1c584bf8338..b5974e001aa 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2068,33 +2068,34 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ) { let res = binding.res(); if filter_fn(res) { - let def_id = res.def_id(); - let has_self = match def_id.as_local() { - Some(def_id) => { - self.r.delegation_fn_sigs.get(&def_id).map_or(false, |sig| sig.has_self) - } - None => self - .r - .tcx - .fn_arg_names(def_id) - .first() - .is_some_and(|ident| ident.name == kw::SelfLower), - }; - if has_self { - return Some(AssocSuggestion::MethodWithSelf { called }); - } else { - match res { - Res::Def(DefKind::AssocFn, _) => { + match res { + Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => { + let has_self = match def_id.as_local() { + Some(def_id) => self + .r + .delegation_fn_sigs + .get(&def_id) + .map_or(false, |sig| sig.has_self), + None => self + .r + .tcx + .fn_arg_names(def_id) + .first() + .is_some_and(|ident| ident.name == kw::SelfLower), + }; + if has_self { + return Some(AssocSuggestion::MethodWithSelf { called }); + } else { return Some(AssocSuggestion::AssocFn { called }); } - Res::Def(DefKind::AssocConst, _) => { - return Some(AssocSuggestion::AssocConst); - } - Res::Def(DefKind::AssocTy, _) => { - return Some(AssocSuggestion::AssocType); - } - _ => {} } + Res::Def(DefKind::AssocConst, _) => { + return Some(AssocSuggestion::AssocConst); + } + Res::Def(DefKind::AssocTy, _) => { + return Some(AssocSuggestion::AssocType); + } + _ => {} } } } @@ -2538,8 +2539,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } let (msg, sugg) = match source { - PathSource::Type => ("you might be missing a type parameter", ident), - PathSource::Expr(_) => ("you might be missing a const parameter", format!("const {ident}: /* Type */")), + PathSource::Type | PathSource::PreciseCapturingArg(TypeNS) => { + ("you might be missing a type parameter", ident) + } + PathSource::Expr(_) | PathSource::PreciseCapturingArg(ValueNS) => ( + "you might be missing a const parameter", + format!("const {ident}: /* Type */"), + ), _ => return None, }; let (span, sugg) = if let [.., param] = &generics.params[..] { diff --git a/library/std/src/process.rs b/library/std/src/process.rs index a155855029e..60d452465da 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1910,10 +1910,14 @@ impl crate::error::Error for ExitStatusError {} /// to its parent under normal termination. /// /// `ExitCode` is intended to be consumed only by the standard library (via -/// [`Termination::report()`]), and intentionally does not provide accessors like -/// `PartialEq`, `Eq`, or `Hash`. Instead the standard library provides the -/// canonical `SUCCESS` and `FAILURE` exit codes as well as `From<u8> for -/// ExitCode` for constructing other arbitrary exit codes. +/// [`Termination::report()`]). For forwards compatibility with potentially +/// unusual targets, this type currently does not provide `Eq`, `Hash`, or +/// access to the raw value. This type does provide `PartialEq` for +/// comparison, but note that there may potentially be multiple failure +/// codes, some of which will _not_ compare equal to `ExitCode::FAILURE`. +/// The standard library provides the canonical `SUCCESS` and `FAILURE` +/// exit codes as well as `From<u8> for ExitCode` for constructing other +/// arbitrary exit codes. /// /// # Portability /// @@ -1952,7 +1956,7 @@ impl crate::error::Error for ExitStatusError {} /// ExitCode::SUCCESS /// } /// ``` -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] #[stable(feature = "process_exitcode", since = "1.61.0")] pub struct ExitCode(imp::ExitCode); diff --git a/tests/assembly/simd/reduce-fadd-unordered.rs b/tests/assembly/simd/reduce-fadd-unordered.rs index fa9ce6bd35e..ade60ba184c 100644 --- a/tests/assembly/simd/reduce-fadd-unordered.rs +++ b/tests/assembly/simd/reduce-fadd-unordered.rs @@ -4,6 +4,7 @@ //@[aarch64] only-aarch64 //@[x86_64] only-x86_64 //@[x86_64] compile-flags: -Ctarget-feature=+sse3 +//@ ignore-sgx Test incompatible with LVI mitigations #![feature(portable_simd)] #![feature(core_intrinsics)] use std::intrinsics::simd as intrinsics; diff --git a/tests/crashes/129850.rs b/tests/crashes/129850.rs deleted file mode 100644 index 9c04805587a..00000000000 --- a/tests/crashes/129850.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: rust-lang/rust#129850 - -pub trait Foo2 { - fn bar<'a: 'a>(&'a mut self) -> impl Sized + use<'static>; -} - -impl Foo2 for () { - fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {} -} diff --git a/tests/crashes/130372-1.rs b/tests/crashes/130372-1.rs deleted file mode 100644 index 5d58c14e7ab..00000000000 --- a/tests/crashes/130372-1.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: rust-lang/rust#130372 - -pub fn variadic_fn(n: usize, mut args: ...) {} - -reuse variadic_fn; - -fn main() { - variadic_fn(); -} diff --git a/tests/crashes/130372-2.rs b/tests/crashes/130372-2.rs deleted file mode 100644 index 46404191e32..00000000000 --- a/tests/crashes/130372-2.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#130372 - -pub fn test_va_copy(_: u64, mut ap: ...) {} - -pub fn main() { - unsafe { - test_va_copy(); - - call(x); - } -} diff --git a/tests/crashes/130372-3.rs b/tests/crashes/130372-3.rs deleted file mode 100644 index 6e1c57437c8..00000000000 --- a/tests/crashes/130372-3.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: rust-lang/rust#130372 - -fn bar() -> impl Fn() { - wrap() -} - -fn wrap(...: impl ...) -> impl Fn() {} diff --git a/tests/crashes/130399.rs b/tests/crashes/130399.rs deleted file mode 100644 index 2248c8c0124..00000000000 --- a/tests/crashes/130399.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#130399 - -fn elided(main: &()) -> impl Sized + use<main> {} - -fn main() {} diff --git a/tests/crashes/129262.rs b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs index c430af35988..4cbbefb0f52 100644 --- a/tests/crashes/129262.rs +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.rs @@ -1,4 +1,3 @@ -//@ known-bug: rust-lang/rust#129262 //@ compile-flags: -Zvalidate-mir --edition=2018 --crate-type=lib -Copt-level=3 #![feature(async_closure)] @@ -11,6 +10,7 @@ fn needs_fn_mut<T>(mut x: impl FnMut() -> T) { fn hello(x: Ty) { needs_fn_mut(async || { + //~^ ERROR cannot move out of `x` x.hello(); }); } diff --git a/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr new file mode 100644 index 00000000000..bab26c19482 --- /dev/null +++ b/tests/ui/async-await/async-closures/closure-shim-borrowck-error.stderr @@ -0,0 +1,24 @@ +error[E0507]: cannot move out of `x` which is behind a mutable reference + --> $DIR/closure-shim-borrowck-error.rs:12:18 + | +LL | needs_fn_mut(async || { + | ^^^^^^^^ `x` is moved here +LL | +LL | x.hello(); + | - + | | + | variable moved due to use in coroutine + | move occurs because `x` has type `Ty`, which does not implement the `Copy` trait + | +note: if `Ty` implemented `Clone`, you could clone the value + --> $DIR/closure-shim-borrowck-error.rs:18:1 + | +LL | x.hello(); + | - you could clone this value +... +LL | struct Ty; + | ^^^^^^^^^ consider implementing `Clone` for this type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs b/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs new file mode 100644 index 00000000000..6f339f0c8ef --- /dev/null +++ b/tests/ui/async-await/async-closures/debuginfo-by-move-body.rs @@ -0,0 +1,19 @@ +//@ aux-build:block-on.rs +//@ edition: 2021 +//@ build-pass +//@ compile-flags: -Cdebuginfo=2 + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +pub fn main() { + block_on::block_on(async { + let async_closure = async move || {}; + call_once(async_closure).await; + }); +} diff --git a/tests/ui/error-codes/E0799.rs b/tests/ui/error-codes/E0799.rs new file mode 100644 index 00000000000..a1e5b532669 --- /dev/null +++ b/tests/ui/error-codes/E0799.rs @@ -0,0 +1,4 @@ +fn test() -> impl Sized + use<main> {} +//~^ ERROR E0799 + +fn main() {} diff --git a/tests/ui/error-codes/E0799.stderr b/tests/ui/error-codes/E0799.stderr new file mode 100644 index 00000000000..3639424e466 --- /dev/null +++ b/tests/ui/error-codes/E0799.stderr @@ -0,0 +1,9 @@ +error[E0799]: expected type or const parameter, found function `main` + --> $DIR/E0799.rs:1:31 + | +LL | fn test() -> impl Sized + use<main> {} + | ^^^^ not a type or const parameter + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0799`. diff --git a/tests/ui/error-codes/E0800.rs b/tests/ui/error-codes/E0800.rs new file mode 100644 index 00000000000..6112157feca --- /dev/null +++ b/tests/ui/error-codes/E0800.rs @@ -0,0 +1,4 @@ +fn test() -> impl Sized + use<Missing> {} +//~^ ERROR E0800 + +fn main() {} diff --git a/tests/ui/error-codes/E0800.stderr b/tests/ui/error-codes/E0800.stderr new file mode 100644 index 00000000000..282981a9173 --- /dev/null +++ b/tests/ui/error-codes/E0800.stderr @@ -0,0 +1,9 @@ +error[E0800]: cannot find type or const parameter `Missing` in this scope + --> $DIR/E0800.rs:1:31 + | +LL | fn test() -> impl Sized + use<Missing> {} + | ^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0800`. diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 17b517abd74..d1ec48df48c 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -1,8 +1,8 @@ fn missing() -> impl Sized + use<T> {} -//~^ ERROR cannot find type `T` in this scope +//~^ ERROR cannot find type or const parameter `T` in this scope fn missing_self() -> impl Sized + use<Self> {} -//~^ ERROR cannot find type `Self` in this scope +//~^ ERROR cannot find type or const parameter `Self` in this scope struct MyType; impl MyType { @@ -11,6 +11,9 @@ impl MyType { } fn hello() -> impl Sized + use<hello> {} -//~^ ERROR expected type or const parameter in `use<...>` precise captures list, found function +//~^ ERROR expected type or const parameter, found function `hello` + +fn arg(x: ()) -> impl Sized + use<x> {} +//~^ ERROR expected type or const parameter, found local variable `x` fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index 06ccf356948..07ada8da300 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,4 +1,4 @@ -error[E0412]: cannot find type `T` in this scope +error[E0800]: cannot find type or const parameter `T` in this scope --> $DIR/bad-params.rs:1:34 | LL | fn missing() -> impl Sized + use<T> {} @@ -9,7 +9,7 @@ help: you might be missing a type parameter LL | fn missing<T>() -> impl Sized + use<T> {} | +++ -error[E0411]: cannot find type `Self` in this scope +error[E0411]: cannot find type or const parameter `Self` in this scope --> $DIR/bad-params.rs:4:39 | LL | fn missing_self() -> impl Sized + use<Self> {} @@ -17,7 +17,19 @@ LL | fn missing_self() -> impl Sized + use<Self> {} | | | `Self` not allowed in a function -error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias +error[E0799]: expected type or const parameter, found function `hello` + --> $DIR/bad-params.rs:13:32 + | +LL | fn hello() -> impl Sized + use<hello> {} + | ^^^^^ not a type or const parameter + +error[E0799]: expected type or const parameter, found local variable `x` + --> $DIR/bad-params.rs:16:35 + | +LL | fn arg(x: ()) -> impl Sized + use<x> {} + | ^ not a type or const parameter + +error[E0799]: `Self` can't be captured in `use<...>` precise captures list, since it is an alias --> $DIR/bad-params.rs:9:48 | LL | impl MyType { @@ -25,13 +37,7 @@ LL | impl MyType { LL | fn self_is_not_param() -> impl Sized + use<Self> {} | ^^^^ -error: expected type or const parameter in `use<...>` precise captures list, found function - --> $DIR/bad-params.rs:13:32 - | -LL | fn hello() -> impl Sized + use<hello> {} - | ^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0411, E0412. +Some errors have detailed explanations: E0411, E0799, E0800. For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs new file mode 100644 index 00000000000..71a91fe319e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -0,0 +1,16 @@ +// Make sure we don't ICE when an RPITIT captures more method args than the +// trait definition, which is not allowed. Due to the default lifetime capture +// rules of RPITITs, this is only doable if we use precise capturing. + +pub trait Foo { + fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits +} + +impl Foo for () { + fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + //~^ ERROR return type captures more lifetimes than trait definition + //~| WARN impl trait in impl method signature does not match trait method signature +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr new file mode 100644 index 00000000000..339e2e6335e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -0,0 +1,42 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: return type captures more lifetimes than trait definition + --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + | +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + | --- ^^^^^^^^^^^^^^^^ + | | + | this lifetime was captured + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: hidden type inferred to be `impl Sized + 'im` + +warning: impl trait in impl method signature does not match trait method signature + --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + | +LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use<Self>; + | ---------------------- return type from trait method defined here +... +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + | ^^^^^^^^^^^^^^^^ + | + = 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 <https://github.com/rust-lang/rust/issues/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 bar<'im: 'im>(&'im mut self) -> impl Sized {} + | ~~~~~~~~~~ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/methods/probe-error-on-infinite-deref.rs b/tests/ui/methods/probe-error-on-infinite-deref.rs new file mode 100644 index 00000000000..85c1c0c09c1 --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.rs @@ -0,0 +1,16 @@ +use std::ops::Deref; + +// Make sure that method probe error reporting doesn't get too tangled up +// on this infinite deref impl. See #130224. + +struct Wrap<T>(T); +impl<T> Deref for Wrap<T> { + type Target = Wrap<Wrap<T>>; + fn deref(&self) -> &Wrap<Wrap<T>> { todo!() } +} + +fn main() { + Wrap(1).lmao(); + //~^ ERROR reached the recursion limit + //~| ERROR no method named `lmao` +} diff --git a/tests/ui/methods/probe-error-on-infinite-deref.stderr b/tests/ui/methods/probe-error-on-infinite-deref.stderr new file mode 100644 index 00000000000..57a9ca2eaa8 --- /dev/null +++ b/tests/ui/methods/probe-error-on-infinite-deref.stderr @@ -0,0 +1,21 @@ +error[E0055]: reached the recursion limit while auto-dereferencing `Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<{integer}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | Wrap(1).lmao(); + | ^^^^ deref recursion limit reached + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`probe_error_on_infinite_deref`) + +error[E0599]: no method named `lmao` found for struct `Wrap<{integer}>` in the current scope + --> $DIR/probe-error-on-infinite-deref.rs:13:13 + | +LL | struct Wrap<T>(T); + | -------------- method `lmao` not found for this struct +... +LL | Wrap(1).lmao(); + | ^^^^ method not found in `Wrap<{integer}>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0055, E0599. +For more information about an error, try `rustc --explain E0055`. diff --git a/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs new file mode 100644 index 00000000000..60a3b47010e --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.rs @@ -0,0 +1,12 @@ +#![feature(c_variadic)] + +// Regression test that covers all 3 cases of https://github.com/rust-lang/rust/issues/130372 + +unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {} + +pub fn main() { + unsafe { + test_va_copy(); + //~^ ERROR this function takes at least 1 argument but 0 arguments were supplied + } +} diff --git a/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr new file mode 100644 index 00000000000..38f76970358 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-args-vargs-issue-130372.stderr @@ -0,0 +1,19 @@ +error[E0060]: this function takes at least 1 argument but 0 arguments were supplied + --> $DIR/mismatch-args-vargs-issue-130372.rs:9:9 + | +LL | test_va_copy(); + | ^^^^^^^^^^^^-- argument #1 of type `u64` is missing + | +note: function defined here + --> $DIR/mismatch-args-vargs-issue-130372.rs:5:22 + | +LL | unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) {} + | ^^^^^^^^^^^^ ------ +help: provide the argument + | +LL | test_va_copy(/* u64 */); + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0060`. diff --git a/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs b/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs new file mode 100644 index 00000000000..952957ec480 --- /dev/null +++ b/tests/ui/resolve/auxiliary/foreign-trait-with-assoc.rs @@ -0,0 +1,3 @@ +pub trait Foo { + type Bar; +} diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs new file mode 100644 index 00000000000..20bbbff8fd2 --- /dev/null +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.rs @@ -0,0 +1,11 @@ +//@ aux-build:foreign-trait-with-assoc.rs + +extern crate foreign_trait_with_assoc; +use foreign_trait_with_assoc::Foo; + +// Make sure we don't try to call `fn_arg_names` on a non-fn item. + +impl Foo for Bar {} +//~^ ERROR cannot find type `Bar` in this scope + +fn main() {} diff --git a/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr new file mode 100644 index 00000000000..a1a8bb575e1 --- /dev/null +++ b/tests/ui/resolve/dont-compute-arg-names-for-non-fn.stderr @@ -0,0 +1,14 @@ +error[E0412]: cannot find type `Bar` in this scope + --> $DIR/dont-compute-arg-names-for-non-fn.rs:8:14 + | +LL | impl Foo for Bar {} + | ^^^ + | +help: you might have meant to use the associated type + | +LL | impl Foo for Self::Bar {} + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. |
