diff --git a/Cargo.lock b/Cargo.lock index 0f6368e4497cb..f2bdc1fc20e39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4267,6 +4267,7 @@ dependencies = [ "rustc_parse_format", "rustc_session", "rustc_span", + "rustc_symbol_mangling", "rustc_target", "rustc_trait_selection", "smallvec", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 52b54655d1ca1..c2bfb3033195e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3867,6 +3867,19 @@ pub struct Fn { pub eii_impls: ThinVec, } +impl Fn { + pub fn is_pin_drop_sugar(&self) -> bool { + self.ident.name == sym::drop + && self + .sig + .decl + .inputs + .first() + .and_then(|param| param.to_self()) + .is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut))) + } +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct EiiImpl { pub node_id: NodeId, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a673069ae5a72..e38415caaa222 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1192,6 +1192,52 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } + fn resolve_pin_drop_sugar_impl_item( + &self, + i: &AssocItem, + ident: Ident, + span: Span, + ) -> (Ident, Result) { + let trait_item_def_id = self + .get_partial_res(i.id) + .and_then(|r| r.expect_full_res().opt_def_id()) + .ok_or_else(|| { + self.dcx().span_delayed_bug(span, "could not resolve trait item being implemented") + }); + + let is_pin_drop_sugar = match &i.kind { + AssocItemKind::Fn(fn_kind) => fn_kind.is_pin_drop_sugar(), + _ => false, + }; + let def_id = match trait_item_def_id { + Ok(def_id) => def_id, + Err(guar) => return (ident, Err(guar)), + }; + if !is_pin_drop_sugar { + return (ident, Ok(def_id)); + } + + let is_drop_pin_drop = self + .tcx + .lang_items() + .drop_trait() + .is_some_and(|drop_trait| self.tcx.parent(def_id) == drop_trait); + if is_drop_pin_drop { + // Associated item collection still derives the impl item's name from HIR. + return (Ident::new(sym::pin_drop, ident.span), Ok(def_id)); + } + + let guar = self + .dcx() + .struct_span_err( + i.span, + "method `drop` with `&pin mut self` is only supported for the `Drop` trait", + ) + .with_span_label(i.span, "not a `Drop::pin_drop` implementation") + .emit(); + (ident, Err(guar)) + } + fn lower_impl_item( &mut self, i: &AssocItem, @@ -1309,26 +1355,19 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(i.span); + let (effective_ident, impl_kind) = if is_in_trait_impl { + let (effective_ident, trait_item_def_id) = + self.resolve_pin_drop_sugar_impl_item(i, ident, span); + (effective_ident, ImplItemImplKind::Trait { defaultness, trait_item_def_id }) + } else { + (ident, ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }) + }; + let item = hir::ImplItem { owner_id: hir_id.expect_owner(), - ident: self.lower_ident(ident), + ident: self.lower_ident(effective_ident), generics, - impl_kind: if is_in_trait_impl { - ImplItemImplKind::Trait { - defaultness, - trait_item_def_id: self - .get_partial_res(i.id) - .and_then(|r| r.expect_full_res().opt_def_id()) - .ok_or_else(|| { - self.dcx().span_delayed_bug( - span, - "could not resolve trait item being implemented", - ) - }), - } - } else { - ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) } - }, + impl_kind, kind, span, has_delayed_lints: !self.delayed_lints.is_empty(), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0fd47cb15f286..26d98ec13cc2b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -152,7 +152,20 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type)) ); - let pointee_type_di_node = type_di_node(cx, pointee_type); + let pointee_type_di_node = match pointee_type.kind() { + // `&[T]` will look like `{ data_ptr: *const T, length: usize }` + ty::Slice(element_type) => type_di_node(cx, *element_type), + // `&str` will look like `{ data_ptr: *const u8, length: usize }` + ty::Str => type_di_node(cx, cx.tcx.types.u8), + + // `&dyn K` will look like `{ pointer: _, vtable: _}` + // any Adt `Foo` containing an unsized type (eg `&[_]` or `&dyn _`) + // will look like `{ data_ptr: *const Foo, length: usize }` + // and thin pointers `&Foo` will just look like `*const Foo`. + // + // in all those cases, we just use the pointee_type + _ => type_di_node(cx, pointee_type), + }; return_if_di_node_created_in_meantime!(cx, unique_type_id); @@ -389,26 +402,11 @@ fn build_dyn_type_di_node<'ll, 'tcx>( } /// Create debuginfo for `[T]` and `str`. These are unsized. -/// -/// NOTE: We currently emit just emit the debuginfo for the element type here -/// (i.e. `T` for slices and `u8` for `str`), so that we end up with -/// `*const T` for the `data_ptr` field of the corresponding wide-pointer -/// debuginfo of `&[T]`. -/// -/// It would be preferable and more accurate if we emitted a DIArray of T -/// without an upper bound instead. That is, LLVM already supports emitting -/// debuginfo of arrays of unknown size. But GDB currently seems to end up -/// in an infinite loop when confronted with such a type. -/// -/// As a side effect of the current encoding every instance of a type like -/// `struct Foo { unsized_field: [u8] }` will look like -/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the -/// slice is zero, then accessing `unsized_field` in the debugger would -/// result in an out-of-bounds access. fn build_slice_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, slice_type: Ty<'tcx>, unique_type_id: UniqueTypeId<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let element_type = match slice_type.kind() { ty::Slice(element_type) => *element_type, @@ -423,7 +421,20 @@ fn build_slice_type_di_node<'ll, 'tcx>( let element_type_di_node = type_di_node(cx, element_type); return_if_di_node_created_in_meantime!(cx, unique_type_id); - DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false } + let (size, align) = cx.spanned_size_and_align_of(slice_type, span); + let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, -1) }; + let subscripts = &[subrange]; + let di_node = unsafe { + llvm::LLVMDIBuilderCreateArrayType( + DIB(cx), + size.bits(), + align.bits() as u32, + element_type_di_node, + subscripts.as_ptr(), + subscripts.len() as c_uint, + ) + }; + DINodeCreationResult { di_node, already_stored_in_typemap: false } } /// Get the debuginfo node for the given type. @@ -454,7 +465,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( } ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t), ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span), - ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id), + ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id, span), ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id), ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id), ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => { diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md index bd93626a8db4d..b194e11b7f85e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0755.md +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -20,7 +20,7 @@ side effects or infinite loops: extern "C" { #[unsafe(ffi_pure)] // ok! - pub fn strlen(s: *const i8) -> isize; + pub fn strlen(s: *const std::ffi::c_char) -> usize; } # fn main() {} ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md index daafc2a5ac092..74233a6ad7a7a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0756.md +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -21,7 +21,7 @@ which have no side effects except for their return value: extern "C" { #[unsafe(ffi_const)] // ok! - pub fn strlen(s: *const i8) -> i32; + pub fn strlen(s: *const std::ffi::c_char) -> usize; } # fn main() {} ``` diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 501ecadd392fc..35d0188769f51 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1088,6 +1088,93 @@ impl<'hir> Generics<'hir> { bound_span.with_lo(bounds[bound_pos - 1].span().hi()) } } + + /// Computes the span representing the removal of a generic parameter at `param_index`. + /// + /// This function identifies the correct slice of source code to delete so that the + /// remaining generic list remains syntactically valid (handling commas and brackets). + /// + /// ### Examples + /// + /// 1. **With a following parameter:** (Includes the trailing comma) + /// - Input: `` (index 0) + /// - Produces span for: `T, ` + /// + /// 2. **With a previous parameter:** (Includes the leading comma and bounds) + /// - Input: `` (index 1) + /// - Produces span for: `, U` + /// + /// 3. **The only parameter:** (Includes the angle brackets) + /// - Input: `` (index 0) + /// - Produces span for: `` + /// + /// 4. **Parameter with where-clause bounds:** + /// - Input: `fn foo() where T: Copy` (index 0) + /// - Produces span for: `T, ` (The where-clause remains for other logic to handle). + pub fn span_for_param_removal(&self, param_index: usize) -> Span { + if param_index >= self.params.len() { + return self.span.shrink_to_hi(); + } + + let is_param_explicit = |par: &&GenericParam<'_>| match par.kind { + GenericParamKind::Type { .. } + | GenericParamKind::Const { .. } + | GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit } => true, + _ => false, + }; + + // Find the span of the type parameter. + if let Some(next) = self.params[param_index + 1..].iter().find(is_param_explicit) { + self.params[param_index].span.until(next.span) + } else if let Some(prev) = self.params[..param_index].iter().rfind(is_param_explicit) { + let mut prev_span = prev.span; + // Consider the span of the bounds with the previous generic parameter when there is. + if let Some(prev_bounds_span) = self.span_for_param_bounds(prev) { + prev_span = prev_span.to(prev_bounds_span); + } + + // Consider the span of the bounds with the current generic parameter when there is. + prev_span.shrink_to_hi().to( + if let Some(cur_bounds_span) = self.span_for_param_bounds(&self.params[param_index]) + { + cur_bounds_span + } else { + self.params[param_index].span + }, + ) + } else { + // Remove also angle brackets <> when there is just ONE generic parameter. + self.span + } + } + + /// Returns the span of the `WherePredicate` associated with the given `GenericParam`, if any. + /// + /// This looks specifically for predicates in the `where` clause that were generated + /// from the parameter definition (e.g., `T` in `where T: Bound`). + /// + /// ### Example + /// + /// - Input: `param` representing `T` + /// - Context: `where T: Clone + Default, U: Copy` + /// - Returns: Span of `T: Clone + Default` + fn span_for_param_bounds(&self, param: &GenericParam<'hir>) -> Option { + self.predicates + .iter() + .find(|pred| { + if let WherePredicateKind::BoundPredicate(WhereBoundPredicate { + origin: PredicateOrigin::GenericParam, + bounded_ty, + .. + }) = pred.kind + { + bounded_ty.span == param.span + } else { + false + } + }) + .map(|pred| pred.span) + } } /// A single predicate in a where-clause. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 4a3615e5421fe..6896506a5f26b 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -448,6 +448,14 @@ language_item_table! { // Used to fallback `{float}` to `f32` when `f32: From<{float}>` From, sym::From, from_trait, Target::Trait, GenericRequirement::Exact(1); + + // Runtime symbols + MemCpy, sym::memcpy_fn, memcpy_fn, Target::Fn, GenericRequirement::None; + MemMove, sym::memmove_fn, memmove_fn, Target::Fn, GenericRequirement::None; + MemSet, sym::memset_fn, memset_fn, Target::Fn, GenericRequirement::None; + MemCmp, sym::memcmp_fn, memcmp_fn, Target::Fn, GenericRequirement::None; + Bcmp, sym::bcmp_fn, bcmp_fn, Target::Fn, GenericRequirement::None; + StrLen, sym::strlen_fn, strlen_fn, Target::Fn, GenericRequirement::None; } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b4e548effd46d..0652503bc28c3 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -23,8 +23,29 @@ macro_rules! weak_lang_items { } } +macro_rules! weak_only_lang_items { + ($($item:ident,)*) => { + pub static WEAK_ONLY_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*]; + + impl LangItem { + pub fn is_weak_only(self) -> bool { + matches!(self, $(LangItem::$item)|*) + } + } + } +} + weak_lang_items! { PanicImpl, rust_begin_unwind; EhPersonality, rust_eh_personality; EhCatchTypeinfo, rust_eh_catch_typeinfo; } + +weak_only_lang_items! { + MemCpy, + MemMove, + MemSet, + MemCmp, + Bcmp, + StrLen, +} diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index be8a8e228c47a..2d6d5a5d81f9a 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{ use rustc_span::{ErrorGuaranteed, Span, kw}; use crate::collect::ItemCtxt; +use crate::errors::DelegationSelfTypeNotSpecified; use crate::hir_ty_lowering::HirTyLowerer; type RemapTable = FxHashMap; @@ -284,6 +285,12 @@ fn get_delegation_self_ty_or_err(tcx: TyCtxt<'_>, delegation_id: LocalDefId) -> ctx.lower_ty(tcx.hir_node(id).expect_ty()) }) .unwrap_or_else(|| { + // It is possible to attempt to get self type when it is used in signature + // (i.e., `fn default() -> Self`), so emit error here in addition to possible + // `mismatched types` error (see #156388). + let err = DelegationSelfTypeNotSpecified { span: tcx.def_span(delegation_id) }; + tcx.dcx().emit_err(err); + Ty::new_error_with_message( tcx, tcx.def_span(delegation_id), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 9fc26a3b80744..0f549e157c280 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -15,6 +15,8 @@ pub(crate) mod wrong_number_of_generic_args; mod precise_captures; pub(crate) use precise_captures::*; +pub(crate) mod remove_or_use_generic; + #[derive(Diagnostic)] #[diag("ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`")] pub(crate) struct AmbiguousAssocItem<'a> { @@ -1670,6 +1672,14 @@ pub(crate) struct UnsupportedDelegation<'a> { pub callee_span: Span, } +#[derive(Diagnostic)] +#[diag("delegation self type is not specified")] +#[help("consider explicitly specifying self type: `reuse ::function`")] +pub(crate) struct DelegationSelfTypeNotSpecified { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("method should be `async` or return a future, but it is synchronous")] pub(crate) struct MethodShouldReturnFuture { diff --git a/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs b/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs new file mode 100644 index 0000000000000..41d22ff041853 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs @@ -0,0 +1,211 @@ +use std::ops::ControlFlow; + +use rustc_errors::{Applicability, Diag}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::{self, Visitor, walk_lifetime}; +use rustc_hir::{GenericArg, HirId, LifetimeKind, Path, QPath, TyKind}; +use rustc_middle::hir::nested_filter::All; +use rustc_middle::ty::{GenericParamDef, GenericParamDefKind, TyCtxt}; + +use crate::hir::def::Res; + +/// Use a Visitor to find usages of the type or lifetime parameter +struct ParamUsageVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + /// The `DefId` of the generic parameter we are looking for. + param_def_id: DefId, + found: bool, +} + +impl<'tcx> Visitor<'tcx> for ParamUsageVisitor<'tcx> { + type NestedFilter = All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + type Result = ControlFlow<()>; + + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result { + if let Some(res_def_id) = path.res.opt_def_id() { + if res_def_id == self.param_def_id { + self.found = true; + return ControlFlow::Break(()); + } + } + intravisit::walk_path(self, path) + } + + fn visit_lifetime(&mut self, lifetime: &'tcx rustc_hir::Lifetime) -> Self::Result { + if let LifetimeKind::Param(id) = lifetime.kind { + if let Some(local_def_id) = self.param_def_id.as_local() { + if id == local_def_id { + self.found = true; + return ControlFlow::Break(()); + } + } + } + walk_lifetime(self, lifetime) + } +} + +/// Adds a suggestion to a diagnostic to either remove an unused generic parameter, or use it. +/// +/// # Examples +/// +/// - `impl Struct { ... }` where `T` is unused -> suggests removing `T` or using it. +/// - `impl Struct { // T used in here }` where `T` is used in the body but not in the self type -> suggests adding `T` to the self type and struct definition. +/// - `impl Struct { ... }` where the struct has a generic parameter with a default -> suggests adding `T` to the self type. +pub(crate) fn suggest_to_remove_or_use_generic( + tcx: TyCtxt<'_>, + diag: &mut Diag<'_>, + impl_def_id: LocalDefId, + param: &GenericParamDef, + is_lifetime: bool, +) { + let node = tcx.hir_node_by_def_id(impl_def_id); + let hir_impl = node.expect_item().expect_impl(); + + let Some((index, _)) = hir_impl + .generics + .params + .iter() + .enumerate() + .find(|(_, par)| par.def_id.to_def_id() == param.def_id) + else { + return; + }; + + // Get the Struct/ADT definition ID from the self type + let struct_def_id = if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind + && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, def_id) = path.res + { + def_id + } else { + return; + }; + + // Count how many generic parameters are defined in the struct definition + let generics = tcx.generics_of(struct_def_id); + let total_params = generics + .own_params + .iter() + .filter(|p| { + if is_lifetime { + matches!(p.kind, GenericParamDefKind::Lifetime) + } else { + matches!(p.kind, GenericParamDefKind::Type { .. }) + } + }) + .count(); + + // Count how many arguments are currently provided in the impl + let mut provided_params = 0; + let mut last_segment_args = None; + + if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind + && let Some(seg) = path.segments.last() + && let Some(args) = seg.args + { + last_segment_args = Some(args); + provided_params = args + .args + .iter() + .filter(|arg| match arg { + GenericArg::Lifetime(_) => is_lifetime, + GenericArg::Type(_) => !is_lifetime, + _ => false, + }) + .count(); + } + + let mut visitor = ParamUsageVisitor { tcx, param_def_id: param.def_id, found: false }; + for item_ref in hir_impl.items { + let _ = visitor.visit_impl_item_ref(item_ref); + if visitor.found { + break; + } + } + let is_param_used = visitor.found; + + let mut suggestions = vec![]; + + // Option A: Remove (Only if not used in body) + if !is_param_used { + suggestions.push((hir_impl.generics.span_for_param_removal(index), String::new())); + } + + // Option B: Suggest adding only if there's an available parameter in the struct definition + // or the parameter is already used somewhere, then we suggest adding to the impl struct and the struct definition + if provided_params < total_params || is_param_used { + if let Some(args) = last_segment_args { + // Struct already has <...>, append to it + suggestions.push((args.span().unwrap().shrink_to_hi(), format!(", {}", param.name))); + } else if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind { + // Struct has no <...> yet, add it + let seg = path.segments.last().unwrap(); + suggestions.push((seg.ident.span.shrink_to_hi(), format!("<{}>", param.name))); + } + if is_param_used { + // If the parameter is used in the body, we also want to suggest adding it to the struct definition if it's not already there + let struct_span = tcx.def_span(struct_def_id); + let last_param_span = if let Some(local_def_id) = struct_def_id.as_local() { + let hir_struct = tcx.hir_node_by_def_id(local_def_id).expect_item().expect_struct(); + hir_struct.1.params.last().map(|param| param.span) + } else { + let generics = tcx.generics_of(struct_def_id); + generics.own_params.last().map(|param| tcx.def_span(param.def_id)) + }; + + if let Some(last_param_span) = last_param_span { + suggestions.push((last_param_span.shrink_to_hi(), format!(", {}", param.name))); + } else { + suggestions.push((struct_span.shrink_to_hi(), format!("<{}>", param.name))); + } + } + } + + if suggestions.is_empty() { + return; + } + + let parameter_type = if is_lifetime { "lifetime" } else { "type" }; + if is_param_used { + let msg = format!( + "use the {} parameter `{}` in the `{}` type and use it in the type definition", + parameter_type, + param.name, + tcx.def_path_str(struct_def_id) + ); + diag.multipart_suggestion( + msg, + vec![ + (suggestions[0].0, suggestions[0].1.clone()), + (suggestions[1].0, suggestions[1].1.clone()), + ], + Applicability::MaybeIncorrect, + ); + } else { + let msg = if suggestions.len() == 2 { + format!("either remove the unused {} parameter `{}`", parameter_type, param.name) + } else { + format!("remove the unused {} parameter `{}`", parameter_type, param.name) + }; + diag.span_suggestion( + suggestions[0].0, + msg, + suggestions[0].1.clone(), + Applicability::MaybeIncorrect, + ); + if suggestions.len() == 2 { + let msg = format!("or use it"); + diag.span_suggestion( + suggestions[1].0, + msg, + suggestions[1].1.clone(), + Applicability::MaybeIncorrect, + ); + } + }; +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 82081fd40a274..bbb40ef0a87ad 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -21,6 +21,7 @@ use rustc_span::{ErrorGuaranteed, kw}; use crate::constrained_generic_params as cgp; use crate::errors::UnconstrainedGenericParameter; +use crate::errors::remove_or_use_generic::suggest_to_remove_or_use_generic; mod min_specialization; @@ -177,6 +178,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( ); } } + suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, param, true); res = Err(diag.emit()); } } @@ -242,6 +244,7 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained( const_param_note2: const_param_note, }); diag.code(E0207); + suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, ¶m, false); res = Err(diag.emit()); } } diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 758d2762a6af4..176890bab85f2 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -22,6 +22,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 10fd1d1501b3b..e4b4acf14036c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -70,6 +70,7 @@ mod precedence; mod ptr_nulls; mod redundant_semicolon; mod reference_casting; +mod runtime_symbols; mod shadowed_into_iter; mod static_mut_refs; mod traits; @@ -113,6 +114,7 @@ use precedence::*; use ptr_nulls::*; use redundant_semicolon::*; use reference_casting::*; +use runtime_symbols::*; use rustc_hir::def_id::LocalModDefId; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -242,6 +244,7 @@ late_lint_methods!( AsyncFnInTrait: AsyncFnInTrait, NonLocalDefinitions: NonLocalDefinitions::default(), InteriorMutableConsts: InteriorMutableConsts, + RuntimeSymbols: RuntimeSymbols, ImplTraitOvercaptures: ImplTraitOvercaptures, IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6d9f486f627f6..0ed0efbe6feb0 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -848,6 +848,33 @@ pub(crate) enum UseLetUnderscoreIgnoreSuggestion { }, } +// runtime_symbols.rs +#[derive(Diagnostic)] +pub(crate) enum RedefiningRuntimeSymbolsDiag<'tcx> { + #[diag( + "invalid definition of the runtime `{$symbol_name}` symbol used by the standard library" + )] + #[note( + "expected `{$expected_fn_sig}` + found `{$found_fn_sig}`" + )] + #[help( + "either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = \"{$symbol_name}\")]`, or `#[link_name = \"{$symbol_name}\"]`" + )] + FnDef { symbol_name: String, expected_fn_sig: Ty<'tcx>, found_fn_sig: Ty<'tcx> }, + #[diag( + "invalid definition of the runtime `{$symbol_name}` symbol used by the standard library" + )] + #[note( + "expected `{$expected_fn_sig}` + found `static {$symbol_name}: {$static_ty}`" + )] + #[help( + "either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = \"{$symbol_name}\")]`" + )] + Static { symbol_name: String, static_ty: Ty<'tcx>, expected_fn_sig: Ty<'tcx> }, +} + // drop_forget_useless.rs #[derive(Diagnostic)] #[diag("calls to `std::mem::drop` with a reference instead of an owned value does nothing")] diff --git a/compiler/rustc_lint/src/runtime_symbols.rs b/compiler/rustc_lint/src/runtime_symbols.rs new file mode 100644 index 0000000000000..a6b52580df861 --- /dev/null +++ b/compiler/rustc_lint/src/runtime_symbols.rs @@ -0,0 +1,206 @@ +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, FnSig, ForeignItemKind, LanguageItems}; +use rustc_infer::infer::DefineOpaqueTypes; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::Span; +use rustc_trait_selection::infer::TyCtxtInferExt; + +use crate::lints::RedefiningRuntimeSymbolsDiag; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `invalid_runtime_symbol_definitions` lint checks the signature of items whose + /// symbol name is a runtime symbols expected by `core`. + /// + /// ### Example + /// + #[cfg_attr(bootstrap, doc = "```rust")] + #[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")] + #[cfg_attr(not(bootstrap), doc = "#[unsafe(no_mangle)]")] + /// pub fn strlen() {} // invalid definition of the `strlen` function + #[doc = "```"] + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Up-most care is required when defining runtime symbols assumed and + /// used by the standard library. They must follow the C specification, not use any + /// standard-library facility or undefined behavior may occur. + /// + /// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`, + /// `bcmp` and `strlen`. + /// + /// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library + pub INVALID_RUNTIME_SYMBOL_DEFINITIONS, + Deny, + "invalid definition of a symbol used by the standard library" +} + +declare_lint_pass!(RuntimeSymbols => [INVALID_RUNTIME_SYMBOL_DEFINITIONS]); + +static EXPECTED_SYMBOLS: &[ExpectedSymbol] = &[ + ExpectedSymbol { symbol: "memcpy", lang: LanguageItems::memcpy_fn }, + ExpectedSymbol { symbol: "memmove", lang: LanguageItems::memmove_fn }, + ExpectedSymbol { symbol: "memset", lang: LanguageItems::memset_fn }, + ExpectedSymbol { symbol: "memcmp", lang: LanguageItems::memcmp_fn }, + ExpectedSymbol { symbol: "bcmp", lang: LanguageItems::bcmp_fn }, + ExpectedSymbol { symbol: "strlen", lang: LanguageItems::strlen_fn }, +]; + +#[derive(Copy, Clone, Debug)] +struct ExpectedSymbol { + symbol: &'static str, + lang: fn(&LanguageItems) -> Option, +} + +impl<'tcx> LateLintPass<'tcx> for RuntimeSymbols { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { + // Bail-out if the item is not a function/method or static. + match item.kind { + hir::ItemKind::Fn { sig, ident: _, generics, body: _, has_body: _ } => { + // Generic functions cannot have the same runtime symbol as we do not allow + // any symbol attributes. + if !generics.params.is_empty() { + return; + } + + // Try to get the overridden symbol name of this function (our mangling + // cannot ever conflict with runtime symbols, so no need to check for those). + let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs( + cx.tcx, + rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()), + ) else { + return; + }; + + check_fn(cx, &symbol_name, sig, item.owner_id.def_id); + } + hir::ItemKind::Static(..) => { + // Compute the symbol name of this static (without mangling, as our mangling + // cannot ever conflict with runtime symbols). + let Some(symbol_name) = rustc_symbol_mangling::symbol_name_from_attrs( + cx.tcx, + rustc_middle::ty::InstanceKind::Item(item.owner_id.to_def_id()), + ) else { + return; + }; + + let def_id = item.owner_id.def_id; + + check_static(cx, &symbol_name, def_id, item.span); + } + hir::ItemKind::ForeignMod { abi: _, items } => { + for item in items { + let item = cx.tcx.hir_foreign_item(*item); + + let did = item.owner_id.def_id; + let instance = Instance::new_raw( + did.to_def_id(), + ty::List::identity_for_item(cx.tcx, did), + ); + let symbol_name = cx.tcx.symbol_name(instance); + + match item.kind { + ForeignItemKind::Fn(fn_sig, _idents, _generics) => { + check_fn(cx, &symbol_name.name, fn_sig, did); + } + ForeignItemKind::Static(..) => { + check_static(cx, &symbol_name.name, did, item.span); + } + ForeignItemKind::Type => return, + } + } + } + _ => return, + } + } +} + +fn check_fn(cx: &LateContext<'_>, symbol_name: &str, sig: FnSig<'_>, did: LocalDefId) { + let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else { + // The symbol name does not correspond to a runtime symbols, bail out + return; + }; + + let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else { + // Can't find the corresponding language item, bail out + return; + }; + + // Get the two function signatures + let lang_sig = cx.tcx.normalize_erasing_regions( + cx.typing_env(), + cx.tcx.fn_sig(expected_def_id).instantiate_identity(), + ); + let user_sig = cx + .tcx + .normalize_erasing_regions(cx.typing_env(), cx.tcx.fn_sig(did).instantiate_identity()); + + // Compare the two signatures with an inference context + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); + let cause = rustc_middle::traits::ObligationCause::misc(sig.span, did); + let result = infcx.at(&cause, cx.param_env).eq(DefineOpaqueTypes::No, lang_sig, user_sig); + + // If they don't match, emit our own mismatch signatures + if let Err(_terr) = result { + // Create fn pointers for diagnostics purpose + let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); + let actual = Ty::new_fn_ptr(cx.tcx, user_sig); + + cx.emit_span_lint( + INVALID_RUNTIME_SYMBOL_DEFINITIONS, + sig.span, + RedefiningRuntimeSymbolsDiag::FnDef { + symbol_name: symbol_name.to_string(), + found_fn_sig: actual, + expected_fn_sig: expected, + }, + ); + } +} + +fn check_static<'tcx>(cx: &LateContext<'tcx>, symbol_name: &str, did: LocalDefId, sp: Span) { + let Some(expected_symbol) = EXPECTED_SYMBOLS.iter().find(|es| es.symbol == symbol_name) else { + // The symbol name does not correspond to a runtime symbols, bail out + return; + }; + + let Some(expected_def_id) = (expected_symbol.lang)(&cx.tcx.lang_items()) else { + // Can't find the corresponding language item, bail out + return; + }; + + // Get the static type + let static_ty = cx.tcx.type_of(did).instantiate_identity().skip_norm_wip(); + + // Peel Option<...> and get the inner type (see std weak! macro with #[linkage = "extern_weak"]) + let inner_static_ty: Ty<'_> = match static_ty.kind() { + ty::Adt(def, args) if Some(def.did()) == cx.tcx.lang_items().option_type() => { + args.type_at(0) + } + _ => static_ty, + }; + + // Get the expected symbol function signature + let lang_sig = cx.tcx.normalize_erasing_regions( + cx.typing_env(), + cx.tcx.fn_sig(expected_def_id).instantiate_identity(), + ); + + let expected = Ty::new_fn_ptr(cx.tcx, lang_sig); + + // Compare the expected function signature with the static type, report an error if they don't match + if expected != inner_static_ty { + cx.emit_span_lint( + INVALID_RUNTIME_SYMBOL_DEFINITIONS, + sp, + RedefiningRuntimeSymbolsDiag::Static { + static_ty, + symbol_name: symbol_name.to_string(), + expected_fn_sig: expected, + }, + ); + } +} diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 9f8a7774327c5..c835ff7dbe070 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -207,6 +207,7 @@ where // We keep async drop unexpanded to poll-loop here, to expand it later, at StateTransform - // into states expand. // call_destructor_only - to call only AsyncDrop::drop, not full async_drop_in_place glue + #[instrument(level = "debug", skip(self), ret)] fn build_async_drop( &mut self, place: Place<'tcx>, @@ -221,14 +222,8 @@ where let span = self.source_info.span; let pin_obj_bb = bb.unwrap_or_else(|| { - self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - // Temporary terminator, will be replaced by patch - source_info: self.source_info, - kind: TerminatorKind::Return, - }), - false, - )) + // Temporary terminator, will be replaced by patch + self.new_block(unwind, TerminatorKind::Return) }); let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { @@ -565,6 +560,7 @@ where .collect() } + #[instrument(level = "debug", skip(self), ret)] fn drop_subpath( &mut self, place: Place<'tcx>, @@ -574,8 +570,6 @@ where dropline: Option, ) -> BasicBlock { if let Some(path) = path { - debug!("drop_subpath: for std field {:?}", place); - DropCtxt { elaborator: self.elaborator, source_info: self.source_info, @@ -587,8 +581,6 @@ where } .elaborated_drop_block() } else { - debug!("drop_subpath: for rest field {:?}", place); - DropCtxt { elaborator: self.elaborator, source_info: self.source_info, @@ -596,8 +588,7 @@ where succ, unwind, dropline, - // Using `self.path` here to condition the drop on - // our own drop flag. + // Using `self.path` here to condition the drop on our own drop flag. path: self.path, } .complete_drop(succ, unwind) @@ -614,6 +605,7 @@ where /// `dropline_ladder` is a similar list of steps in reverse order, /// which is called if the matching step of the drop glue will contain async drop /// (expanded later to Yield) and the containing coroutine will be dropped at this point. + #[instrument(level = "debug", skip(self), ret)] fn drop_halfladder( &mut self, unwind_ladder: &[Unwind], @@ -679,6 +671,7 @@ where /// /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. + #[instrument(level = "debug", skip(self), ret)] fn drop_ladder( &mut self, fields: Vec<(Place<'tcx>, Option)>, @@ -686,7 +679,6 @@ where unwind: Unwind, dropline: Option, ) -> (BasicBlock, Unwind, Option) { - debug!("drop_ladder({:?}, {:?})", self, fields); assert!( if unwind.is_cleanup() { dropline.is_none() } else { true }, "Dropline is set for cleanup drop ladder" @@ -723,9 +715,8 @@ where ) } + #[instrument(level = "debug", skip(self), ret)] fn open_drop_for_tuple(&mut self, tys: &[Ty<'tcx>]) -> BasicBlock { - debug!("open_drop_for_tuple({:?}, {:?})", self, tys); - let fields = tys .iter() .enumerate() @@ -769,18 +760,14 @@ where let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline); - let setup_bbd = BasicBlockData::new_stmts( + self.new_block_with_statements( + unwind, vec![self.assign( Place::from(ptr_local), Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), )], - Some(Terminator { - kind: TerminatorKind::Goto { target: do_drop_bb }, - source_info: self.source_info, - }), - unwind.is_cleanup(), - ); - self.elaborator.patch().new_block(setup_bbd) + TerminatorKind::Goto { target: do_drop_bb }, + ) } #[instrument(level = "debug", ret)] @@ -790,17 +777,11 @@ where args: GenericArgsRef<'tcx>, ) -> BasicBlock { if adt.variants().is_empty() { - return self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Unreachable, - }), - self.unwind.is_cleanup(), - )); + return self.new_block(self.unwind, TerminatorKind::Unreachable); } let skip_contents = adt.is_union() || adt.is_manually_drop(); - let contents_drop = if skip_contents { + let (contents_succ, contents_unwind, contents_dropline) = if skip_contents { if adt.has_dtor(self.tcx()) && self.elaborator.get_drop_flag(self.path).is_some() { // the top-level drop flag is usually cleared by open_drop_for_adt_contents // types with destructors would still need an empty drop ladder to clear it @@ -819,21 +800,19 @@ where if adt.has_dtor(self.tcx()) { let destructor_block = if adt.is_box() { // we need to drop the inside of the box before running the destructor - let succ = self.destructor_call_block_sync((contents_drop.0, contents_drop.1)); - let unwind = contents_drop - .1 - .map(|unwind| self.destructor_call_block_sync((unwind, Unwind::InCleanup))); - let dropline = contents_drop - .2 - .map(|dropline| self.destructor_call_block_sync((dropline, contents_drop.1))); + let succ = self.destructor_call_block_sync(contents_succ, contents_unwind); + let unwind = contents_unwind + .map(|unwind| self.destructor_call_block_sync(unwind, Unwind::InCleanup)); + let dropline = contents_dropline + .map(|dropline| self.destructor_call_block_sync(dropline, contents_unwind)); self.open_drop_for_box_contents(adt, args, succ, unwind, dropline) } else { - self.destructor_call_block(contents_drop) + self.destructor_call_block(contents_succ, contents_unwind, contents_dropline) }; - self.drop_flag_test_block(destructor_block, contents_drop.0, contents_drop.1) + self.drop_flag_test_block(destructor_block, contents_succ, contents_unwind) } else { - contents_drop.0 + contents_succ } } @@ -976,26 +955,22 @@ where let discr_ty = adt.repr().discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place); - let switch_block = BasicBlockData::new_stmts( + let switch_block = self.new_block_with_statements( + unwind, vec![self.assign(discr, discr_rv)], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::SwitchInt { - discr: Operand::Move(discr), - targets: SwitchTargets::new( - values.iter().copied().zip(blocks.iter().copied()), - *blocks.last().unwrap(), - ), - }, - }), - unwind.is_cleanup(), + TerminatorKind::SwitchInt { + discr: Operand::Move(discr), + targets: SwitchTargets::new( + values.iter().copied().zip(blocks.iter().copied()), + *blocks.last().unwrap(), + ), + }, ); - let switch_block = self.elaborator.patch().new_block(switch_block); self.drop_flag_test_block(switch_block, succ, unwind) } - fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { - debug!("destructor_call_block_sync({:?}, {:?})", self, succ); + #[instrument(level = "debug", skip(self), ret)] + fn destructor_call_block_sync(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { let tcx = self.tcx(); let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; @@ -1005,7 +980,8 @@ where let ref_place = self.new_temp(ref_ty); let unit_temp = Place::from(self.new_temp(tcx.types.unit)); - let result = BasicBlockData::new_stmts( + self.new_block_with_statements( + unwind, vec![self.assign( Place::from(ref_place), Rvalue::Ref( @@ -1014,40 +990,31 @@ where self.place, ), )], - Some(Terminator { - kind: TerminatorKind::Call { - func: Operand::function_handle( - tcx, - drop_fn, - [ty.into()], - self.source_info.span, - ), - args: [Spanned { node: Operand::Move(Place::from(ref_place)), span: DUMMY_SP }] - .into(), - destination: unit_temp, - target: Some(succ), - unwind: unwind.into_action(), - call_source: CallSource::Misc, - fn_span: self.source_info.span, - }, - source_info: self.source_info, - }), - unwind.is_cleanup(), - ); - - self.elaborator.patch().new_block(result) + TerminatorKind::Call { + func: Operand::function_handle(tcx, drop_fn, [ty.into()], self.source_info.span), + args: [Spanned { node: Operand::Move(Place::from(ref_place)), span: DUMMY_SP }] + .into(), + destination: unit_temp, + target: Some(succ), + unwind: unwind.into_action(), + call_source: CallSource::Misc, + fn_span: self.source_info.span, + }, + ) } + #[instrument(level = "debug", skip(self), ret)] fn destructor_call_block( &mut self, - (succ, unwind, dropline): (BasicBlock, Unwind, Option), + succ: BasicBlock, + unwind: Unwind, + dropline: Option, ) -> BasicBlock { - debug!("destructor_call_block({:?}, {:?})", self, succ); let ty = self.place_ty(self.place); if !unwind.is_cleanup() && self.check_if_can_async_drop(ty, true) { self.build_async_drop(self.place, ty, None, succ, unwind, dropline, true) } else { - self.destructor_call_block_sync((succ, unwind)) + self.destructor_call_block_sync(succ, unwind) } } @@ -1080,7 +1047,8 @@ where let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); - let drop_block = BasicBlockData::new_stmts( + let drop_block = self.new_block_with_statements( + unwind, vec![ self.assign( ptr, @@ -1091,27 +1059,18 @@ where Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), ), ], - Some(Terminator { - source_info: self.source_info, - // this gets overwritten by drop elaboration. - kind: TerminatorKind::Unreachable, - }), - unwind.is_cleanup(), + // this gets overwritten by drop elaboration. + TerminatorKind::Unreachable, ); - let drop_block = self.elaborator.patch().new_block(drop_block); - let loop_block = BasicBlockData::new_stmts( + let loop_block = self.new_block_with_statements( + unwind, vec![self.assign( can_go, Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::if_(move_(can_go), succ, drop_block), - }), - unwind.is_cleanup(), + TerminatorKind::if_(move_(can_go), succ, drop_block), ); - let loop_block = self.elaborator.patch().new_block(loop_block); let place = tcx.mk_place_deref(ptr); if !unwind.is_cleanup() && self.check_if_can_async_drop(ety, false) { @@ -1140,13 +1099,13 @@ where loop_block } + #[instrument(level = "debug", skip(self), ret)] fn open_drop_for_array( &mut self, array_ty: Ty<'tcx>, ety: Ty<'tcx>, opt_size: Option, ) -> BasicBlock { - debug!("open_drop_for_array({:?}, {:?}, {:?})", array_ty, ety, opt_size); let tcx = self.tcx(); if let Some(size) = opt_size { @@ -1215,7 +1174,15 @@ where let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty); let slice_ptr = self.new_temp(slice_ptr_ty); - let mut delegate_block = BasicBlockData::new_stmts( + let array_place = mem::replace( + &mut self.place, + Place::from(slice_ptr).project_deeper(&[PlaceElem::Deref], tcx), + ); + let slice_block = self.drop_loop_trio_for_slice(ety); + self.place = array_place; + + self.new_block_with_statements( + self.unwind, vec![ self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)), self.assign( @@ -1230,28 +1197,14 @@ where ), ), ], - None, - self.unwind.is_cleanup(), - ); - - let array_place = mem::replace( - &mut self.place, - Place::from(slice_ptr).project_deeper(&[PlaceElem::Deref], tcx), - ); - let slice_block = self.drop_loop_trio_for_slice(ety); - self.place = array_place; - - delegate_block.terminator = Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Goto { target: slice_block }, - }); - self.elaborator.patch().new_block(delegate_block) + TerminatorKind::Goto { target: slice_block }, + ) } /// Creates a trio of drop-loops of `place`, which drops its contents, even /// in the case of 1 panic or in the case of coroutine drop + #[instrument(level = "debug", skip(self), ret)] fn drop_loop_trio_for_slice(&mut self, ety: Ty<'tcx>) -> BasicBlock { - debug!("drop_loop_trio_for_slice({:?})", ety); let tcx = self.tcx(); let len = self.new_temp(tcx.types.usize); let cur = self.new_temp(tcx.types.usize); @@ -1274,7 +1227,8 @@ where }; let zero = self.constant_usize(0); - let block = BasicBlockData::new_stmts( + let drop_block = self.new_block_with_statements( + unwind, vec![ self.assign( len.into(), @@ -1285,14 +1239,9 @@ where ), self.assign(cur.into(), Rvalue::Use(zero, WithRetag::Yes)), ], - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Goto { target: loop_block }, - }), - unwind.is_cleanup(), + TerminatorKind::Goto { target: loop_block }, ); - let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); self.drop_flag_test_block(reset_block, self.succ, unwind) @@ -1336,37 +1285,28 @@ where self.source_info.span, "open drop for unsafe binder shouldn't be encountered", ); - self.elaborator.patch().new_block(BasicBlockData::new( - Some(Terminator { - source_info: self.source_info, - kind: TerminatorKind::Unreachable, - }), - self.unwind.is_cleanup(), - )) + self.new_block(self.unwind, TerminatorKind::Unreachable) } _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), } } + #[instrument(level = "debug", skip(self), ret)] fn complete_drop(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock { - debug!("complete_drop(succ={:?}, unwind={:?})", succ, unwind); - let drop_block = self.drop_block(succ, unwind); - self.drop_flag_test_block(drop_block, succ, unwind) } /// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will /// also be cleared. + #[instrument(level = "debug", skip(self), ret)] fn drop_flag_reset_block( &mut self, mode: DropFlagMode, succ: BasicBlock, unwind: Unwind, ) -> BasicBlock { - debug!("drop_flag_reset_block({:?},{:?})", self, mode); - if unwind.is_cleanup() { // The drop flag isn't read again on the unwind path, so don't // bother setting it. @@ -1378,25 +1318,23 @@ where block } + #[instrument(level = "debug", skip(self), ret)] fn elaborated_drop_block(&mut self) -> BasicBlock { - debug!("elaborated_drop_block({:?})", self); - let blk = self.drop_block_simple(self.succ, self.unwind); + let blk = self.new_block( + self.unwind, + TerminatorKind::Drop { + place: self.place, + target: self.succ, + unwind: self.unwind.into_action(), + replace: false, + drop: self.dropline, + async_fut: None, + }, + ); self.elaborate_drop(blk); blk } - fn drop_block_simple(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { - let block = TerminatorKind::Drop { - place: self.place, - target, - unwind: unwind.into_action(), - replace: false, - drop: self.dropline, - async_fut: None, - }; - self.new_block(unwind, block) - } - fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let drop_ty = self.place_ty(self.place); if !unwind.is_cleanup() && self.check_if_can_async_drop(drop_ty, false) { @@ -1410,15 +1348,17 @@ where false, ) } else { - let block = TerminatorKind::Drop { - place: self.place, - target, - unwind: unwind.into_action(), - replace: false, - drop: None, - async_fut: None, - }; - self.new_block(unwind, block) + self.new_block( + unwind, + TerminatorKind::Drop { + place: self.place, + target, + unwind: unwind.into_action(), + replace: false, + drop: None, + async_fut: None, + }, + ) } } @@ -1432,6 +1372,7 @@ where /// Depending on the required `DropStyle`, this might be a generated block with an `if` /// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case /// the drop can be statically determined. + #[instrument(level = "debug", skip(self), ret)] fn drop_flag_test_block( &mut self, on_set: BasicBlock, @@ -1439,11 +1380,6 @@ where unwind: Unwind, ) -> BasicBlock { let style = self.elaborator.drop_style(self.path, DropFlagMode::Shallow); - debug!( - "drop_flag_test_block({:?},{:?},{:?},{:?}) - {:?}", - self, on_set, on_unset, unwind, style - ); - match style { DropStyle::Dead => on_unset, DropStyle::Static => on_set, @@ -1455,6 +1391,7 @@ where } } + #[instrument(level = "trace", skip(self), ret)] fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { self.elaborator.patch().new_block(BasicBlockData::new( Some(Terminator { source_info: self.source_info, kind: k }), @@ -1462,6 +1399,7 @@ where )) } + #[instrument(level = "trace", skip(self, statements), ret)] fn new_block_with_statements( &mut self, unwind: Unwind, diff --git a/compiler/rustc_passes/src/eii.rs b/compiler/rustc_passes/src/eii.rs index f3e84665f21dc..2916f5355e7b6 100644 --- a/compiler/rustc_passes/src/eii.rs +++ b/compiler/rustc_passes/src/eii.rs @@ -18,8 +18,8 @@ enum CheckingMode { } fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode { - // if any of the crate types is not rlib or dylib, we must check for existence. - if tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib | CrateType::Dylib)) { + // if any of the crate types is not rlib, we must check for existence. + if tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib)) { CheckingMode::CheckExistence } else { CheckingMode::CheckDuplicates diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index c274ca48df622..0d73c3fceb16b 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -29,6 +29,11 @@ pub(crate) enum Duplicate { CrateDepends, } +enum CollectWeak { + Allowed, + Ignore, +} + struct LanguageItemCollector<'ast, 'tcx> { items: LanguageItems, tcx: TyCtxt<'tcx>, @@ -60,19 +65,24 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { attrs: &'ast [ast::Attribute], item_span: Span, generics: Option<&'ast ast::Generics>, + collect_weak: CollectWeak, ) { if let Some((name, attr_span)) = extract_ast(attrs) { match LangItem::from_name(name) { // Known lang item with attribute on correct target. Some(lang_item) if actual_target == lang_item.target() => { - self.collect_item_extended( - lang_item, - def_id, - item_span, - attr_span, - generics, - actual_target, - ); + // Weak lang items are handled separately + // Weak only lang items are always handled here + if !lang_item.is_weak() || matches!(collect_weak, CollectWeak::Allowed) { + self.collect_item_extended( + lang_item, + def_id, + item_span, + attr_span, + generics, + actual_target, + ); + } } // Known lang item with attribute on incorrect target. Some(lang_item) => { @@ -299,6 +309,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { &i.attrs, i.span, i.opt_generics(), + CollectWeak::Allowed, ); let parent_item = self.parent_item.replace(i); @@ -306,6 +317,17 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.parent_item = parent_item; } + fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { + self.check_for_lang( + Target::Fn, + self.resolver.owners[&i.id].def_id, + &i.attrs, + i.span, + None, + CollectWeak::Ignore, + ); + } + fn visit_variant(&mut self, variant: &'ast ast::Variant) { self.check_for_lang( Target::Variant, @@ -313,6 +335,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { &variant.attrs, variant.span, None, + CollectWeak::Allowed, ); } @@ -346,7 +369,14 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { } }; - self.check_for_lang(target, self.resolver.owners[&i.id].def_id, &i.attrs, i.span, generics); + self.check_for_lang( + target, + self.resolver.owners[&i.id].def_id, + &i.attrs, + i.span, + generics, + CollectWeak::Allowed, + ); visit::walk_assoc_item(self, i, ctxt); } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 4200003ea1d1a..fbf486c741df5 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -48,11 +48,15 @@ struct WeakLangItemVisitor<'a, 'tcx> { impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> { fn visit_foreign_item(&mut self, i: &'ast ast::ForeignItem) { if let Some((lang_item, _)) = extract_ast(&i.attrs) { - if let Some(item) = LangItem::from_name(lang_item) - && item.is_weak() - { - if self.items.get(item).is_none() { - self.items.missing.push(item); + if let Some(item) = LangItem::from_name(lang_item) { + if item.is_weak() { + if self.items.get(item).is_none() { + self.items.missing.push(item); + } + } else if item.is_weak_only() { + // weak only lang items are handled directly in lang_items.rs + } else { + self.tcx.dcx().emit_err(UnknownExternLangItem { span: i.span, lang_item }); } } else { self.tcx.dcx().emit_err(UnknownExternLangItem { span: i.span, lang_item }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 664d1632fb59d..8be99499cd17a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3612,6 +3612,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.check_trait_item( item.id, *ident, + *ident, &item.kind, ValueNS, item.span, @@ -3656,7 +3657,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); self.resolve_define_opaques(define_opaque); } - AssocItemKind::Fn(Fn { ident, generics, define_opaque, .. }) => { + AssocItemKind::Fn(fn_kind @ Fn { ident, generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( @@ -3666,10 +3667,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Function, generics.span, |this| { + let effective_ident = if is_in_trait_impl && fn_kind.is_pin_drop_sugar() { + Ident::new(sym::pin_drop, ident.span) + } else { + *ident + }; // If this is a trait impl, ensure the method // exists in trait this.check_trait_item( item.id, + effective_ident, *ident, &item.kind, ValueNS, @@ -3701,6 +3708,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.check_trait_item( item.id, *ident, + *ident, &item.kind, TypeNS, item.span, @@ -3726,6 +3734,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.check_trait_item( item.id, delegation.ident, + delegation.ident, &item.kind, ValueNS, item.span, @@ -3750,6 +3759,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, id: NodeId, mut ident: Ident, + mut reported_ident: Ident, kind: &AssocItemKind, ns: Namespace, span: Span, @@ -3763,6 +3773,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); + reported_ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(IdentKey::new(ident), ns); let mut decl = self.r.resolution(module, key).and_then(|r| r.best_decl()); debug!(?decl); @@ -3798,10 +3809,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let Some(decl) = decl else { // We could not find the method: report an error. - let candidate = self.find_similarly_named_assoc_item(ident.name, kind); + let candidate = self.find_similarly_named_assoc_item(reported_ident.name, kind); let path = &self.current_trait_ref.as_ref().unwrap().1.path; let path_names = path_names_to_string(path); - self.report_error(span, err(ident, path_names, candidate)); + self.report_error(span, err(reported_ident, path_names, candidate)); feed_visibility(self, module.def_id()); return; }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 69ed7314855f9..d7aaea08db024 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -508,6 +508,7 @@ symbols! { backchain, backend_repr, bang, + bcmp_fn, begin_panic, bench, bevy_ecs, @@ -1255,7 +1256,11 @@ symbols! { mem_variant_count, mem_zeroed, member_constraints, + memcmp_fn, + memcpy_fn, + memmove_fn, memory, + memset_fn, memtag, message, meta, @@ -1992,6 +1997,7 @@ symbols! { strict_provenance_lints, string_deref_patterns, stringify, + strlen_fn, struct_field_attributes, struct_inherit, struct_variant, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c052037f05b39..693aa95b2524a 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -92,7 +92,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mono::{InstantiationMode, MonoItem}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Instance, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, TyCtxt}; use rustc_session::config::SymbolManglingVersion; use tracing::debug; @@ -149,29 +149,22 @@ pub fn typeid_for_trait_ref<'tcx>( v0::mangle_typeid_for_trait_ref(tcx, trait_ref) } -/// Computes the symbol name for the given instance. This function will call -/// `compute_instantiating_crate` if it needs to factor the instantiating crate -/// into the symbol name. -fn compute_symbol_name<'tcx>( +pub fn symbol_name_from_attrs<'tcx>( tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - compute_instantiating_crate: impl FnOnce() -> CrateNum, -) -> String { - let def_id = instance.def_id(); - let args = instance.args; - - debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); + instance_kind: InstanceKind<'tcx>, +) -> Option { + let def_id = instance_kind.def_id(); if let Some(def_id) = def_id.as_local() { if tcx.proc_macro_decls_static(()) == Some(def_id) { let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); - return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); + return Some(tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id)); } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. let attrs = if tcx.def_kind(def_id).has_codegen_attrs() { - &tcx.codegen_instance_attrs(instance.def) + &tcx.codegen_instance_attrs(instance_kind) } else { CodegenFnAttrs::EMPTY }; @@ -197,7 +190,7 @@ fn compute_symbol_name<'tcx>( // legacy symbol mangling scheme. let name = if let Some(name) = attrs.symbol_name { name } else { tcx.item_name(def_id) }; - return v0::mangle_internal_symbol(tcx, name.as_str()); + return Some(v0::mangle_internal_symbol(tcx, name.as_str())); } let wasm_import_module_exception_force_mangling = { @@ -225,15 +218,35 @@ fn compute_symbol_name<'tcx>( if !wasm_import_module_exception_force_mangling { if let Some(name) = attrs.symbol_name { // Use provided name - return name.to_string(); + return Some(name.to_string()); } if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { // Don't mangle - return tcx.item_name(def_id).to_string(); + return Some(tcx.item_name(def_id).to_string()); } } + None +} + +/// Computes the symbol name for the given instance. This function will call +/// `compute_instantiating_crate` if it needs to factor the instantiating crate +/// into the symbol name. +fn compute_symbol_name<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + compute_instantiating_crate: impl FnOnce() -> CrateNum, +) -> String { + let def_id = instance.def_id(); + let args = instance.args; + + debug!("symbol_name(def_id={:?}, args={:?})", def_id, args); + + if let Some(symbol) = symbol_name_from_attrs(tcx, instance.def) { + return symbol; + } + // If we're dealing with an instance of a function that's inlined from // another crate but we're marking it as globally shared to our // compilation (aka we're not making an internal copy in each of our diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 1efbedf5dc42f..cf04402e3d984 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -308,7 +308,10 @@ impl str { pub fn replace(&self, from: P, to: &str) -> String { // Fast path for replacing a single ASCII character with another. if let Some(from_byte) = match from.as_utf8_pattern() { - Some(Utf8Pattern::StringPattern([from_byte])) => Some(*from_byte), + Some(Utf8Pattern::StringPattern(s)) => match s.as_bytes() { + [from_byte] => Some(*from_byte), + _ => None, + }, Some(Utf8Pattern::CharPattern(c)) => c.as_ascii().map(|ascii_char| ascii_char.to_u8()), _ => None, } { diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4e97dfd2d561e..e1285bc596484 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2654,7 +2654,7 @@ impl<'b> Pattern for &'b String { #[inline] fn as_utf8_pattern(&self) -> Option> { - Some(Utf8Pattern::StringPattern(self.as_bytes())) + Some(Utf8Pattern::StringPattern(self.as_str())) } } diff --git a/library/compiler-builtins/compiler-builtins/src/arm.rs b/library/compiler-builtins/compiler-builtins/src/arm.rs index 0c15b37df1dc1..f26fce2d912b6 100644 --- a/library/compiler-builtins/compiler-builtins/src/arm.rs +++ b/library/compiler-builtins/compiler-builtins/src/arm.rs @@ -84,7 +84,11 @@ intrinsics! { /// /// Usual `memcpy` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memcpy( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { // SAFETY: memcpy preconditions apply. unsafe { crate::mem::memcpy(dst, src, n) }; } @@ -96,7 +100,11 @@ intrinsics! { /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy4(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memcpy4( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { // We are guaranteed 4-alignment, so accessing at u32 is okay. let mut dst = dst.cast::(); let mut src = src.cast::(); @@ -121,7 +129,7 @@ intrinsics! { } // SAFETY: `dst` and `src` will still be valid for `n` bytes - unsafe { __aeabi_memcpy(dst.cast::(), src.cast::(), n) }; + unsafe { __aeabi_memcpy(dst.cast::(), src.cast::(), n) }; } /// `memcpy` for 8-byte alignment. @@ -131,7 +139,11 @@ intrinsics! { /// Usual `memcpy` requirements apply. Additionally, `dest` and `src` must be aligned to /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memcpy8(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memcpy8( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { debug_assert!(dst.addr().is_multiple_of(8)); debug_assert!(src.addr().is_multiple_of(8)); @@ -145,7 +157,11 @@ intrinsics! { /// /// Usual `memmove` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memmove(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memmove( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { // SAFETY: memmove preconditions apply. unsafe { crate::mem::memmove(dst, src, n) }; } @@ -157,7 +173,11 @@ intrinsics! { /// Usual `memmove` requirements apply. Additionally, `dest` and `src` must be aligned to /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove4(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memmove4( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { debug_assert!(dst.addr().is_multiple_of(4)); debug_assert!(src.addr().is_multiple_of(4)); @@ -172,7 +192,11 @@ intrinsics! { /// Usual `memmove` requirements apply. Additionally, `dst` and `src` must be aligned to /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memmove8(dst: *mut u8, src: *const u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memmove8( + dst: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) { debug_assert!(dst.addr().is_multiple_of(8)); debug_assert!(src.addr().is_multiple_of(8)); @@ -186,7 +210,11 @@ intrinsics! { /// /// Usual `memset` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset(dst: *mut u8, n: usize, c: i32) { + pub unsafe extern "aapcs" fn __aeabi_memset( + dst: *mut core::ffi::c_void, + n: usize, + c: i32 + ) { // Note the different argument order // SAFETY: memset preconditions apply. unsafe { crate::mem::memset(dst, c, n) }; @@ -199,7 +227,11 @@ intrinsics! { /// Usual `memset` requirements apply. Additionally, `dest` and `src` must be aligned to /// four bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset4(dst: *mut u8, n: usize, c: i32) { + pub unsafe extern "aapcs" fn __aeabi_memset4( + dst: *mut core::ffi::c_void, + n: usize, + c: i32 + ) { let mut dst = dst.cast::(); debug_assert!(dst.is_aligned()); let mut n = n; @@ -222,7 +254,7 @@ intrinsics! { } // SAFETY: `dst` will still be valid for `n` bytes - unsafe { __aeabi_memset(dst.cast::(), n, byte as i32) }; + unsafe { __aeabi_memset(dst.cast::(), n, byte as i32) }; } /// `memset` for 8-byte alignment. @@ -232,7 +264,11 @@ intrinsics! { /// Usual `memset` requirements apply. Additionally, `dst` and `src` must be aligned to /// eight bytes. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memset8(dst: *mut u8, n: usize, c: i32) { + pub unsafe extern "aapcs" fn __aeabi_memset8( + dst: *mut core::ffi::c_void, + n: usize, + c: i32 + ) { debug_assert!(dst.addr().is_multiple_of(8)); // SAFETY: memset preconditions apply, less strict alignment. @@ -245,7 +281,7 @@ intrinsics! { /// /// Usual `memclr` requirements apply. #[cfg(not(target_vendor = "apple"))] - pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memclr(dst: *mut core::ffi::c_void, n: usize) { // SAFETY: memclr preconditions apply, less strict alignment. unsafe { __aeabi_memset(dst, n, 0) }; } @@ -257,7 +293,7 @@ intrinsics! { /// Usual `memclr` requirements apply. Additionally, `dest` and `src` must be aligned to /// four bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memclr4(dst: *mut core::ffi::c_void, n: usize) { debug_assert!(dst.addr().is_multiple_of(4)); // SAFETY: memclr preconditions apply, less strict alignment. @@ -271,7 +307,7 @@ intrinsics! { /// Usual `memclr` requirements apply. Additionally, `dst` and `src` must be aligned to /// eight bytes. #[cfg(not(any(target_vendor = "apple", target_env = "msvc")))] - pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut u8, n: usize) { + pub unsafe extern "aapcs" fn __aeabi_memclr8(dst: *mut core::ffi::c_void, n: usize) { debug_assert!(dst.addr().is_multiple_of(8)); // SAFETY: memclr preconditions apply, less strict alignment. diff --git a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs index ac41cd33416f6..ef0f4da228e96 100644 --- a/library/compiler-builtins/compiler-builtins/src/mem/mod.rs +++ b/library/compiler-builtins/compiler-builtins/src/mem/mod.rs @@ -9,37 +9,57 @@ mod impls; intrinsics! { #[mem_builtin] - pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { - impls::copy_forward(dest, src, n); + pub unsafe extern "C" fn memcpy( + dest: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) -> *mut core::ffi::c_void { + impls::copy_forward(dest.cast(), src.cast(), n); dest } #[mem_builtin] - pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 { + pub unsafe extern "C" fn memmove( + dest: *mut core::ffi::c_void, + src: *const core::ffi::c_void, + n: usize + ) -> *mut core::ffi::c_void { let delta = (dest as usize).wrapping_sub(src as usize); if delta >= n { // We can copy forwards because either dest is far enough ahead of src, // or src is ahead of dest (and delta overflowed). - impls::copy_forward(dest, src, n); + impls::copy_forward(dest.cast(), src.cast(), n); } else { - impls::copy_backward(dest, src, n); + impls::copy_backward(dest.cast(), src.cast(), n); } dest } #[mem_builtin] - pub unsafe extern "C" fn memset(s: *mut u8, c: core::ffi::c_int, n: usize) -> *mut u8 { - impls::set_bytes(s, c as u8, n); + pub unsafe extern "C" fn memset( + s: *mut core::ffi::c_void, + c: core::ffi::c_int, + n: usize + ) -> *mut core::ffi::c_void { + impls::set_bytes(s.cast(), c as u8, n); s } #[mem_builtin] - pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> core::ffi::c_int { - impls::compare_bytes(s1, s2, n) + pub unsafe extern "C" fn memcmp( + s1: *const core::ffi::c_void, + s2: *const core::ffi::c_void, + n: usize + ) -> core::ffi::c_int { + impls::compare_bytes(s1.cast(), s2.cast(), n) } #[mem_builtin] - pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, n: usize) -> core::ffi::c_int { + pub unsafe extern "C" fn bcmp( + s1: *const core::ffi::c_void, + s2: *const core::ffi::c_void, + n: usize + ) -> core::ffi::c_int { memcmp(s1, s2, n) } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 3f1aa54050a31..df6396b84264d 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -85,3 +85,30 @@ impl fmt::Debug for c_void { )] #[link(name = "/defaultlib:libcmt", modifiers = "+verbatim", cfg(target_feature = "crt-static"))] unsafe extern "C" {} + +// Used by rustc for checking the definitions of other function with the same symbol names +// +// See the `invalid_runtime_symbols_definitions` lint. +mod runtime_symbols { + use crate::ffi::{c_char, c_int, c_void}; + + unsafe extern "C" { + #[lang = "memcpy_fn"] + fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; + + #[lang = "memmove_fn"] + fn memmove(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; + + #[lang = "memset_fn"] + fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void; + + #[lang = "memcmp_fn"] + fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; + + #[lang = "bcmp_fn"] + fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; + + #[lang = "strlen_fn"] + fn strlen(s: *const c_char) -> usize; + } +} diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 25202ffd67313..77e0093d3ce84 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -161,7 +161,7 @@ pub trait Pattern: Sized { } } - /// Returns the pattern as utf-8 bytes if possible. + /// Returns the pattern as UTF-8 if possible. fn as_utf8_pattern(&self) -> Option> { None } @@ -172,7 +172,9 @@ pub trait Pattern: Sized { #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Utf8Pattern<'a> { /// Type returned by String and str types. - StringPattern(&'a [u8]), + /// This stores `str` rather than bytes so callers cannot describe + /// non-UTF-8 string patterns through this API. + StringPattern(&'a str), /// Type returned by char types. CharPattern(char), } @@ -1049,7 +1051,7 @@ impl<'b> Pattern for &'b str { #[inline] fn as_utf8_pattern(&self) -> Option> { - Some(Utf8Pattern::StringPattern(self.as_bytes())) + Some(Utf8Pattern::StringPattern(*self)) } } diff --git a/library/std/src/env.rs b/library/std/src/env.rs index d3e4417656e9a..f60c8392785c1 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -689,7 +689,7 @@ pub fn home_dir() -> Option { /// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha /// [appledoc]: https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 /// -/// ```no_run +/// ``` /// use std::env; /// /// fn main() { diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index c70944790d2b5..ae9696fa2ca92 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -103,6 +103,7 @@ def __call__(self, valobj): printer.add(RustType.StdString, StdStringProvider) printer.add(RustType.StdOsString, StdOsStringProvider) printer.add(RustType.StdStr, StdStrProvider) +printer.add(RustType.StdBoxStr, StdBoxStrProvider) printer.add(RustType.StdSlice, StdSliceProvider) printer.add(RustType.StdVec, StdVecProvider) printer.add(RustType.StdVecDeque, StdVecDequeProvider) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index bd27998b37706..7d50de0d3050d 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -142,6 +142,20 @@ def display_hint(): return "array" +class StdBoxStrProvider(printer_base): + def __init__(self, valobj): + self._valobj = valobj + self._length = int(valobj["length"]) + self._data_ptr = valobj["data_ptr"] + + def to_string(self): + return self._data_ptr.lazy_string(encoding="utf-8", length=self._length) + + @staticmethod + def display_hint(): + return "string" + + class StdVecProvider(printer_base): def __init__(self, valobj): self._valobj = valobj @@ -203,6 +217,12 @@ def __init__(self, valobj, is_atomic=False): self._is_atomic = is_atomic self._ptr = unwrap_unique_or_non_null(valobj["ptr"]) self._value = self._ptr["data" if is_atomic else "value"] + # FIXME(shua): the debuginfo template type should be 'str' not 'u8' + if self._ptr.type.target().name == "alloc::rc::RcInner": + length = self._valobj["ptr"]["pointer"]["length"] + u8_ptr_ty = gdb.Type.pointer(gdb.lookup_type("u8")) + ptr = self._value.address.reinterpret_cast(u8_ptr_ty) + self._value = ptr.lazy_string(encoding="utf-8", length=length) self._strong = unwrap_scalar_wrappers(self._ptr["strong"]) self._weak = unwrap_scalar_wrappers(self._ptr["weak"]) - 1 diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index ca462654e44e6..1cc526a25604a 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -37,12 +37,14 @@ class RustType(Enum): StdNonZeroNumber = 29 StdPath = 30 StdPathBuf = 31 + StdBoxStr = 32 STD_STRING_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)String$") STD_STR_REGEX = re.compile(r"^&(mut )?str$") STD_SLICE_REGEX = re.compile(r"^&(mut )?\[.+\]$") STD_OS_STRING_REGEX = re.compile(r"^(std::ffi::([a-z_]+::)+)OsString$") +STD_BOX_STR_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)Box$") STD_VEC_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)Vec<.+>$") STD_VEC_DEQUE_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)VecDeque<.+>$") STD_BTREE_SET_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)BTreeSet<.+>$") @@ -67,6 +69,7 @@ class RustType(Enum): RustType.StdString: STD_STRING_REGEX, RustType.StdOsString: STD_OS_STRING_REGEX, RustType.StdStr: STD_STR_REGEX, + RustType.StdBoxStr: STD_BOX_STR_REGEX, RustType.StdSlice: STD_SLICE_REGEX, RustType.StdVec: STD_VEC_REGEX, RustType.StdVecDeque: STD_VEC_DEQUE_REGEX, diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs index d3c91be3a280a..ec8b65984852c 100644 --- a/src/librustdoc/html/macro_expansion.rs +++ b/src/librustdoc/html/macro_expansion.rs @@ -1,5 +1,8 @@ -use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item, walk_pat, walk_stmt, walk_ty}; -use rustc_ast::{Crate, Expr, Item, Pat, Stmt, Ty}; +use rustc_ast::visit::{ + AssocCtxt, Visitor, walk_assoc_item, walk_crate, walk_expr, walk_item, walk_pat, walk_stmt, + walk_ty, +}; +use rustc_ast::{AssocItem, Crate, Expr, Item, Pat, Stmt, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span}; @@ -161,4 +164,14 @@ impl<'ast> Visitor<'ast> for ExpandedCodeVisitor<'ast> { walk_ty(self, ty); } } + + fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) -> Self::Result { + if item.span.from_expansion() { + self.handle_new_span(item.span, || { + rustc_ast_pretty::pprust::assoc_item_to_string(item) + }); + } else { + walk_assoc_item(self, item, ctxt); + } + } } diff --git a/tests/codegen-llvm/debuginfo-unsize-field.rs b/tests/codegen-llvm/debuginfo-unsize-field.rs new file mode 100644 index 0000000000000..f82e8c4f6ae5e --- /dev/null +++ b/tests/codegen-llvm/debuginfo-unsize-field.rs @@ -0,0 +1,58 @@ +//@ compile-flags:-g -Copt-level=0 -C panic=abort + +// Check that debug information for structs with embedded str and [u8] slices is distinct from +// structs with embedded u8 + +#![crate_type = "lib"] + +// CHECK: ![[U8:[0-9]+]] = !DIBasicType(name: "u8", + +pub struct Foo { + a: u32, + b: str, +} +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "&{{[^"]+}}::Foo", {{.*}}elements: ![[FOO_REF_ELEMS:[0-9]+]] +// CHECK: ![[FOO_REF_ELEMS]] = !{![[FOO_REF_PTR:[0-9]+]], ![[FOO_REF_LEN:[0-9]+]]} +// CHECK: ![[FOO_REF_PTR]] = !DIDerivedType(tag: DW_TAG_member, name: "data_ptr", {{.*}}baseType: ![[FOO_PTR:[0-9]+]] +// CHECK: ![[FOO_PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[FOO:[0-9]+]] +// CHECK: ![[FOO]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", {{.*}}elements: ![[FOO_ELEMS:[0-9]+]] +// CHECK: ![[FOO_ELEMS]] = !{![[FOO_A:[0-9]+]], ![[FOO_B:[0-9]+]]} +// CHECK: ![[FOO_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a" +// CHECK: ![[FOO_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b", {{.*}}baseType: ![[U8_SLICE:[0-9]+]] +// +// CHECK: ![[U8_SLICE]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[U8]], {{.*}}elements: ![[U8_SLICE_ELEMS:[0-9]+]] +// CHECK: ![[U8_SLICE_ELEMS]] = !{![[U8_SLICE_RANGE:[0-9]+]]} +// this is special to embedded slices, there is no upper bound on the number of elements, +// that info is stored in the length metadata for a reference to the parent struct +// CHECK: ![[U8_SLICE_RANGE]] = !DISubrange(count: -1, lowerBound: 0) +// +// CHECK: ![[FOO_REF_LEN]] = !DIDerivedType(tag: DW_TAG_member, name: "length", {{.*}}baseType: ![[USIZE:[0-9]+]] +// CHECK: ![[USIZE]] = !DIBasicType(name: "usize" +pub struct Bar { + a: u32, + b: [u8], +} +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "&{{[^"]+}}::Bar", {{.*}}elements: ![[BAR_REF_ELEMS:[0-9]+]] +// CHECK: ![[BAR_REF_ELEMS]] = !{![[BAR_REF_PTR:[0-9]+]], ![[BAR_REF_LEN:[0-9]+]]} +// CHECK: ![[BAR_REF_PTR]] = !DIDerivedType(tag: DW_TAG_member, name: "data_ptr", {{.*}}baseType: ![[BAR_PTR:[0-9]+]] +// CHECK: ![[BAR_PTR]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[BAR:[0-9]+]] +// CHECK: ![[BAR]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Bar", {{.*}}elements: ![[BAR_ELEMS:[0-9]+]] +// CHECK: ![[BAR_ELEMS]] = !{![[BAR_A:[0-9]+]], ![[BAR_B:[0-9]+]]} +// CHECK: ![[BAR_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a" +// CHECK: ![[BAR_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b", {{.*}}baseType: ![[U8_SLICE]] +// CHECK: ![[BAR_REF_LEN]] = !DIDerivedType(tag: DW_TAG_member, name: "length", {{.*}}baseType: ![[USIZE:[0-9]+]] +pub struct Baz { + a: u32, + b: u8, +} +// CHECK: !DIDerivedType(tag: DW_TAG_pointer_type, name: "&{{[^"]+}}::Baz", {{.*}}baseType: ![[BAZ:[0-9]+]] +// CHECK: ![[BAZ]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Baz", {{.*}}elements: ![[BAZ_ELEMS:[0-9]+]] +// CHECK: ![[BAZ_ELEMS]] = !{![[BAZ_A:[0-9]+]], ![[BAZ_B:[0-9]+]]} +// CHECK: ![[BAZ_A]] = !DIDerivedType(tag: DW_TAG_member, name: "a" +// CHECK: ![[BAZ_B]] = !DIDerivedType(tag: DW_TAG_member, name: "b", {{.*}}baseType: ![[U8]] + +#[no_mangle] +pub fn test<'a>(a: &'a Foo, b: &'a Bar, c: &'a Baz) -> &'a u8 { + // just use this somehow so the debuginfo isn't removed + &a.b.as_bytes()[0] +} diff --git a/tests/codegen-llvm/no_builtins-at-crate.rs b/tests/codegen-llvm/no_builtins-at-crate.rs index ba1d31f60c390..de80a925aebc5 100644 --- a/tests/codegen-llvm/no_builtins-at-crate.rs +++ b/tests/codegen-llvm/no_builtins-at-crate.rs @@ -3,11 +3,13 @@ #![no_builtins] #![crate_type = "lib"] +use std::ffi::c_void; + // CHECK: define // CHECK-SAME: @__aeabi_memcpy // CHECK-SAME: #0 #[no_mangle] -pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) { +pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut c_void, src: *const c_void, size: usize) { // CHECK: call // CHECK-SAME: @memcpy( memcpy(dest, src, size); @@ -17,7 +19,7 @@ pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usi // CHECK-SAME: @memcpy // CHECK-SAME: #0 extern "C" { - pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; + pub fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; } // CHECK: attributes #0 diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs index 165cfcd968a67..178b92df3630a 100644 --- a/tests/debuginfo/strings-and-strs.rs +++ b/tests/debuginfo/strings-and-strs.rs @@ -23,6 +23,12 @@ //@ gdb-command:print str_in_rc //@ gdb-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull> {pointer: 0x[...]}, phantom: core::marker::PhantomData>, alloc: alloc::alloc::Global} +//@ gdb-command:print box_str +//@ gdb-check:$6 = alloc::boxed::Box [87, 111, 114, 108, 100] + +//@ gdb-command:print rc_str +//@ gdb-check:$7 = alloc::rc::Rc {ptr: core::ptr::non_null::NonNull> {pointer: alloc::rc::RcInner {strong: core::cell::Cell {value: core::cell::UnsafeCell {value: 1}}, weak: core::cell::Cell {value: core::cell::UnsafeCell {value: 1}}, value: 0x[...]}}, phantom: core::marker::PhantomData>, alloc: alloc::alloc::Global} + // === LLDB TESTS ================================================================================== //@ lldb-command:run //@ lldb-command:v plain_string @@ -40,6 +46,12 @@ //@ lldb-command:v str_in_rc //@ lldb-check:(alloc::rc::Rc<&str, alloc::alloc::Global>) str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } +//@ lldb-command:v box_str +//@ lldb-check:(alloc::boxed::Box) box_str = { __0 = { pointer = { pointer = { data_ptr = 0x[...] "World" length = 5 } } _marker = } __1 = } + +//@ lldb-command:v rc_str +//@ lldb-check:(alloc::rc::Rc) rc_str = strong=1, weak=0 { value = "World" } + #![allow(unused_variables)] pub struct Foo<'a> { @@ -53,6 +65,8 @@ fn main() { let str_in_tuple = ("Hello", "World"); let str_in_rc = std::rc::Rc::new("Hello"); + let box_str: Box = "World".into(); + let rc_str: std::rc::Rc = "World".into(); zzz(); // #break } diff --git a/tests/rustdoc-html/macro-expansion/assoc-items-decl-macro.rs b/tests/rustdoc-html/macro-expansion/assoc-items-decl-macro.rs new file mode 100644 index 0000000000000..294b3d5d74ca0 --- /dev/null +++ b/tests/rustdoc-html/macro-expansion/assoc-items-decl-macro.rs @@ -0,0 +1,24 @@ +// Ensure assoc items work for decl macros. +// Regression test for . + +//@ compile-flags: -Zunstable-options --generate-macro-expansion + +#![crate_name = "foo"] +#![feature(decl_macro)] + +//@ has 'src/foo/assoc-items-decl-macro.rs.html' + +pub macro first() { + type P1 = bool; + fn u1() {} +} + +trait C1 { + type P1; + fn u1(); +} + +impl C1 for u32 { + //@ matches - '//*[@class="expansion"]/*[@class="expanded"]' 'type P1 = bool;\nfn u1\(\) {}' + first!(); +} diff --git a/tests/rustdoc-html/macro-expansion/assoc-items-macro.rs b/tests/rustdoc-html/macro-expansion/assoc-items-macro.rs new file mode 100644 index 0000000000000..1760ade6f2eaf --- /dev/null +++ b/tests/rustdoc-html/macro-expansion/assoc-items-macro.rs @@ -0,0 +1,25 @@ +// Ensure assoc items work for macro rules. +// Regression test for . + +//@ compile-flags: -Zunstable-options --generate-macro-expansion + +#![crate_name = "foo"] + +//@ has 'src/foo/assoc-items-macro.rs.html' + +macro_rules! first { + () => { + type P1 = bool; + fn u1() {} + } +} + +trait C1 { + type P1; + fn u1(); +} + +impl C1 for u32 { + //@ matches - '//*[@class="expansion"]/*[@class="expanded"]' 'type P1 = bool;\nfn u1\(\) {}' + first!(); +} diff --git a/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr b/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr index 55ab144b92419..b19d965e7c198 100644 --- a/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr +++ b/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/not-wf-ambiguous-normalization.rs:14:6 | LL | impl Allocator for DefaultAllocator { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr index 38d1a537fe458..ba644957127ae 100644 --- a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr +++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `Q` is not constrained by the impl trait, self --> $DIR/unconstrained-param-in-impl-ambiguity.rs:7:13 | LL | unsafe impl Send for Inner {} - | ^ unconstrained type parameter + | -^-------- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `Q` error: aborting due to 1 previous error diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr index b06add2f5db5d..efb8a38e09955 100644 --- a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr @@ -3,6 +3,13 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Foo { | ^^ unconstrained lifetime parameter + | +help: use the lifetime parameter `'a` in the `Foo` type and use it in the type definition + | +LL ~ struct Foo(T); +LL | +LL ~ impl<'a> Foo { + | error[E0308]: mismatched types --> $DIR/hr-do-not-blame-outlives-static-ice.rs:13:11 diff --git a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr index 9ce20cb4875b9..ce0e6d6f0a081 100644 --- a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr +++ b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `X` is not constrained by the impl trait, self --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:9:6 | LL | impl S<'_> { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `X` error[E0308]: mismatched types --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:17:5 diff --git a/tests/ui/associated-inherent-types/next-solver-opaque-inherent-fn-ptr-issue-155204.stderr b/tests/ui/associated-inherent-types/next-solver-opaque-inherent-fn-ptr-issue-155204.stderr index 65a20433f1fba..a21ed19756477 100644 --- a/tests/ui/associated-inherent-types/next-solver-opaque-inherent-fn-ptr-issue-155204.stderr +++ b/tests/ui/associated-inherent-types/next-solver-opaque-inherent-fn-ptr-issue-155204.stderr @@ -27,7 +27,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/next-solver-opaque-inherent-fn-ptr-issue-155204.rs:7:6 | LL | impl Windows { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error[E0282]: type annotations needed --> $DIR/next-solver-opaque-inherent-fn-ptr-issue-155204.rs:12:22 diff --git a/tests/ui/associated-inherent-types/next-solver-opaque-inherent-no-ice.stderr b/tests/ui/associated-inherent-types/next-solver-opaque-inherent-no-ice.stderr index 0f893a6d5688e..3c9892d7a98ec 100644 --- a/tests/ui/associated-inherent-types/next-solver-opaque-inherent-no-ice.stderr +++ b/tests/ui/associated-inherent-types/next-solver-opaque-inherent-no-ice.stderr @@ -24,7 +24,10 @@ error[E0207]: the const parameter `X` is not constrained by the impl trait, self --> $DIR/next-solver-opaque-inherent-no-ice.rs:6:6 | LL | impl Foo { - | ^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `X` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/associated-types/issue-26262.stderr b/tests/ui/associated-types/issue-26262.stderr index 90e2d0d930164..4ac7416755039 100644 --- a/tests/ui/associated-types/issue-26262.stderr +++ b/tests/ui/associated-types/issue-26262.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl S { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `S` type and use it in the type definition + | +LL ~ struct S(T); +LL | +LL | trait Tr { type Assoc; fn test(); } +LL | +LL ~ impl S { + | error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-26262.rs:17:6 diff --git a/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr index 15d0820c895dd..e190dfdbf70b8 100644 --- a/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr +++ b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr @@ -3,6 +3,15 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Fun for Holder { | ^^ unconstrained lifetime parameter + | +help: use the lifetime parameter `'a` in the `Holder` type and use it in the type definition + | +LL ~ struct Holder<'a> { +LL | x: String, +LL | } +LL | +LL ~ impl<'a> Fun for Holder<'a> { + | error: aborting due to 1 previous error diff --git a/tests/ui/async-await/issues/issue-78654.full.stderr b/tests/ui/async-await/issues/issue-78654.full.stderr index 0d12a948c68bd..e1f9aa9ce81e7 100644 --- a/tests/ui/async-await/issues/issue-78654.full.stderr +++ b/tests/ui/async-await/issues/issue-78654.full.stderr @@ -8,7 +8,10 @@ error[E0207]: the const parameter `H` is not constrained by the impl trait, self --> $DIR/issue-78654.rs:9:6 | LL | impl Foo { - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `H` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/async-await/issues/issue-78654.min.stderr b/tests/ui/async-await/issues/issue-78654.min.stderr index 0d12a948c68bd..e1f9aa9ce81e7 100644 --- a/tests/ui/async-await/issues/issue-78654.min.stderr +++ b/tests/ui/async-await/issues/issue-78654.min.stderr @@ -8,7 +8,10 @@ error[E0207]: the const parameter `H` is not constrained by the impl trait, self --> $DIR/issue-78654.rs:9:6 | LL | impl Foo { - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `H` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr index 8112613f3bf80..f304bfc8e4cec 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr @@ -37,7 +37,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/unsized-anon-const-err-2.rs:13:6 | LL | impl Copy for S {} - | ^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -46,7 +49,10 @@ error[E0207]: the const parameter `M` is not constrained by the impl trait, self --> $DIR/unsized-anon-const-err-2.rs:16:6 | LL | impl Copy for S {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `M` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr index d58bc67232758..d214c31675a3b 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr @@ -24,7 +24,10 @@ error[E0207]: the const parameter `NUM` is not constrained by the impl trait, se --> $DIR/post-analysis-user-facing-param-env.rs:5:10 | LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | --^^^^^^^^^^^^^^^^ + | | | + | | unconstrained const parameter + | help: remove the unused type parameter `NUM` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr index 311caaede09af..e4287fae20f1f 100644 --- a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr +++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr @@ -71,6 +71,14 @@ LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported +help: use the type parameter `N` in the `ConstChunksExact` type and use it in the type definition + | +LL ~ struct ConstChunksExact<'rem, T: 'a, const N: usize, N> {} +LL | +LL | +LL | +LL ~ impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}, N> { + | error: aborting due to 8 previous errors diff --git a/tests/ui/const-generics/issues/issue-68366.full.stderr b/tests/ui/const-generics/issues/issue-68366.full.stderr index 02c34b8256d6d..53e42b1219732 100644 --- a/tests/ui/const-generics/issues/issue-68366.full.stderr +++ b/tests/ui/const-generics/issues/issue-68366.full.stderr @@ -14,7 +14,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:12:7 | LL | impl Collatz<{Some(N)}> {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -23,7 +26,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:19:6 | LL | impl Foo {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr index 4b544c49af8c1..40bf7dc6deeab 100644 --- a/tests/ui/const-generics/issues/issue-68366.min.stderr +++ b/tests/ui/const-generics/issues/issue-68366.min.stderr @@ -23,7 +23,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:12:7 | LL | impl Collatz<{Some(N)}> {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -32,7 +35,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:19:6 | LL | impl Foo {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr b/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr index ad89705e1dca8..f5a57f864564d 100644 --- a/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr +++ b/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr @@ -53,6 +53,14 @@ LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact< | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported +help: use the type parameter `N` in the `ConstChunksExact` type and use it in the type definition + | +LL ~ struct ConstChunksExact<'a, T: '_, const assert: usize, N> {} +LL | +LL | +LL | +LL ~ impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}, N> { + | error[E0308]: mismatched types --> $DIR/normalizing_with_unconstrained_impl_params.rs:6:27 diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs index abb69e5fc1588..e3d0bdbc7e9b0 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.rs +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + #![feature(fn_delegation)] trait Bound {} @@ -19,12 +21,16 @@ reuse ::static_method::<'static, Vec, false> as bar2; reuse Trait::static_method as error { self - 123 } //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method as error2; //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } //~^ ERROR: type annotations needed +//~| ERROR: delegation self type is not specified reuse ::static_method as error5; //~^ ERROR: the trait bound `String: Trait<'a, T, X>` is not satisfied diff --git a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr index 398fa2e5db92a..8d87b9376acd4 100644 --- a/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr +++ b/tests/ui/delegation/generics/free-to-trait-static-reuse.stderr @@ -1,21 +1,53 @@ +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:22:14 + | +LL | reuse Trait::static_method as error { self - 123 } + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:25:35 + | +LL | reuse Trait::<'static, i32, 123>::static_method as error2; + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:28:35 + | +LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: delegation self type is not specified + --> $DIR/free-to-trait-static-reuse.rs:31:14 + | +LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:33:49 + --> $DIR/free-to-trait-static-reuse.rs:39:49 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:32:1 + --> $DIR/free-to-trait-static-reuse.rs:38:1 | LL | struct Struct; | ^^^^^^^^^^^^^ help: the trait `Bound` is implemented for `usize` - --> $DIR/free-to-trait-static-reuse.rs:13:1 + --> $DIR/free-to-trait-static-reuse.rs:15:1 | LL | impl Bound for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `Trait` - --> $DIR/free-to-trait-static-reuse.rs:7:11 + --> $DIR/free-to-trait-static-reuse.rs:9:11 | LL | trait Trait<'a, T, const X: usize> | ----- required by a bound in this trait @@ -24,13 +56,13 @@ LL | Self: Bound, | ^^^^^^^^ required by this bound in `Trait` error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:20:14 + --> $DIR/free-to-trait-static-reuse.rs:22:14 | LL | reuse Trait::static_method as error { self - 123 } | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,13 +71,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:22:35 + --> $DIR/free-to-trait-static-reuse.rs:25:35 | LL | reuse Trait::<'static, i32, 123>::static_method as error2; | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,13 +86,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:24:35 + --> $DIR/free-to-trait-static-reuse.rs:28:35 | LL | reuse Trait::<'static, i32, 123>::static_method::<'static, String, false> as error3; | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'static, i32, 123>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,13 +101,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0283]: type annotations needed - --> $DIR/free-to-trait-static-reuse.rs:26:14 + --> $DIR/free-to-trait-static-reuse.rs:31:14 | LL | reuse Trait::static_method::<'static, Vec, false> as error4 { self + 4 } | ^^^^^^^^^^^^^ cannot infer type | note: multiple `impl`s satisfying `_: Trait<'a, T, X>` found - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,13 +116,13 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `String: Trait<'a, T, X>` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:29:8 + --> $DIR/free-to-trait-static-reuse.rs:35:8 | LL | reuse ::static_method as error5; | ^^^^^^ the trait `Trait<'a, T, X>` is not implemented for `String` | help: the following other types implement trait `Trait<'a, T, X>` - --> $DIR/free-to-trait-static-reuse.rs:12:1 + --> $DIR/free-to-trait-static-reuse.rs:14:1 | LL | impl<'a, T, const X: usize> Trait<'a, T, X> for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `usize` @@ -99,23 +131,23 @@ LL | impl<'a, T, const X: usize> Trait<'a, T, X> for Struct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Struct` error[E0277]: the trait bound `Struct: Bound` is not satisfied - --> $DIR/free-to-trait-static-reuse.rs:36:8 + --> $DIR/free-to-trait-static-reuse.rs:42:8 | LL | reuse ::static_method as error6; | ^^^^^^ unsatisfied trait bound | help: the trait `Bound` is not implemented for `Struct` - --> $DIR/free-to-trait-static-reuse.rs:32:1 + --> $DIR/free-to-trait-static-reuse.rs:38:1 | LL | struct Struct; | ^^^^^^^^^^^^^ help: the trait `Bound` is implemented for `usize` - --> $DIR/free-to-trait-static-reuse.rs:13:1 + --> $DIR/free-to-trait-static-reuse.rs:15:1 | LL | impl Bound for usize {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `Trait::static_method` - --> $DIR/free-to-trait-static-reuse.rs:7:11 + --> $DIR/free-to-trait-static-reuse.rs:9:11 | LL | Self: Bound, | ^^^^^^^^ required by this bound in `Trait::static_method` @@ -123,7 +155,7 @@ LL | { LL | fn static_method<'c: 'c, U, const B: bool>(x: usize) {} | ------------- required by a bound in this associated function -error: aborting due to 7 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0277, E0283. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/delegation/self-ty-ice-156388.rs b/tests/ui/delegation/self-ty-ice-156388.rs new file mode 100644 index 0000000000000..542f56867b2b2 --- /dev/null +++ b/tests/ui/delegation/self-ty-ice-156388.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + +#![feature(fn_delegation)] + +reuse Default::default; +//~^ ERROR: delegation self type is not specified + +fn main() {} diff --git a/tests/ui/delegation/self-ty-ice-156388.stderr b/tests/ui/delegation/self-ty-ice-156388.stderr new file mode 100644 index 0000000000000..c2323cf1c6082 --- /dev/null +++ b/tests/ui/delegation/self-ty-ice-156388.stderr @@ -0,0 +1,10 @@ +error: delegation self type is not specified + --> $DIR/self-ty-ice-156388.rs:5:16 + | +LL | reuse Default::default; + | ^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs index 253ce1fffff72..2355decd3d4f7 100644 --- a/tests/ui/delegation/target-expr.rs +++ b/tests/ui/delegation/target-expr.rs @@ -1,3 +1,5 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes + #![feature(fn_delegation)] trait Trait { @@ -14,6 +16,7 @@ fn foo(x: i32) -> i32 { x } fn bar(_: T) { reuse Trait::static_method { //~^ ERROR mismatched types + //~| ERROR: delegation self type is not specified let _ = T::Default(); //~^ ERROR can't use generic parameters from outer item } diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr index 7153fa4178374..8965a1a060786 100644 --- a/tests/ui/delegation/target-expr.stderr +++ b/tests/ui/delegation/target-expr.stderr @@ -1,18 +1,18 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/target-expr.rs:17:17 + --> $DIR/target-expr.rs:20:17 | LL | fn bar(_: T) { | - type parameter from outer item LL | reuse Trait::static_method { | ------------- generic parameter used in this inner delegated function -LL | +... LL | let _ = T::Default(); | ^ use of generic parameter from outer item | = note: nested items are independent from their parent item for everything except for privacy and name resolution error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/target-expr.rs:25:17 + --> $DIR/target-expr.rs:28:17 | LL | let x = y; | ^ @@ -20,7 +20,7 @@ LL | let x = y; = help: use the `|| { ... }` closure form instead error[E0424]: expected value, found module `self` - --> $DIR/target-expr.rs:32:5 + --> $DIR/target-expr.rs:35:5 | LL | fn main() { | ---- this function can't have a `self` parameter @@ -29,29 +29,38 @@ LL | self.0; | ^^^^ `self` value is a keyword only available in methods with a `self` parameter error[E0425]: cannot find value `x` in this scope - --> $DIR/target-expr.rs:34:13 + --> $DIR/target-expr.rs:37:13 | LL | let z = x; | ^ | help: the binding `x` is available in a different scope in the same function - --> $DIR/target-expr.rs:25:13 + --> $DIR/target-expr.rs:28:13 | LL | let x = y; | ^ +error: delegation self type is not specified + --> $DIR/target-expr.rs:17:18 + | +LL | reuse Trait::static_method { + | ^^^^^^^^^^^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + error[E0308]: mismatched types - --> $DIR/target-expr.rs:15:32 + --> $DIR/target-expr.rs:17:32 | LL | reuse Trait::static_method { | ________________________________^ LL | | +LL | | LL | | let _ = T::Default(); LL | | LL | | } | |_____^ expected `i32`, found `()` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/unsupported.current.stderr b/tests/ui/delegation/unsupported.current.stderr index 21ea451a2ea5c..88938cd8b362c 100644 --- a/tests/ui/delegation/unsupported.current.stderr +++ b/tests/ui/delegation/unsupported.current.stderr @@ -1,41 +1,49 @@ -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:29:25 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:29:25 + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:29:25 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:32:24 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:32:24 + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:32:24 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: delegation self type is not specified + --> $DIR/unsupported.rs:54:18 + | +LL | reuse Trait::foo; + | ^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.next.stderr b/tests/ui/delegation/unsupported.next.stderr index 21ea451a2ea5c..88938cd8b362c 100644 --- a/tests/ui/delegation/unsupported.next.stderr +++ b/tests/ui/delegation/unsupported.next.stderr @@ -1,41 +1,49 @@ -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:29:25 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:29:25 + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:29:25 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:30:25 | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` - --> $DIR/unsupported.rs:32:24 +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ | note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process... - --> $DIR/unsupported.rs:32:24 + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle -note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition - --> $DIR/unsupported.rs:32:24 + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle +note: cycle used when checking assoc item `opaque::::opaque_ret` is compatible with trait definition + --> $DIR/unsupported.rs:33:24 | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error: delegation self type is not specified + --> $DIR/unsupported.rs:54:18 + | +LL | reuse Trait::foo; + | ^^^ + | + = help: consider explicitly specifying self type: `reuse ::function` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/delegation/unsupported.rs b/tests/ui/delegation/unsupported.rs index 678c93dcd53c0..3349c4ec27ab1 100644 --- a/tests/ui/delegation/unsupported.rs +++ b/tests/ui/delegation/unsupported.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Z deduplicate-diagnostics=yes //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver @@ -51,6 +52,7 @@ mod effects { } reuse Trait::foo; + //~^ ERROR: delegation self type is not specified } fn main() {} diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr index 515637dd47fc3..6cf78a06752ba 100644 --- a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr @@ -22,7 +22,10 @@ error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, --> $DIR/unconstrained_const_param_on_drop.rs:3:6 | LL | impl Drop for Foo {} - | ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `UNUSED` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/eii/dylib_needs_impl.rs b/tests/ui/eii/dylib_needs_impl.rs new file mode 100644 index 0000000000000..bb1ec22b0488e --- /dev/null +++ b/tests/ui/eii/dylib_needs_impl.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ needs-crate-type: dylib +#![crate_type = "dylib"] +#![feature(extern_item_impls)] + +#[eii(eii1)] //~ ERROR `#[eii1]` required, but not found +fn decl1(x: u64); diff --git a/tests/ui/eii/dylib_needs_impl.stderr b/tests/ui/eii/dylib_needs_impl.stderr new file mode 100644 index 0000000000000..60ef656c30174 --- /dev/null +++ b/tests/ui/eii/dylib_needs_impl.stderr @@ -0,0 +1,10 @@ +error: `#[eii1]` required, but not found + --> $DIR/dylib_needs_impl.rs:6:7 + | +LL | #[eii(eii1)] + | ^^^^ expected because `#[eii1]` was declared here in crate `dylib_needs_impl` + | + = help: expected at least one implementation in crate `dylib_needs_impl` or any of its dependencies + +error: aborting due to 1 previous error + diff --git a/tests/ui/error-codes/E0207.stderr b/tests/ui/error-codes/E0207.stderr index 01d7c41854412..97e2fa0ae3f45 100644 --- a/tests/ui/error-codes/E0207.stderr +++ b/tests/ui/error-codes/E0207.stderr @@ -3,6 +3,13 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Foo { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Foo` type and use it in the type definition + | +LL ~ struct Foo; +LL | +LL ~ impl Foo { + | error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0264.rs b/tests/ui/error-codes/E0264.rs index 855644796ed45..5974eb05e2c4b 100644 --- a/tests/ui/error-codes/E0264.rs +++ b/tests/ui/error-codes/E0264.rs @@ -1,7 +1,7 @@ #![feature(lang_items)] extern "C" { - #[lang = "copy"] + #[lang = "copy"] //~ ERROR E0718 fn copy(); //~ ERROR E0264 } diff --git a/tests/ui/error-codes/E0264.stderr b/tests/ui/error-codes/E0264.stderr index 6442f42e689d6..aa578194d1f28 100644 --- a/tests/ui/error-codes/E0264.stderr +++ b/tests/ui/error-codes/E0264.stderr @@ -1,9 +1,16 @@ +error[E0718]: `copy` lang item must be applied to a trait + --> $DIR/E0264.rs:4:5 + | +LL | #[lang = "copy"] + | ^^^^^^^^^^^^^^^^ attribute should be applied to a trait, not a function + error[E0264]: unknown external lang item: `copy` --> $DIR/E0264.rs:5:5 | LL | fn copy(); | ^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0264`. +Some errors have detailed explanations: E0264, E0718. +For more information about an error, try `rustc --explain E0264`. diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7fd7504622c89..e69797c0aa063 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -17,6 +17,14 @@ impl Drop for Foo { //~^ ERROR use of unstable library feature `pin_ergonomics` [E0658] } +struct Sugar; + +impl Drop for Sugar { + //~^ ERROR not all trait items implemented, missing: `drop` + fn drop(&pin mut self) {} //~ ERROR pinned reference syntax is experimental + //~^ ERROR use of unstable library feature `pin_ergonomics` [E0658] +} + fn foo(mut x: Pin<&mut Foo>) { Foo::foo_sugar(x.as_mut()); Foo::foo_sugar_const(x.as_ref()); diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index e1919666adbda..c4db06d499450 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -29,7 +29,17 @@ LL | fn pin_drop(&pin mut self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:23:14 + --> $DIR/feature-gate-pin_ergonomics.rs:24:14 + | +LL | fn drop(&pin mut self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:31:14 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -39,7 +49,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:27:14 + --> $DIR/feature-gate-pin_ergonomics.rs:35:14 | LL | let _y: &pin const Foo = x; | ^^^ @@ -49,7 +59,7 @@ LL | let _y: &pin const Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:30:18 + --> $DIR/feature-gate-pin_ergonomics.rs:38:18 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -59,7 +69,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:42:18 + --> $DIR/feature-gate-pin_ergonomics.rs:50:18 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -69,7 +79,7 @@ LL | fn baz_sugar(_: &pin const Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:45:31 + --> $DIR/feature-gate-pin_ergonomics.rs:53:31 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -79,7 +89,7 @@ LL | let mut x: Pin<&mut _> = &pin mut Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:50:23 + --> $DIR/feature-gate-pin_ergonomics.rs:58:23 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -89,7 +99,7 @@ LL | let x: Pin<&_> = &pin const Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:57:6 + --> $DIR/feature-gate-pin_ergonomics.rs:65:6 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -99,7 +109,7 @@ LL | &pin mut x: &pin mut i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:57:18 + --> $DIR/feature-gate-pin_ergonomics.rs:65:18 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -109,7 +119,7 @@ LL | &pin mut x: &pin mut i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:60:6 + --> $DIR/feature-gate-pin_ergonomics.rs:68:6 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -119,7 +129,7 @@ LL | &pin const y: &'a pin const i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:60:23 + --> $DIR/feature-gate-pin_ergonomics.rs:68:23 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -129,7 +139,7 @@ LL | &pin const y: &'a pin const i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:63:9 + --> $DIR/feature-gate-pin_ergonomics.rs:71:9 | LL | ref pin mut z: i32, | ^^^ @@ -139,7 +149,7 @@ LL | ref pin mut z: i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:64:9 + --> $DIR/feature-gate-pin_ergonomics.rs:72:9 | LL | ref pin const w: i32, | ^^^ @@ -149,7 +159,7 @@ LL | ref pin const w: i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:76:23 + --> $DIR/feature-gate-pin_ergonomics.rs:84:23 | LL | fn foo_sugar(&pin mut self) {} | ^^^ @@ -159,7 +169,7 @@ LL | fn foo_sugar(&pin mut self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:77:29 + --> $DIR/feature-gate-pin_ergonomics.rs:85:29 | LL | fn foo_sugar_const(&pin const self) {} | ^^^ @@ -169,7 +179,7 @@ LL | fn foo_sugar_const(&pin const self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:81:22 + --> $DIR/feature-gate-pin_ergonomics.rs:89:22 | LL | fn pin_drop(&pin mut self) {} | ^^^ @@ -179,7 +189,7 @@ LL | fn pin_drop(&pin mut self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:87:18 + --> $DIR/feature-gate-pin_ergonomics.rs:95:18 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -189,7 +199,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:90:22 + --> $DIR/feature-gate-pin_ergonomics.rs:98:22 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -199,7 +209,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:102:22 + --> $DIR/feature-gate-pin_ergonomics.rs:110:22 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -209,7 +219,7 @@ LL | fn baz_sugar(_: &pin const Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:105:35 + --> $DIR/feature-gate-pin_ergonomics.rs:113:35 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -219,7 +229,7 @@ LL | let mut x: Pin<&mut _> = &pin mut Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:110:27 + --> $DIR/feature-gate-pin_ergonomics.rs:118:27 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -229,7 +239,7 @@ LL | let x: Pin<&_> = &pin const Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:117:10 + --> $DIR/feature-gate-pin_ergonomics.rs:125:10 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -239,7 +249,7 @@ LL | &pin mut x: &pin mut i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:117:22 + --> $DIR/feature-gate-pin_ergonomics.rs:125:22 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -249,7 +259,7 @@ LL | &pin mut x: &pin mut i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:120:10 + --> $DIR/feature-gate-pin_ergonomics.rs:128:10 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -259,7 +269,7 @@ LL | &pin const y: &'a pin const i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:120:27 + --> $DIR/feature-gate-pin_ergonomics.rs:128:27 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -269,7 +279,7 @@ LL | &pin const y: &'a pin const i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:123:13 + --> $DIR/feature-gate-pin_ergonomics.rs:131:13 | LL | ref pin mut z: i32, | ^^^ @@ -279,7 +289,7 @@ LL | ref pin mut z: i32, = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:124:13 + --> $DIR/feature-gate-pin_ergonomics.rs:132:13 | LL | ref pin const w: i32, | ^^^ @@ -308,6 +318,16 @@ LL | fn pin_drop(&pin mut self) {} = help: add `#![feature(pin_ergonomics)]` 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]: use of unstable library feature `pin_ergonomics` + --> $DIR/feature-gate-pin_ergonomics.rs:24:5 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` 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[E0046]: not all trait items implemented, missing: `drop` --> $DIR/feature-gate-pin_ergonomics.rs:14:1 | @@ -316,8 +336,16 @@ LL | impl Drop for Foo { | = help: implement the missing item: `fn drop(&mut self) { todo!() }` +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/feature-gate-pin_ergonomics.rs:22:1 + | +LL | impl Drop for Sugar { + | ^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:34:9 + --> $DIR/feature-gate-pin_ergonomics.rs:42:9 | LL | fn bar(x: Pin<&mut Foo>) { | - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -327,7 +355,7 @@ LL | foo(x); | ^ value used here after move | note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:20:15 + --> $DIR/feature-gate-pin_ergonomics.rs:28:15 | LL | fn foo(mut x: Pin<&mut Foo>) { | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value @@ -335,7 +363,7 @@ LL | fn foo(mut x: Pin<&mut Foo>) { | in this function error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:39:5 + --> $DIR/feature-gate-pin_ergonomics.rs:47:5 | LL | fn baz(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -354,7 +382,7 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 34 previous errors +error: aborting due to 37 previous errors Some errors have detailed explanations: E0046, E0382, E0658. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/foreign/foreign-int-types.rs b/tests/ui/foreign/foreign-int-types.rs index d20a4c96ea0e2..bac9d8c603918 100644 --- a/tests/ui/foreign/foreign-int-types.rs +++ b/tests/ui/foreign/foreign-int-types.rs @@ -4,7 +4,7 @@ mod xx { extern "C" { - pub fn strlen(str: *const u8) -> usize; + pub fn strlen2(str: *const u8) -> usize; pub fn foo(x: isize, y: usize); } } diff --git a/tests/ui/generic-associated-types/bugs/issue-87735.stderr b/tests/ui/generic-associated-types/bugs/issue-87735.stderr index c3f4f7a73f35f..60e1d71cdac7d 100644 --- a/tests/ui/generic-associated-types/bugs/issue-87735.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-87735.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self | LL | impl<'b, T, U> AsRef2 for Foo | ^ unconstrained type parameter + | +help: use the type parameter `U` in the `Foo` type and use it in the type definition + | +LL ~ struct Foo(T); +LL | #[derive(Debug)] +LL | struct FooRef<'a, U>(&'a [U]); +LL | +LL ~ impl<'b, T, U> AsRef2 for Foo + | error[E0309]: the parameter type `U` may not live long enough --> $DIR/issue-87735.rs:34:3 diff --git a/tests/ui/generic-associated-types/bugs/issue-88526.stderr b/tests/ui/generic-associated-types/bugs/issue-88526.stderr index 5e39eb7a6b95a..ea2962c693f0a 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88526.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-88526.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `I` is not constrained by the impl trait, self --> $DIR/issue-88526.rs:25:13 | LL | impl<'q, Q, I, F> A for TestB - | ^ unconstrained type parameter + | ^-- + | | + | unconstrained type parameter + | help: remove the unused type parameter `I` error[E0309]: the parameter type `F` may not live long enough --> $DIR/issue-88526.rs:16:5 diff --git a/tests/ui/generics/unconstrained-param-default-available.rs b/tests/ui/generics/unconstrained-param-default-available.rs new file mode 100644 index 0000000000000..a602a88cb6d6e --- /dev/null +++ b/tests/ui/generics/unconstrained-param-default-available.rs @@ -0,0 +1,18 @@ +//! Test that making use of parameter is suggested when a parameter with default type is available + +struct S { + _u: U, +} +impl MyTrait for S {} +//~^ ERROR the type parameter `V` is not constrained by the impl trait, self type, or predicates + +struct S2 { + _t: T, + _u: U, +} +impl MyTrait for S2 {} +//~^ ERROR the type parameter `V` is not constrained by the impl trait, self type, or predicates + +trait MyTrait {} + +fn main() {} diff --git a/tests/ui/generics/unconstrained-param-default-available.stderr b/tests/ui/generics/unconstrained-param-default-available.stderr new file mode 100644 index 0000000000000..f1eac56b366cf --- /dev/null +++ b/tests/ui/generics/unconstrained-param-default-available.stderr @@ -0,0 +1,35 @@ +error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-param-default-available.rs:6:6 + | +LL | impl MyTrait for S {} + | ^ unconstrained type parameter + | +help: either remove the unused type parameter `V` + | +LL - impl MyTrait for S {} +LL + impl MyTrait for S {} + | +help: or use it + | +LL | impl MyTrait for S {} + | +++ + +error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-param-default-available.rs:13:9 + | +LL | impl MyTrait for S2 {} + | ^ unconstrained type parameter + | +help: either remove the unused type parameter `V` + | +LL - impl MyTrait for S2 {} +LL + impl MyTrait for S2 {} + | +help: or use it + | +LL | impl MyTrait for S2 {} + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr index 19b02ad396cd3..958b1ff0664ab 100644 --- a/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr +++ b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr @@ -2,13 +2,19 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/unconstrained-type-params-inherent-impl.rs:11:6 | LL | impl MyType { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained-type-params-inherent-impl.rs:20:9 | LL | impl MyType1 { - | ^ unconstrained type parameter + | --^ + | | | + | | unconstrained type parameter + | help: remove the unused type parameter `U` error: aborting due to 2 previous errors diff --git a/tests/ui/generics/unconstrained-used-param.rs b/tests/ui/generics/unconstrained-used-param.rs new file mode 100644 index 0000000000000..592880fcf7527 --- /dev/null +++ b/tests/ui/generics/unconstrained-used-param.rs @@ -0,0 +1,23 @@ +//! Test that making use of parameter is suggested when the parameter is used in the impl +//! but not in the trait or self type + +struct S; +impl S { +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + fn foo(&self, x: T) { + // use T here + } +} + + +struct S2 { + _f: F, +} +impl S2 { +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + fn foo(&self, x: T) { + // use T here + } +} + +fn main() {} diff --git a/tests/ui/generics/unconstrained-used-param.stderr b/tests/ui/generics/unconstrained-used-param.stderr new file mode 100644 index 0000000000000..b0d9320602b2f --- /dev/null +++ b/tests/ui/generics/unconstrained-used-param.stderr @@ -0,0 +1,29 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-used-param.rs:5:6 + | +LL | impl S { + | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `S` type and use it in the type definition + | +LL ~ struct S; +LL ~ impl S { + | + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-used-param.rs:16:9 + | +LL | impl S2 { + | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `S2` type and use it in the type definition + | +LL ~ struct S2 { +LL | _f: F, +LL | } +LL ~ impl S2 { + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/issues/issue-16562.stderr b/tests/ui/issues/issue-16562.stderr index efbd7f712a45a..ac957fdb069d0 100644 --- a/tests/ui/issues/issue-16562.stderr +++ b/tests/ui/issues/issue-16562.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/issue-16562.rs:10:6 | LL | impl Collection for Col { - | ^ unconstrained type parameter + | ^-- + | | + | unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-22886.stderr b/tests/ui/issues/issue-22886.stderr index a04fa677f9ec5..aebbdf8a2ec12 100644 --- a/tests/ui/issues/issue-22886.stderr +++ b/tests/ui/issues/issue-22886.stderr @@ -3,6 +3,13 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Iterator for Newtype { | ^^ unconstrained lifetime parameter + | +help: use the lifetime parameter `'a` in the `Newtype` type and use it in the type definition + | +LL ~ struct Newtype<'a>(Option>); +LL | +LL ~ impl<'a> Iterator for Newtype<'a> { + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-35139.stderr b/tests/ui/issues/issue-35139.stderr index 875af70483224..4568b9b70f412 100644 --- a/tests/ui/issues/issue-35139.stderr +++ b/tests/ui/issues/issue-35139.stderr @@ -3,6 +3,13 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> MethodType for MTFn { | ^^ unconstrained lifetime parameter + | +help: use the lifetime parameter `'a` in the `MTFn` type and use it in the type definition + | +LL ~ pub struct MTFn<'a>; +LL | +LL ~ impl<'a> MethodType for MTFn<'a> { + | error: aborting due to 1 previous error diff --git a/tests/ui/lint/runtime-symbols.rs b/tests/ui/lint/runtime-symbols.rs new file mode 100644 index 0000000000000..813ebff4ff4de --- /dev/null +++ b/tests/ui/lint/runtime-symbols.rs @@ -0,0 +1,54 @@ +// This test checks the runtime symbols lint. + +//@ edition: 2021 +//@ normalize-stderr: "\*const [iu]8" -> "*const U8" + +#![allow(clashing_extern_declarations)] // we are volontary testing differents defs + +use core::ffi::{c_char, c_int, c_void}; + +fn invalid() { + #[no_mangle] + pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { + std::ptr::null_mut() + } + //~^^^ ERROR invalid definition of the runtime `memcpy` symbol + + #[no_mangle] + pub fn memmove() {} + //~^ ERROR invalid definition of the runtime `memmove` symbol + + extern "C" { + pub fn memset(); + //~^ ERROR invalid definition of the runtime `memset` symbol + + pub fn memcmp(); + //~^ ERROR invalid definition of the runtime `memcmp` symbol + } + + #[export_name = "bcmp"] + pub fn bcmp_() {} + //~^ ERROR invalid definition of the runtime `bcmp` symbol + + #[no_mangle] + pub static strlen: () = (); + //~^ ERROR invalid definition of the runtime `strlen` symbol +} + +fn valid() { + extern "C" { + fn memcpy(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; + + fn memmove(dest: *mut c_void, src: *const c_void, n: usize) -> *mut c_void; + + fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void; + + fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; + + fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int; + + static strlen: Option usize>; + } +} + +fn main() {} diff --git a/tests/ui/lint/runtime-symbols.stderr b/tests/ui/lint/runtime-symbols.stderr new file mode 100644 index 0000000000000..bac3c352bdca6 --- /dev/null +++ b/tests/ui/lint/runtime-symbols.stderr @@ -0,0 +1,63 @@ +error: invalid definition of the runtime `memcpy` symbol used by the standard library + --> $DIR/runtime-symbols.rs:12:5 + | +LL | pub extern "C" fn memcpy(dest: *mut c_void, src: *const c_void, n: i64) -> *mut c_void { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` + found `extern "C" fn(*mut c_void, *const c_void, i64) -> *mut c_void` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcpy")]`, or `#[link_name = "memcpy"]` + = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default + +error: invalid definition of the runtime `memmove` symbol used by the standard library + --> $DIR/runtime-symbols.rs:18:5 + | +LL | pub fn memmove() {} + | ^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*mut c_void, *const c_void, usize) -> *mut c_void` + found `fn()` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memmove")]`, or `#[link_name = "memmove"]` + +error: invalid definition of the runtime `memset` symbol used by the standard library + --> $DIR/runtime-symbols.rs:22:9 + | +LL | pub fn memset(); + | ^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*mut c_void, i32, usize) -> *mut c_void` + found `unsafe extern "C" fn()` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memset")]`, or `#[link_name = "memset"]` + +error: invalid definition of the runtime `memcmp` symbol used by the standard library + --> $DIR/runtime-symbols.rs:25:9 + | +LL | pub fn memcmp(); + | ^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` + found `unsafe extern "C" fn()` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcmp")]`, or `#[link_name = "memcmp"]` + +error: invalid definition of the runtime `bcmp` symbol used by the standard library + --> $DIR/runtime-symbols.rs:30:5 + | +LL | pub fn bcmp_() {} + | ^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32` + found `fn()` + = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "bcmp")]`, or `#[link_name = "bcmp"]` + +error: invalid definition of the runtime `strlen` symbol used by the standard library + --> $DIR/runtime-symbols.rs:34:5 + | +LL | pub static strlen: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: expected `unsafe extern "C" fn(*const U8) -> usize` + found `static strlen: ()` + = help: either fix the signature or remove any attributes `#[unsafe(no_mangle)]` or `#[unsafe(export_name = "strlen")]` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.rs b/tests/ui/pin-ergonomics/pinned-drop-check.rs index a8005b94dbba2..bd8d096fec547 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.rs +++ b/tests/ui/pin-ergonomics/pinned-drop-check.rs @@ -25,11 +25,11 @@ mod pin_drop_only { struct Bar; impl Drop for Foo { - fn pin_drop(&pin mut self) {} // ok, only `pin_drop` is implemented + fn pin_drop(&pin mut self) {} // ok, non-`#[pin_v2]` can also implement `pin_drop` } impl Drop for Bar { - fn pin_drop(&pin mut self) {} // ok, non-`#[pin_v2]` can also implement `pin_drop` + fn pin_drop(&pin mut self) {} // ok, `#[pin_v2]` implements `pin_drop` } } @@ -60,16 +60,67 @@ mod neither { impl Drop for Bar {} //~ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` [E0046] } -mod drop_wrong_type { +mod drop_sugar { struct Foo; #[pin_v2] struct Bar; impl Drop for Foo { - fn drop(&pin mut self) {} //~ ERROR method `drop` has an incompatible type for trait [E0053] + fn drop(&pin mut self) {} // ok, sugar for `pin_drop` } + impl Drop for Bar { - fn drop(&pin mut self) {} + fn drop(&pin mut self) {} // ok, sugar for `pin_drop` + } +} + +mod drop_pin_const_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin const self) {} //~ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop(&pin const self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + //~| ERROR `Bar` must implement `pin_drop` + } +} + +mod drop_with_lifetime_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop<'a>(&'a pin mut self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop<'a>(&'a pin mut self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + //~| ERROR `Bar` must implement `pin_drop` + } +} + +mod drop_explicit_pin_wrong_type { + use std::pin::Pin; + + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(self: Pin<&mut Self>) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop(self: Pin<&mut Self>) {} //~^ ERROR method `drop` has an incompatible type for trait [E0053] //~| ERROR `Bar` must implement `pin_drop` } @@ -124,4 +175,31 @@ mod explicit_call_drop { } } +mod explicit_call_drop_sugar { + struct Foo; + + impl Drop for Foo { + fn drop(&pin mut self) { + Drop::drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + Drop::pin_drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } +} + +mod sugar_and_pin_drop { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin mut self) {} + fn pin_drop(&pin mut self) {} //~ ERROR duplicate definitions with name `pin_drop` + } + + impl Drop for Bar { + fn drop(&pin mut self) {} + fn pin_drop(&pin mut self) {} //~ ERROR duplicate definitions with name `pin_drop` + } +} + fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index edadbcd0a0a93..3a848c66578b4 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -1,3 +1,27 @@ +error[E0201]: duplicate definitions with name `pin_drop`: + --> $DIR/pinned-drop-check.rs:196:9 + | +LL | fn drop(&pin mut self) {} + | ------------------------- previous definition here +LL | fn pin_drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | + --> $SRC_DIR/core/src/ops/drop.rs:LL:COL + | + = note: item in trait + +error[E0201]: duplicate definitions with name `pin_drop`: + --> $DIR/pinned-drop-check.rs:201:9 + | +LL | fn drop(&pin mut self) {} + | ------------------------- previous definition here +LL | fn pin_drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | + --> $SRC_DIR/core/src/ops/drop.rs:LL:COL + | + = note: item in trait + error: `Bar` must implement `pin_drop` --> $DIR/pinned-drop-check.rs:18:9 | @@ -55,56 +79,157 @@ LL | impl Drop for Bar {} | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation error: `Bar` must implement `pin_drop` - --> $DIR/pinned-drop-check.rs:72:9 + --> $DIR/pinned-drop-check.rs:87:9 | -LL | fn drop(&pin mut self) {} - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: structurally pinned types must keep `Pin`'s safety contract note: `Bar` is marked `#[pin_v2]` here - --> $DIR/pinned-drop-check.rs:65:5 + --> $DIR/pinned-drop-check.rs:79:5 | LL | #[pin_v2] | ^^^^^^^^^ help: implement `pin_drop` instead | -LL | fn pin_drop(&pin mut self) {} - | ++++ +LL - fn drop(&pin const self) {} +LL + fn pin_drop(&pin mut self) {} + | help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning | LL - #[pin_v2] | error[E0053]: method `drop` has an incompatible type for trait - --> $DIR/pinned-drop-check.rs:69:17 + --> $DIR/pinned-drop-check.rs:83:17 | -LL | fn drop(&pin mut self) {} - | ^^^^^^^^^^^^^ expected `&mut drop_wrong_type::Foo`, found `Pin<&mut drop_wrong_type::Foo>` +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Foo`, found `Pin<&drop_pin_const_wrong_type::Foo>` | - = note: expected signature `fn(&mut drop_wrong_type::Foo)` - found signature `fn(Pin<&mut drop_wrong_type::Foo>)` + = note: expected signature `fn(&mut drop_pin_const_wrong_type::Foo)` + found signature `fn(Pin<&drop_pin_const_wrong_type::Foo>)` help: change the self-receiver type to match the trait | -LL - fn drop(&pin mut self) {} +LL - fn drop(&pin const self) {} LL + fn drop(&mut self) {} | error[E0053]: method `drop` has an incompatible type for trait - --> $DIR/pinned-drop-check.rs:72:17 + --> $DIR/pinned-drop-check.rs:87:17 | -LL | fn drop(&pin mut self) {} - | ^^^^^^^^^^^^^ expected `&mut drop_wrong_type::Bar`, found `Pin<&mut drop_wrong_type::Bar>` +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Bar`, found `Pin<&drop_pin_const_wrong_type::Bar>` + | + = note: expected signature `fn(&mut drop_pin_const_wrong_type::Bar)` + found signature `fn(Pin<&drop_pin_const_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(&pin const self) {} +LL + fn drop(&mut self) {} + | + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:104:9 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:95:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:99:21 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Foo`, found `Pin<&mut Foo>` + | + = note: expected signature `fn(&mut drop_with_lifetime_wrong_type::Foo)` + found signature `fn(Pin<&mut drop_with_lifetime_wrong_type::Foo>)` +help: change the self-receiver type to match the trait + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn drop<'a>(&mut self) {} | - = note: expected signature `fn(&mut drop_wrong_type::Bar)` - found signature `fn(Pin<&mut drop_wrong_type::Bar>)` + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:104:21 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Bar`, found `Pin<&mut Bar>` + | + = note: expected signature `fn(&mut drop_with_lifetime_wrong_type::Bar)` + found signature `fn(Pin<&mut drop_with_lifetime_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn drop<'a>(&mut self) {} + | + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:123:9 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:114:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop(self: Pin<&mut Self>) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:118:23 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Foo`, found `Pin<&mut Foo>` + | + = note: expected signature `fn(&mut drop_explicit_pin_wrong_type::Foo)` + found signature `fn(Pin<&mut drop_explicit_pin_wrong_type::Foo>)` help: change the self-receiver type to match the trait | -LL - fn drop(&pin mut self) {} +LL - fn drop(self: Pin<&mut Self>) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:123:23 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Bar`, found `Pin<&mut Bar>` + | + = note: expected signature `fn(&mut drop_explicit_pin_wrong_type::Bar)` + found signature `fn(Pin<&mut drop_explicit_pin_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(self: Pin<&mut Self>) {} LL + fn drop(&mut self) {} | error[E0053]: method `pin_drop` has an incompatible type for trait - --> $DIR/pinned-drop-check.rs:84:21 + --> $DIR/pinned-drop-check.rs:135:21 | LL | fn pin_drop(&mut self) {} | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Foo>`, found `&mut pin_drop_wrong_type::Foo` @@ -118,7 +243,7 @@ LL + fn pin_drop(self: Pin<&mut pin_drop_wrong_type::Foo>) {} | error[E0053]: method `pin_drop` has an incompatible type for trait - --> $DIR/pinned-drop-check.rs:88:21 + --> $DIR/pinned-drop-check.rs:139:21 | LL | fn pin_drop(&mut self) {} | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Bar>`, found `&mut pin_drop_wrong_type::Bar` @@ -132,14 +257,14 @@ LL + fn pin_drop(self: Pin<&mut pin_drop_wrong_type::Bar>) {} | error: `Bar` must implement `pin_drop` - --> $DIR/pinned-drop-check.rs:103:9 + --> $DIR/pinned-drop-check.rs:154:9 | LL | fn drop(&mut self) { | ^^^^^^^^^^^^^^^^^^ | = help: structurally pinned types must keep `Pin`'s safety contract note: `Bar` is marked `#[pin_v2]` here - --> $DIR/pinned-drop-check.rs:94:5 + --> $DIR/pinned-drop-check.rs:145:5 | LL | #[pin_v2] | ^^^^^^^^^ @@ -154,30 +279,42 @@ LL - #[pin_v2] | error[E0040]: explicit use of destructor method - --> $DIR/pinned-drop-check.rs:99:13 + --> $DIR/pinned-drop-check.rs:150:13 | LL | Drop::pin_drop(todo!()); | ^^^^^^^^^^^^^^ explicit destructor calls not allowed error[E0040]: explicit use of destructor method - --> $DIR/pinned-drop-check.rs:105:13 + --> $DIR/pinned-drop-check.rs:156:13 | LL | Drop::pin_drop(todo!()); | ^^^^^^^^^^^^^^ explicit destructor calls not allowed error[E0040]: explicit use of destructor method - --> $DIR/pinned-drop-check.rs:117:13 + --> $DIR/pinned-drop-check.rs:168:13 + | +LL | Drop::drop(todo!()); + | ^^^^^^^^^^ explicit destructor calls not allowed + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop-check.rs:173:13 | LL | Drop::drop(todo!()); | ^^^^^^^^^^ explicit destructor calls not allowed error[E0040]: explicit use of destructor method - --> $DIR/pinned-drop-check.rs:122:13 + --> $DIR/pinned-drop-check.rs:183:13 | LL | Drop::drop(todo!()); | ^^^^^^^^^^ explicit destructor calls not allowed -error: aborting due to 15 previous errors +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop-check.rs:184:13 + | +LL | Drop::pin_drop(todo!()); + | ^^^^^^^^^^^^^^ explicit destructor calls not allowed + +error: aborting due to 25 previous errors -Some errors have detailed explanations: E0040, E0046, E0053. +Some errors have detailed explanations: E0040, E0046, E0053, E0201. For more information about an error, try `rustc --explain E0040`. diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs new file mode 100644 index 0000000000000..d5687705defee --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs @@ -0,0 +1,78 @@ +//@ check-pass + +#![no_std] +#![no_core] +#![no_main] +#![feature(no_core, pin_ergonomics, lang_items)] +#![allow(incomplete_features)] + +#[lang = "pointee_sized"] +trait PointeeSized {} + +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} + +#[lang = "sized"] +trait Sized: MetaSized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "legacy_receiver"] +trait LegacyReceiver: PointeeSized {} + +#[lang = "deref"] +trait Deref: PointeeSized { + #[lang = "deref_target"] + type Target: PointeeSized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +trait DerefMut: Deref + PointeeSized { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +#[lang = "pin"] +struct Pin { + pointer: T, +} + +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Pin {} + +impl Deref for Pin { + type Target = Ptr::Target; + + fn deref(&self) -> &Self::Target { + &*self.pointer + } +} + +impl DerefMut for Pin { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.pointer + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &Self::Target { + self + } +} + +struct LocalDrop; + +impl Drop for LocalDrop { + fn drop(&pin mut self) {} +} + +#[lang = "drop"] +trait Drop { + fn drop(&mut self) {} + fn pin_drop(self: Pin<&mut Self>) {} +} diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs new file mode 100644 index 0000000000000..ace00348d1876 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs @@ -0,0 +1,62 @@ +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +use std::pin::Pin; + +struct S; + +trait NeedsPinDrop { + fn pin_drop(self: Pin<&mut Self>); +} + +impl NeedsPinDrop for S { + //~^ ERROR not all trait items implemented, missing: `pin_drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` with `&pin mut self` is only supported for the `Drop` trait +} + +trait HasDrop { + fn drop(self: Pin<&mut Self>); +} + +impl HasDrop for S { + //~^ ERROR not all trait items implemented, missing: `drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` is not a member of trait `HasDrop` [E0407] +} + +trait HasPinnedDropReceiver { + fn drop(self: &pin mut Self); +} + +impl HasPinnedDropReceiver for S { + //~^ ERROR not all trait items implemented, missing: `drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` is not a member of trait `HasPinnedDropReceiver` [E0407] +} + +struct Inherent; + +impl Inherent { + fn drop(&pin mut self) {} +} + +mod local_drop_trait { + use std::pin::Pin; + + struct S; + + trait Drop { + fn pin_drop(self: Pin<&mut Self>); + } + + impl Drop for S { + //~^ ERROR not all trait items implemented, missing: `pin_drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` with `&pin mut self` is only supported for the `Drop` trait + } +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr new file mode 100644 index 0000000000000..2238abea2484d --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr @@ -0,0 +1,70 @@ +error[E0407]: method `drop` is not a member of trait `HasDrop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:26:5 + | +LL | fn drop(&pin mut self) {} + | ^^^----^^^^^^^^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `drop` + | not a member of trait `HasDrop` + +error[E0407]: method `drop` is not a member of trait `HasPinnedDropReceiver` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:36:5 + | +LL | fn drop(&pin mut self) {} + | ^^^----^^^^^^^^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `drop` + | not a member of trait `HasPinnedDropReceiver` + +error: method `drop` with `&pin mut self` is only supported for the `Drop` trait + --> $DIR/pinned-drop-sugar-not-other-traits.rs:16:5 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a `Drop::pin_drop` implementation + +error: method `drop` with `&pin mut self` is only supported for the `Drop` trait + --> $DIR/pinned-drop-sugar-not-other-traits.rs:57:9 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a `Drop::pin_drop` implementation + +error[E0046]: not all trait items implemented, missing: `pin_drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:14:1 + | +LL | fn pin_drop(self: Pin<&mut Self>); + | ---------------------------------- `pin_drop` from trait +... +LL | impl NeedsPinDrop for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:24:1 + | +LL | fn drop(self: Pin<&mut Self>); + | ------------------------------ `drop` from trait +... +LL | impl HasDrop for S { + | ^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:34:1 + | +LL | fn drop(self: &pin mut Self); + | ----------------------------- `drop` from trait +... +LL | impl HasPinnedDropReceiver for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + +error[E0046]: not all trait items implemented, missing: `pin_drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:55:5 + | +LL | fn pin_drop(self: Pin<&mut Self>); + | ---------------------------------- `pin_drop` from trait +... +LL | impl Drop for S { + | ^^^^^^^^^^^^^^^ missing `pin_drop` in implementation + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0046, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar.rs new file mode 100644 index 0000000000000..11c940d2e2dff --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar.rs @@ -0,0 +1,31 @@ +//@ check-pass +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +struct Unpinned; + +#[pin_v2] +struct Pinned; + +struct Qualified; +struct CoreQualified; + +impl Drop for Unpinned { + fn drop(&pin mut self) {} +} + +impl Drop for Pinned { + fn drop(&pin mut self) {} +} + +impl std::ops::Drop for Qualified { + fn drop(&pin mut self) {} +} + +impl core::ops::Drop for CoreQualified { + fn drop(&pin mut self) {} +} + +fn main() {} diff --git a/tests/ui/suggestions/auxiliary/generics_other_crate.rs b/tests/ui/suggestions/auxiliary/generics_other_crate.rs new file mode 100644 index 0000000000000..2345257eddfb8 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/generics_other_crate.rs @@ -0,0 +1,4 @@ +//! This file is used to test suggestions for generics in other crates. + +pub struct External; +pub struct ExternalGeneric(T); diff --git a/tests/ui/suggestions/unconstrained-params.rs b/tests/ui/suggestions/unconstrained-params.rs new file mode 100644 index 0000000000000..4983ee6330c34 --- /dev/null +++ b/tests/ui/suggestions/unconstrained-params.rs @@ -0,0 +1,54 @@ +//@ aux-build:generics_other_crate.rs + +extern crate generics_other_crate; +use generics_other_crate::External; + +struct Local; +struct Defaulted(T); + +// Case 1: Unused parameter -> suggests removing T +impl Local {} +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates +//~| HELP: remove the unused type parameter `T` + +// Case 2: T used in body but not in self type +// -> suggests adding T to self type and struct definition +impl Local { + //~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + //~| HELP: use the type parameter `T` in the `Local` type and use it in the type definition + fn check() { + let _: T; + } +} + + +// Case 3: Struct has a generic parameter with a default +// -> suggests adding T to the self type +impl Defaulted {} +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates +//~| HELP: either remove the unused type parameter `T` +//~| HELP: or use it + +// Case 4: Generated from a macro +macro_rules! make_impl { + ($t:ident) => { + impl<$t> Local {} + //~^ HELP: remove the unused type parameter `U` + } +} +make_impl!(U); +//~^ ERROR the type parameter `U` is not constrained by the impl trait, self type, or predicates + +// Case 5: Type defined in another crate +impl External { + //~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + //~| ERROR: cannot define inherent `impl` for a type outside of the crate where the type is defined [E0116] + //~| HELP: use the type parameter `T` in the `External` type and use it in the type definition + //~| HELP: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + fn check() { + let _: T; + } +} + + +fn main() {} diff --git a/tests/ui/suggestions/unconstrained-params.stderr b/tests/ui/suggestions/unconstrained-params.stderr new file mode 100644 index 0000000000000..f6f899a93055e --- /dev/null +++ b/tests/ui/suggestions/unconstrained-params.stderr @@ -0,0 +1,68 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params.rs:10:6 + | +LL | impl Local {} + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params.rs:16:6 + | +LL | impl Local { + | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Local` type and use it in the type definition + | +LL ~ struct Local; +LL | struct Defaulted(T); +... +LL | // -> suggests adding T to self type and struct definition +LL ~ impl Local { + | + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params.rs:27:6 + | +LL | impl Defaulted {} + | ^ unconstrained type parameter + | +help: either remove the unused type parameter `T` + | +LL - impl Defaulted {} +LL + impl Defaulted {} + | +help: or use it + | +LL | impl Defaulted {} + | +++ + +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params.rs:39:12 + | +LL | impl<$t> Local {} + | ---- help: remove the unused type parameter `U` +... +LL | make_impl!(U); + | ^ unconstrained type parameter + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-params.rs:43:6 + | +LL | impl External { + | ^ unconstrained type parameter + +error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined + --> $DIR/unconstrained-params.rs:43:1 + | +LL | impl External { + | ^^^^^^^^^^^^^^^^ impl for type defined outside of crate + | + = help: consider defining a trait and implementing it for the type or using a newtype wrapper like `struct MyType(ExternalType);` and implement it + = note: for more details about the orphan rules, see + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0116, E0207. +For more information about an error, try `rustc --explain E0116`. diff --git a/tests/ui/traits/associated_type_bound/generic-const-args-default.rs b/tests/ui/traits/associated_type_bound/generic-const-args-default.rs index b56fe6ddab7a6..b53d0bb359c02 100644 --- a/tests/ui/traits/associated_type_bound/generic-const-args-default.rs +++ b/tests/ui/traits/associated_type_bound/generic-const-args-default.rs @@ -3,7 +3,7 @@ #![feature(min_generic_const_args)] -trait Bar {} +trait Bar {} trait Foo { type AssocB: Bar; diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr index 9e8194b46c04f..193e144d17cd6 100644 --- a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self --> $DIR/leaking-vars-in-cause-code-2.rs:19:9 | LL | impl Trait<()> for B - | ^ unconstrained type parameter + | --^ + | | | + | | unconstrained type parameter + | help: remove the unused type parameter `U` error[E0277]: the trait bound `(): IncompleteGuidance` is not satisfied --> $DIR/leaking-vars-in-cause-code-2.rs:29:19 diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr index 9ce0e8d957dab..e8742e7f09902 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.current.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Thing` type and use it in the type definition + | +LL ~ struct Thing; +LL | +... +LL | } +LL ~ impl Every for Thing { + | error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization-2.rs:16:18 diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr index 9ce0e8d957dab..e8742e7f09902 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization-2.next.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Thing` type and use it in the type definition + | +LL ~ struct Thing; +LL | +... +LL | } +LL ~ impl Every for Thing { + | error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization-2.rs:16:18 diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr index c52e8dd68aa87..6e908df0aba2d 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization.current.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Thing` type and use it in the type definition + | +LL ~ struct Thing; +LL | +... +LL | } +LL ~ impl Every for Thing { + | error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization.rs:15:18 diff --git a/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr b/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr index c52e8dd68aa87..6e908df0aba2d 100644 --- a/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr +++ b/tests/ui/traits/normalize/unconstrained-projection-normalization.next.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Thing` type and use it in the type definition + | +LL ~ struct Thing; +LL | +... +LL | } +LL ~ impl Every for Thing { + | error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization.rs:15:18 diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr index d18a824287c0c..4b050f362c9ca 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl>>, U> MyIndex> for Scope { | ^ unconstrained type parameter + | +help: use the type parameter `T` in the `Scope` type and use it in the type definition + | +LL ~ struct Scope(Phantom2>); +LL | +... +LL | +LL ~ impl>>, U> MyIndex> for Scope { + | error: item does not constrain `DummyT::{opaque#0}` --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:30:8 diff --git a/tests/ui/type-alias-impl-trait/issue-74244.stderr b/tests/ui/type-alias-impl-trait/issue-74244.stderr index f5ca56bacccf6..6e01425afec5e 100644 --- a/tests/ui/type-alias-impl-trait/issue-74244.stderr +++ b/tests/ui/type-alias-impl-trait/issue-74244.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/issue-74244.rs:9:6 | LL | impl Allocator for DefaultAllocator { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error