diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 68b536da9f7..846abce9d6a 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,8 +1,7 @@ //! Parsing and validation of builtin attributes use rustc_ast as ast; -use rustc_ast::node_id::CRATE_NODE_ID; -use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -436,7 +435,12 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { } /// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { +pub fn cfg_matches( + cfg: &ast::MetaItem, + sess: &ParseSess, + lint_node_id: NodeId, + features: Option<&Features>, +) -> bool { eval_condition(cfg, sess, features, &mut |cfg| { try_gate_cfg(cfg, sess, features); let error = |span, msg| { @@ -470,7 +474,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, - CRATE_NODE_ID, + lint_node_id, "unexpected `cfg` condition name", BuiltinLintDiagnostics::UnexpectedCfg(ident.span, name, None), ); @@ -482,7 +486,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat sess.buffer_lint_with_diagnostic( UNEXPECTED_CFGS, cfg.span, - CRATE_NODE_ID, + lint_node_id, "unexpected `cfg` condition value", BuiltinLintDiagnostics::UnexpectedCfg( cfg.name_value_literal_span().unwrap(), diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 4502d15f36f..684a3ced5a0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -5,16 +5,21 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; +use rustc_middle::ty::{ + self, suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind, Ty, +}; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::TraitEngineExt as _; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -423,7 +428,63 @@ pub(crate) fn report_use_of_moved_or_uninitialized( None, ); } + } else { + // Try to find predicates on *generic params* that would allow copying `ty` + + let tcx = self.infcx.tcx; + let generics = tcx.generics_of(self.mir_def_id()); + if let Some(hir_generics) = tcx + .typeck_root_def_id(self.mir_def_id().to_def_id()) + .as_local() + .and_then(|def_id| tcx.hir().get_generics(def_id)) + { + let predicates: Result, _> = tcx.infer_ctxt().enter(|infcx| { + let mut fulfill_cx = + >::new(infcx.tcx); + + let copy_did = infcx.tcx.lang_items().copy_trait().unwrap(); + let cause = ObligationCause::new( + span, + self.mir_hir_id(), + rustc_infer::traits::ObligationCauseCode::MiscObligation, + ); + fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause); + let errors = fulfill_cx.select_where_possible(&infcx); + + // Only emit suggestion if all required predicates are on generic + errors + .into_iter() + .map(|err| match err.obligation.predicate.kind().skip_binder() { + PredicateKind::Trait(predicate) => { + match predicate.self_ty().kind() { + ty::Param(param_ty) => Ok(( + generics.type_param(param_ty, tcx), + predicate + .trait_ref + .print_only_trait_path() + .to_string(), + )), + _ => Err(()), + } + } + _ => Err(()), + }) + .collect() + }); + + if let Ok(predicates) = predicates { + suggest_constraining_type_params( + tcx, + hir_generics, + &mut err, + predicates.iter().map(|(param, constraint)| { + (param.name.as_str(), &**constraint, None) + }), + ); + } + } } + let span = if let Some(local) = place.as_local() { let decl = &self.body.local_decls[local]; Some(decl.source_info.span) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 1e1cf917c60..f5ef4765df6 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -19,7 +19,12 @@ pub fn expand_cfg( match parse_cfg(cx, sp, tts) { Ok(cfg) => { - let matches_cfg = attr::cfg_matches(&cfg, &cx.sess.parse_sess, cx.ecfg.features); + let matches_cfg = attr::cfg_matches( + &cfg, + &cx.sess.parse_sess, + cx.current_expansion.lint_node_id, + cx.ecfg.features, + ); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } Err(mut err) => { diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 8574cfae860..3c8f8f1854b 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -5,6 +5,7 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::visit::Visitor; +use rustc_ast::NodeId; use rustc_ast::{mut_visit, visit}; use rustc_ast::{AstLike, Attribute}; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -26,15 +27,16 @@ ) -> Vec { check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); warn_on_duplicate_attribute(&ecx, &annotatable, sym::cfg_eval); - vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)] + vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable, ecx.current_expansion.lint_node_id)] } crate fn cfg_eval( sess: &Session, features: Option<&Features>, annotatable: Annotatable, + lint_node_id: NodeId, ) -> Annotatable { - CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } } + CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } } .configure_annotatable(annotatable) // Since the item itself has already been configured by the `InvocationCollector`, // we know that fold result vector will contain exactly one element. diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 47d7b6c259e..61681ec66a4 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -64,7 +64,12 @@ fn expand( match &mut resolutions[..] { [] => {} [(_, first_item, _), others @ ..] => { - *first_item = cfg_eval(sess, features, item.clone()); + *first_item = cfg_eval( + sess, + features, + item.clone(), + ecx.current_expansion.lint_node_id, + ); for (_, item, _) in others { *item = first_item.clone(); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4a8894983b9..6e9e0332faf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -576,12 +576,12 @@ pub enum PassKind { Module, } -/// LLVMRustThinLTOData +// LLVMRustThinLTOData extern "C" { pub type ThinLTOData; } -/// LLVMRustThinLTOBuffer +// LLVMRustThinLTOBuffer extern "C" { pub type ThinLTOBuffer; } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 9e252c0d9b7..9cc06ac0319 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,4 +1,5 @@ use rustc_arena::TypedArena; +use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -2434,7 +2435,7 @@ fn add_upstream_native_libraries( fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, None), + Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None), None => true, } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index c0d7bc359bf..d43c6fec7d5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -5,6 +5,7 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use rustc_ast::tokenstream::{DelimSpan, Spacing}; use rustc_ast::tokenstream::{LazyTokenStream, TokenTree}; +use rustc_ast::NodeId; use rustc_ast::{self as ast, AstLike, AttrStyle, Attribute, MetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; @@ -29,6 +30,7 @@ pub struct StripUnconfigured<'a> { /// This is only used for the input to derive macros, /// which needs eager expansion of `cfg` and `cfg_attr` pub config_tokens: bool, + pub lint_node_id: NodeId, } fn get_features( @@ -196,8 +198,13 @@ fn active_features_up_to(edition: Edition) -> impl Iterator (ast::Crate, Features) { - let mut strip_unconfigured = StripUnconfigured { sess, features: None, config_tokens: false }; +pub fn features( + sess: &Session, + mut krate: ast::Crate, + lint_node_id: NodeId, +) -> (ast::Crate, Features) { + let mut strip_unconfigured = + StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id }; let unconfigured_attrs = krate.attrs.clone(); let diag = &sess.parse_sess.span_diagnostic; @@ -353,7 +360,12 @@ fn process_cfg_attr(&self, attr: Attribute) -> Vec { ); } - if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) { + if !attr::cfg_matches( + &cfg_predicate, + &self.sess.parse_sess, + self.lint_node_id, + self.features, + ) { return vec![]; } @@ -445,7 +457,7 @@ fn in_cfg(&self, attrs: &[Attribute]) -> bool { } }; parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| { - attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features) + attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features) }) } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index ab3951d7683..1b976180509 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -551,11 +551,6 @@ fn collect_invocations( // attribute is expanded. Therefore, we don't need to configure the tokens // Derive macros *can* see the results of cfg-expansion - they are handled // specially in `fully_expand_fragment` - cfg: StripUnconfigured { - sess: &self.cx.sess, - features: self.cx.ecfg.features, - config_tokens: false, - }, cx: self.cx, invocations: Vec::new(), monotonic: self.monotonic, @@ -1538,12 +1533,20 @@ fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attri struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, - cfg: StripUnconfigured<'a>, invocations: Vec<(Invocation, Option>)>, monotonic: bool, } impl<'a, 'b> InvocationCollector<'a, 'b> { + fn cfg(&self) -> StripUnconfigured<'_> { + StripUnconfigured { + sess: &self.cx.sess, + features: self.cx.ecfg.features, + config_tokens: false, + lint_node_id: self.cx.current_expansion.lint_node_id, + } + } + fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { let expn_id = LocalExpnId::fresh_empty(); let vis = kind.placeholder_visibility(); @@ -1683,7 +1686,7 @@ fn expand_cfg_true( attr: ast::Attribute, pos: usize, ) -> bool { - let res = self.cfg.cfg_true(&attr); + let res = self.cfg().cfg_true(&attr); if res { // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion, // and some tools like rustdoc and clippy rely on that. Find a way to remove them @@ -1696,7 +1699,7 @@ fn expand_cfg_true( fn expand_cfg_attr(&self, node: &mut impl AstLike, attr: ast::Attribute, pos: usize) { node.visit_attrs(|attrs| { - attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr, false)); + attrs.splice(pos..pos, self.cfg().expand_cfg_attr(attr, false)); }); } @@ -1718,7 +1721,7 @@ fn flat_map_node>( continue; } _ => { - Node::pre_flat_map_node_collect_attr(&self.cfg, &attr); + Node::pre_flat_map_node_collect_attr(&self.cfg(), &attr); self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND) .make_ast::() } @@ -1882,7 +1885,7 @@ fn visit_pat(&mut self, node: &mut P) { fn visit_expr(&mut self, node: &mut P) { // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`. if let Some(attr) = node.attrs.first() { - self.cfg.maybe_emit_expr_attr_err(attr); + self.cfg().maybe_emit_expr_attr_err(attr); } self.visit_node(node) } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 2cdcf0b11d1..3b51f8eb61c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -2,6 +2,7 @@ use crate::proc_macro_decls; use crate::util; +use ast::CRATE_NODE_ID; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_borrowck as mir_borrowck; @@ -188,7 +189,7 @@ pub fn register_plugins<'a>( ) }); - let (krate, features) = rustc_expand::config::features(sess, krate); + let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID); // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 46b90baa585..72b8d8bb297 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1086,6 +1086,16 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) { warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs); } + + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { + warn_if_doc(cx, block.span, "block", &block.attrs()); + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { + if let ast::ItemKind::ForeignMod(_) = item.kind { + warn_if_doc(cx, item.span, "extern block", &item.attrs); + } + } } declare_lint! { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index dce1b35c6b8..7cdcb6a4ab3 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,3 +1,4 @@ +use rustc_ast::CRATE_NODE_ID; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; @@ -21,7 +22,7 @@ crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), + Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, CRATE_NODE_ID, None), None => true, } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 7ca564f29e6..f977b0fffeb 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -56,6 +56,7 @@ #![feature(nonzero_ops)] #![feature(unwrap_infallible)] #![feature(decl_macro)] +#![feature(drain_filter)] #![recursion_limit = "512"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 892808386de..13c325a14e4 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -7,6 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; +use rustc_index::vec::Idx; use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; @@ -380,7 +381,7 @@ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<' // instances into account. The others don't matter for // the codegen tests and can even make item order // unstable. - InstanceDef::Item(def) => Some(def.did.index.as_usize()), + InstanceDef::Item(def) => def.did.as_local().map(Idx::index), InstanceDef::VtableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) @@ -391,10 +392,8 @@ fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<' | InstanceDef::CloneShim(..) => None, } } - MonoItem::Static(def_id) => Some(def_id.index.as_usize()), - MonoItem::GlobalAsm(item_id) => { - Some(item_id.def_id.to_def_id().index.as_usize()) - } + MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), + MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.index()), }, item.symbol_name(tcx), ) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 58cf9fa7a89..99a3d4c7fe4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -7,6 +7,7 @@ ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, }; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -157,9 +158,17 @@ pub fn suggest_arbitrary_trait_bound( true } +#[derive(Debug)] +enum SuggestChangingConstraintsMessage<'a> { + RestrictBoundFurther, + RestrictType { ty: &'a str }, + RestrictTypeFurther { ty: &'a str }, + RemovingQSized, +} + fn suggest_removing_unsized_bound( generics: &hir::Generics<'_>, - err: &mut Diagnostic, + suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, param_name: &str, param: &hir::GenericParam<'_>, def_id: Option, @@ -221,13 +230,12 @@ fn suggest_removing_unsized_bound( // ^^^^^^^^^ (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), }; - err.span_suggestion_verbose( + + suggestions.push(( sp, - "consider removing the `?Sized` bound to make the \ - type parameter `Sized`", String::new(), - Applicability::MaybeIncorrect, - ); + SuggestChangingConstraintsMessage::RemovingQSized, + )); } } _ => {} @@ -249,13 +257,12 @@ fn suggest_removing_unsized_bound( // ^^^^^^^^^ (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()), }; - err.span_suggestion_verbose( + + suggestions.push(( sp, - "consider removing the `?Sized` bound to make the type parameter \ - `Sized`", String::new(), - Applicability::MaybeIncorrect, - ); + SuggestChangingConstraintsMessage::RemovingQSized, + )); } _ => {} } @@ -271,184 +278,249 @@ pub fn suggest_constraining_type_param( constraint: &str, def_id: Option, ) -> bool { - let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); + suggest_constraining_type_params( + tcx, + generics, + err, + [(param_name, constraint, def_id)].into_iter(), + ) +} - let Some(param) = param else { - return false; - }; +/// Suggest restricting a type param with a new bound. +pub fn suggest_constraining_type_params<'a>( + tcx: TyCtxt<'_>, + generics: &hir::Generics<'_>, + err: &mut Diagnostic, + param_names_and_constraints: impl Iterator)>, +) -> bool { + let mut grouped = FxHashMap::default(); + param_names_and_constraints.for_each(|(param_name, constraint, def_id)| { + grouped.entry(param_name).or_insert(Vec::new()).push((constraint, def_id)) + }); - const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound"; - let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name); - let msg_restrict_type_further = - format!("consider further restricting type parameter `{}`", param_name); + let mut applicability = Applicability::MachineApplicable; + let mut suggestions = Vec::new(); - if def_id == tcx.lang_items().sized_trait() { - // Type parameters are already `Sized` by default. - err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); - suggest_removing_unsized_bound(generics, err, param_name, param, def_id); - return true; - } - let mut suggest_restrict = |span| { - err.span_suggestion_verbose( - span, - MSG_RESTRICT_BOUND_FURTHER, - format!(" + {}", constraint), - Applicability::MachineApplicable, - ); - }; + for (param_name, mut constraints) in grouped { + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); + let Some(param) = param else { return false }; - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` + { + let mut sized_constraints = + constraints.drain_filter(|(_, def_id)| *def_id == tcx.lang_items().sized_trait()); + if let Some((constraint, def_id)) = sized_constraints.next() { + applicability = Applicability::MaybeIncorrect; - suggest_restrict(param.span.shrink_to_hi()); - return true; - } + err.span_label( + param.span, + &format!("this type parameter needs to be `{}`", constraint), + ); + suggest_removing_unsized_bound( + generics, + &mut suggestions, + param_name, + param, + def_id, + ); + } + } - if generics.where_clause.predicates.is_empty() - // Given `trait Base: Super` where `T: Copy`, suggest restricting in the - // `where` clause instead of `trait Base: Super`. - && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - { - if let Some(span) = param.bounds_span_for_suggestions() { - // If user has provided some bounds, suggest restricting them: + if constraints.is_empty() { + continue; + } + + let constraint = constraints.iter().map(|&(c, _)| c).collect::>().join(" + "); + let mut suggest_restrict = |span| { + suggestions.push(( + span, + format!(" + {}", constraint), + SuggestChangingConstraintsMessage::RestrictBoundFurther, + )) + }; + + if param_name.starts_with("impl ") { + // If there's an `impl Trait` used in argument position, suggest + // restricting it: // - // fn foo(t: T) { ... } - // --- + // fn foo(t: impl Foo) { ... } + // -------- // | // help: consider further restricting this bound with `+ Bar` // // Suggestion for tools in this case is: // - // fn foo(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - suggest_restrict(span); - } else { - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - err.span_suggestion_verbose( - param.span.shrink_to_hi(), - &msg_restrict_type, - format!(": {}", constraint), - Applicability::MachineApplicable, - ); + // fn foo(t: impl Foo) { ... } + // -------- + // | + // replace with: `impl Foo + Bar` + + suggest_restrict(param.span.shrink_to_hi()); + continue; } - true - } else { - // This part is a bit tricky, because using the `where` clause user can - // provide zero, one or many bounds for the same type parameter, so we - // have following cases to consider: - // - // 1) When the type parameter has been provided zero bounds - // - // Message: - // fn foo(x: X, y: Y) where Y: Foo { ... } - // - help: consider restricting this type parameter with `where X: Bar` - // - // Suggestion: - // fn foo(x: X, y: Y) where Y: Foo { ... } - // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - // - // Additionally, there may be no `where` clause whatsoever in the case that this was - // reached because the generic parameter has a default: - // - // Message: - // trait Foo {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // trait Foo where T: Zar {... } - // - insert: `where T: Zar` - - if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - && generics.where_clause.predicates.len() == 0 + if generics.where_clause.predicates.is_empty() + // Given `trait Base: Super` where `T: Copy`, suggest restricting in the + // `where` clause instead of `trait Base: Super`. + && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) { - // Suggest a bound, but there is no existing `where` clause *and* the type param has a - // default (``), so we suggest adding `where T: Bar`. - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(" where {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + if let Some(span) = param.bounds_span_for_suggestions() { + // If user has provided some bounds, suggest restricting them: + // + // fn foo(t: T) { ... } + // --- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo(t: T) { ... } + // -- + // | + // replace with: `T: Bar +` + suggest_restrict(span); + } else { + // If user hasn't provided any bounds, suggest adding a new one: + // + // fn foo(t: T) { ... } + // - help: consider restricting this type parameter with `T: Foo` + suggestions.push(( + param.span.shrink_to_hi(), + format!(": {}", constraint), + SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, + )); + } } else { - let mut param_spans = Vec::new(); + // This part is a bit tricky, because using the `where` clause user can + // provide zero, one or many bounds for the same type parameter, so we + // have following cases to consider: + // + // 1) When the type parameter has been provided zero bounds + // + // Message: + // fn foo(x: X, y: Y) where Y: Foo { ... } + // - help: consider restricting this type parameter with `where X: Bar` + // + // Suggestion: + // fn foo(x: X, y: Y) where Y: Foo { ... } + // - insert: `, X: Bar` + // + // + // 2) When the type parameter has been provided one bound + // + // Message: + // fn foo(t: T) where T: Foo { ... } + // ^^^^^^ + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion: + // fn foo(t: T) where T: Foo { ... } + // ^^ + // | + // replace with: `T: Bar +` + // + // + // 3) When the type parameter has been provided many bounds + // + // Message: + // fn foo(t: T) where T: Foo, T: Bar {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // fn foo(t: T) where T: Foo, T: Bar {... } + // - insert: `, T: Zar` + // + // Additionally, there may be no `where` clause whatsoever in the case that this was + // reached because the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo where T: Zar {... } + // - insert: `where T: Zar` - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, - bounded_ty, - .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + && generics.where_clause.predicates.len() == 0 + { + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. + suggestions.push(( + generics.where_clause.tail_span_for_suggestion(), + format!(" where {}: {}", param_name, constraint), + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, + )); + } else { + let mut param_spans = Vec::new(); + + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, + bounded_ty, + .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } } } } } - } - match param_spans[..] { - [¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + match param_spans[..] { + [¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + suggestions.push(( + generics.where_clause.tail_span_for_suggestion(), + constraints + .iter() + .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) + .collect::(), + SuggestChangingConstraintsMessage::RestrictTypeFurther { + ty: param_name, + }, + )); + } } } } - - true } + + if suggestions.len() == 1 { + let (span, suggestion, msg) = suggestions.pop().unwrap(); + + let s; + let msg = match msg { + SuggestChangingConstraintsMessage::RestrictBoundFurther => { + "consider further restricting this bound" + } + SuggestChangingConstraintsMessage::RestrictType { ty } => { + s = format!("consider restricting type parameter `{}`", ty); + &s + } + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty } => { + s = format!("consider further restricting type parameter `{}`", ty); + &s + } + SuggestChangingConstraintsMessage::RemovingQSized => { + "consider removing the `?Sized` bound to make the type parameter `Sized`" + } + }; + + err.span_suggestion_verbose(span, msg, suggestion, applicability); + } else { + err.multipart_suggestion_verbose( + "consider restricting type parameters", + suggestions.into_iter().map(|(span, suggestion, _)| (span, suggestion)).collect(), + applicability, + ); + } + + true } /// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 040a087b235..f01843ebaba 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -276,11 +276,28 @@ fn suggest_compatible_variants( // we suggest adding a separate return expression instead. // (To avoid things like suggesting `Ok(while .. { .. })`.) if expr_ty.is_unit() { + let mut id = expr.hir_id; + let mut parent; + + // Unroll desugaring, to make sure this works for `for` loops etc. + loop { + parent = self.tcx.hir().get_parent_node(id); + if let Some(parent_span) = self.tcx.hir().opt_span(parent) { + if parent_span.find_ancestor_inside(expr.span).is_some() { + // The parent node is part of the same span, so is the result of the + // same expansion/desugaring and not the 'real' parent node. + id = parent; + continue; + } + } + break; + } + if let Some(hir::Node::Block(&hir::Block { span: block_span, expr: Some(e), .. - })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id)) + })) = self.tcx.hir().find(parent) { - if e.hir_id == expr.hir_id { + if e.hir_id == id { if let Some(span) = expr.span.find_ancestor_inside(block_span) { let return_suggestions = if self.tcx.is_diagnostic_item(sym::Result, expected_adt.did) { diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index e5255686ff9..2b611e5aae2 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -117,7 +117,7 @@ mod c_char_definition { all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), all( - target_os = "freebsd", + any(target_os = "freebsd", target_os = "openbsd"), any( target_arch = "aarch64", target_arch = "arm", @@ -130,7 +130,6 @@ mod c_char_definition { target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") ), - all(target_os = "openbsd", target_arch = "aarch64"), all( target_os = "vxworks", any( diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs index 4c68d11e893..cf2c0a02351 100644 --- a/library/portable-simd/crates/core_simd/src/intrinsics.rs +++ b/library/portable-simd/crates/core_simd/src/intrinsics.rs @@ -18,9 +18,10 @@ //! //! Unless stated otherwise, all intrinsics for binary operations require SIMD vectors of equal types and lengths. -/// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are -/// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner. -/// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function. + +// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are +// mostly lowered to the matching LLVM instructions by the compiler in a fairly straightforward manner. +// The associated LLVM instruction or intrinsic is documented alongside each Rust intrinsic function. extern "platform-intrinsic" { /// add/fadd pub(crate) fn simd_add(x: T, y: T) -> T; diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index df11dc21aa7..13bb079194f 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -11,3 +11,6 @@ // Implementations for `AsRawFd` etc. for network types. mod net; + +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index d72f9a2ff9c..807b057234a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -21,6 +21,10 @@ /// descriptor, so it can be used in FFI in places where a file descriptor is /// passed as an argument, it is not captured or consumed, and it never has the /// value `-1`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedFd` +/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file +/// descriptor, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -62,7 +66,7 @@ impl BorrowedFd<'_> { /// the returned `BorrowedFd`, and it must not have the value `-1`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + pub unsafe fn borrow_raw(fd: RawFd) -> Self { assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { Self { fd, _phantom: PhantomData } } @@ -231,7 +235,7 @@ fn as_fd(&self) -> BorrowedFd<'_> { // Safety: `OwnedFd` and `BorrowedFd` have the same validity // invariants, and the `BorrowdFd` is bounded by the lifetime // of `&self`. - unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } } } diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs new file mode 100644 index 00000000000..26ef93e3d71 --- /dev/null +++ b/library/std/src/os/fd/tests.rs @@ -0,0 +1,34 @@ +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_raw_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + + let raw_fd: RawFd = crate::io::stdin().as_raw_fd(); + + let stdin_as_file = unsafe { crate::fs::File::from_raw_fd(raw_fd) }; + assert_eq!(stdin_as_file.as_raw_fd(), raw_fd); + assert_eq!(unsafe { BorrowedFd::borrow_raw(raw_fd).as_raw_fd() }, raw_fd); + assert_eq!(stdin_as_file.into_raw_fd(), 0); +} + +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + + let stdin = crate::io::stdin(); + let fd: BorrowedFd<'_> = stdin.as_fd(); + let raw_fd: RawFd = fd.as_raw_fd(); + let owned_fd: OwnedFd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; + + let stdin_as_file = crate::fs::File::from(owned_fd); + + assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd); + assert_eq!(Into::::into(stdin_as_file).into_raw_fd(), raw_fd); +} diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 8df6c54a414..842a15ae1bf 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -28,6 +28,10 @@ /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// +/// This type's `.to_owned()` implementation returns another `BorrowedHandle` +/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw +/// handle, which is then borrowed under the same lifetime. +/// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[derive(Copy, Clone)] #[repr(transparent)] @@ -131,7 +135,7 @@ impl BorrowedHandle<'_> { /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn borrow_raw(handle: RawHandle) -> Self { Self { handle, _phantom: PhantomData } } } @@ -345,7 +349,7 @@ fn as_handle(&self) -> BorrowedHandle<'_> { // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity // invariants, and the `BorrowdHandle` is bounded by the lifetime // of `&self`. - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -373,49 +377,49 @@ fn from(owned: OwnedHandle) -> Self { impl AsHandle for crate::io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::process::ChildStdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -429,7 +433,7 @@ fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle { impl AsHandle for crate::process::ChildStdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -443,7 +447,7 @@ fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle { impl AsHandle for crate::process::ChildStderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -457,7 +461,7 @@ fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle { impl AsHandle for crate::thread::JoinHandle { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 2f13eb77a1b..a695a4106e8 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -21,6 +21,10 @@ /// so it can be used in FFI in places where a socket is passed as an argument, /// it is not captured or consumed, and it never has the value /// `INVALID_SOCKET`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedSocket` +/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw +/// socket, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -67,7 +71,7 @@ impl BorrowedSocket<'_> { /// `INVALID_SOCKET`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self { + pub unsafe fn borrow_raw(socket: RawSocket) -> Self { debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); Self { socket, _phantom: PhantomData } } @@ -239,14 +243,14 @@ fn as_socket(&self) -> BorrowedSocket<'_> { // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity // invariants, and the `BorrowdSocket` is bounded by the lifetime // of `&self`. - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } impl AsSocket for crate::net::TcpStream { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -267,7 +271,7 @@ fn from(owned: OwnedSocket) -> Self { impl AsSocket for crate::net::TcpListener { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -288,7 +292,7 @@ fn from(owned: OwnedSocket) -> Self { impl AsSocket for crate::net::UdpSocket { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b359987595d..e4d83ba0ffd 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -96,7 +96,7 @@ pub fn panic_output() -> Option { impl AsFd for io::Stdin { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -104,7 +104,7 @@ fn as_fd(&self) -> BorrowedFd<'_> { impl<'a> AsFd for io::StdinLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -112,7 +112,7 @@ fn as_fd(&self) -> BorrowedFd<'_> { impl AsFd for io::Stdout { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -120,7 +120,7 @@ fn as_fd(&self) -> BorrowedFd<'_> { impl<'a> AsFd for io::StdoutLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -128,7 +128,7 @@ fn as_fd(&self) -> BorrowedFd<'_> { impl AsFd for io::Stderr { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } @@ -136,6 +136,6 @@ fn as_fd(&self) -> BorrowedFd<'_> { impl<'a> AsFd for io::StderrLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } diff --git a/library/stdarch b/library/stdarch index b4a0e07552c..bcbe010614f 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit b4a0e07552cf90ef8f1a5b775bf70e4db94b3d63 +Subproject commit bcbe010614f398ec86f3a9274d22e33e5f2ee60b diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d7e0b9d50f0..4c05818440b 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -139,7 +139,7 @@ target | std | notes `armv7r-none-eabi` | * | Bare ARMv7-R `armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat `asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten -`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE +`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE `i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23) `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL `i686-linux-android` | ✓ | 32-bit x86 Android @@ -236,7 +236,7 @@ target | std | host | notes `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) -`i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support +`i686-pc-windows-msvc` | * | | 32-bit Windows XP support `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD @@ -283,7 +283,7 @@ target | std | host | notes [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS -`x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support +`x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support `x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku diff --git a/src/test/codegen/debuginfo-generic-closure-env-names.rs b/src/test/codegen/debuginfo-generic-closure-env-names.rs index ad59f740b56..b29f8b4a029 100644 --- a/src/test/codegen/debuginfo-generic-closure-env-names.rs +++ b/src/test/codegen/debuginfo-generic-closure-env-names.rs @@ -3,7 +3,7 @@ // of the enclosing functions don't get lost. // // Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard -// to predict once async fns are involved. +// to predict once async fns are involved, so DAG allows any order. // // Note that the test does not check async-fns when targeting MSVC because debuginfo for // those does not follow the enum-fallback encoding yet and thus is incomplete. @@ -27,24 +27,24 @@ // CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" // function_containing_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] // generic_async_function() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] // generic_async_function() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] // generic_async_block() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] // generic_async_block() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] // function_containing_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] +// NONMSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] #![crate_type = "lib"] diff --git a/src/test/ui/async-await/proper-span-for-type-error.fixed b/src/test/ui/async-await/proper-span-for-type-error.fixed index 1f1e1184dcc..7d43b575d2f 100644 --- a/src/test/ui/async-await/proper-span-for-type-error.fixed +++ b/src/test/ui/async-await/proper-span-for-type-error.fixed @@ -5,7 +5,8 @@ async fn a() {} async fn foo() -> Result<(), i32> { - Ok(a().await) //~ ERROR mismatched types + a().await; + Ok(()) //~ ERROR mismatched types } fn main() {} diff --git a/src/test/ui/async-await/proper-span-for-type-error.stderr b/src/test/ui/async-await/proper-span-for-type-error.stderr index 611dc0407bf..25f05156ce2 100644 --- a/src/test/ui/async-await/proper-span-for-type-error.stderr +++ b/src/test/ui/async-await/proper-span-for-type-error.stderr @@ -6,10 +6,11 @@ LL | a().await | = note: expected enum `Result<(), i32>` found unit type `()` -help: try wrapping the expression in `Ok` +help: try adding an expression at the end of the block + | +LL ~ a().await; +LL ~ Ok(()) | -LL | Ok(a().await) - | +++ + error: aborting due to previous error diff --git a/src/test/ui/check-cfg/allow-macro-cfg.rs b/src/test/ui/check-cfg/allow-macro-cfg.rs new file mode 100644 index 00000000000..8016a4d190c --- /dev/null +++ b/src/test/ui/check-cfg/allow-macro-cfg.rs @@ -0,0 +1,14 @@ +// This test check that local #[allow(unexpected_cfgs)] works +// +// check-pass +// compile-flags:--check-cfg=names() -Z unstable-options + +#[allow(unexpected_cfgs)] +fn foo() { + if cfg!(FALSE) {} +} + +fn main() { + #[allow(unexpected_cfgs)] + if cfg!(FALSE) {} +} diff --git a/src/test/ui/check-cfg/allow-same-level.rs b/src/test/ui/check-cfg/allow-same-level.rs new file mode 100644 index 00000000000..6c869dc4202 --- /dev/null +++ b/src/test/ui/check-cfg/allow-same-level.rs @@ -0,0 +1,11 @@ +// This test check that #[allow(unexpected_cfgs)] doesn't work if put on the same level +// +// check-pass +// compile-flags:--check-cfg=names() -Z unstable-options + +#[allow(unexpected_cfgs)] +#[cfg(FALSE)] +//~^ WARNING unexpected `cfg` condition name +fn bar() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/allow-same-level.stderr b/src/test/ui/check-cfg/allow-same-level.stderr new file mode 100644 index 00000000000..7797de584b9 --- /dev/null +++ b/src/test/ui/check-cfg/allow-same-level.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name + --> $DIR/allow-same-level.rs:7:7 + | +LL | #[cfg(FALSE)] + | ^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/check-cfg/allow-top-level.rs b/src/test/ui/check-cfg/allow-top-level.rs new file mode 100644 index 00000000000..d14b0eae5cc --- /dev/null +++ b/src/test/ui/check-cfg/allow-top-level.rs @@ -0,0 +1,15 @@ +// This test check that a top-level #![allow(unexpected_cfgs)] works +// +// check-pass +// compile-flags:--check-cfg=names() -Z unstable-options + +#![allow(unexpected_cfgs)] + +#[cfg(FALSE)] +fn bar() {} + +fn foo() { + if cfg!(FALSE) {} +} + +fn main() {} diff --git a/src/test/ui/check-cfg/allow-upper-level.rs b/src/test/ui/check-cfg/allow-upper-level.rs new file mode 100644 index 00000000000..04340694d9c --- /dev/null +++ b/src/test/ui/check-cfg/allow-upper-level.rs @@ -0,0 +1,12 @@ +// This test check that #[allow(unexpected_cfgs)] work if put on an upper level +// +// check-pass +// compile-flags:--check-cfg=names() -Z unstable-options + +#[allow(unexpected_cfgs)] +mod aa { + #[cfg(FALSE)] + fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/compatible-variants.rs b/src/test/ui/did_you_mean/compatible-variants.rs index a70dda8386f..b078064b267 100644 --- a/src/test/ui/did_you_mean/compatible-variants.rs +++ b/src/test/ui/did_you_mean/compatible-variants.rs @@ -23,6 +23,21 @@ fn b() -> Result<(), ()> { //~| HELP try adding an expression } +fn c() -> Option<()> { + for _ in [1, 2] { + //~^ ERROR mismatched types + f(); + } + //~^ HELP try adding an expression +} + +fn d() -> Option<()> { + c()? + //~^ ERROR incompatible types + //~| HELP try removing this `?` + //~| HELP try adding an expression +} + fn main() { let _: Option<()> = while false {}; //~^ ERROR mismatched types diff --git a/src/test/ui/did_you_mean/compatible-variants.stderr b/src/test/ui/did_you_mean/compatible-variants.stderr index 0dfd8f5c128..51c1bf97c4e 100644 --- a/src/test/ui/did_you_mean/compatible-variants.stderr +++ b/src/test/ui/did_you_mean/compatible-variants.stderr @@ -37,7 +37,52 @@ LL + Ok(()) | error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:27:25 + --> $DIR/compatible-variants.rs:27:5 + | +LL | fn c() -> Option<()> { + | ---------- expected `Option<()>` because of return type +LL | / for _ in [1, 2] { +LL | | +LL | | f(); +LL | | } + | |_____^ expected enum `Option`, found `()` + | + = note: expected enum `Option<()>` + found unit type `()` +help: try adding an expression at the end of the block + | +LL ~ } +LL + None + | +LL ~ } +LL + Some(()) + | + +error[E0308]: `?` operator has incompatible types + --> $DIR/compatible-variants.rs:35:5 + | +LL | c()? + | ^^^^ expected enum `Option`, found `()` + | + = note: `?` operator cannot convert from `()` to `Option<()>` + = note: expected enum `Option<()>` + found unit type `()` +help: try removing this `?` + | +LL - c()? +LL + c() + | +help: try adding an expression at the end of the block + | +LL ~ c()?; +LL + None + | +LL ~ c()?; +LL + Some(()) + | + +error[E0308]: mismatched types + --> $DIR/compatible-variants.rs:42:25 | LL | let _: Option<()> = while false {}; | ---------- ^^^^^^^^^^^^^^ expected enum `Option`, found `()` @@ -52,7 +97,7 @@ LL | let _: Option<()> = Some(while false {}); | +++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:31:9 + --> $DIR/compatible-variants.rs:46:9 | LL | while false {} | ^^^^^^^^^^^^^^ expected enum `Option`, found `()` @@ -69,7 +114,7 @@ LL + Some(()) | error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:35:31 + --> $DIR/compatible-variants.rs:50:31 | LL | let _: Result = 1; | ---------------- ^ expected enum `Result`, found integer @@ -86,7 +131,7 @@ LL | let _: Result = Err(1); | ++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:38:26 + --> $DIR/compatible-variants.rs:53:26 | LL | let _: Option = 1; | ----------- ^ expected enum `Option`, found integer @@ -101,7 +146,7 @@ LL | let _: Option = Some(1); | +++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:41:28 + --> $DIR/compatible-variants.rs:56:28 | LL | let _: Hey = 1; | ------------- ^ expected enum `Hey`, found integer @@ -118,7 +163,7 @@ LL | let _: Hey = Hey::B(1); | +++++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:44:29 + --> $DIR/compatible-variants.rs:59:29 | LL | let _: Hey = false; | -------------- ^^^^^ expected enum `Hey`, found `bool` @@ -133,7 +178,7 @@ LL | let _: Hey = Hey::B(false); | +++++++ + error[E0308]: mismatched types - --> $DIR/compatible-variants.rs:48:19 + --> $DIR/compatible-variants.rs:63:19 | LL | let _ = Foo { bar }; | ^^^ expected enum `Option`, found `i32` @@ -145,6 +190,6 @@ help: try wrapping the expression in `Some` LL | let _ = Foo { bar: Some(bar) }; | ++++++++++ + -error: aborting due to 9 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs index 258f9e4831f..54d86c31fb4 100644 --- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs +++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.rs @@ -29,4 +29,18 @@ fn doc_comment_on_expr(num: u8) -> bool { fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {} //~^ ERROR: unused doc comment +fn doc_comment_on_block() { + /// unused doc comment + //~^ ERROR: unused doc comment + { + let x = 12; + } +} + +/// unused doc comment +//~^ ERROR: unused doc comment +extern "C" { + fn foo(); +} + fn main() {} diff --git a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 3ce1df71a2e..30a96af583a 100644 --- a/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/src/test/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -49,6 +49,32 @@ LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {} | = help: use `//` for a plain comment +error: unused doc comment + --> $DIR/unused-doc-comments-edge-cases.rs:33:5 + | +LL | /// unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / { +LL | | let x = 12; +LL | | } + | |_____- rustdoc does not generate documentation for expressions + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/unused-doc-comments-edge-cases.rs:40:1 + | +LL | /// unused doc comment + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / extern "C" { +LL | | fn foo(); +LL | | } + | |_- rustdoc does not generate documentation for extern block + | + = help: use `//` for a plain comment + error[E0308]: mismatched types --> $DIR/unused-doc-comments-edge-cases.rs:14:9 | @@ -63,7 +89,7 @@ help: you might have meant to return this value LL | return true; | ++++++ + -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs b/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs new file mode 100644 index 00000000000..d5c8d4e6bdf --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs @@ -0,0 +1,6 @@ +// `Rc` is not ever `Copy`, we should not suggest adding `T: Copy` constraint +fn duplicate_rc(t: std::rc::Rc) -> (std::rc::Rc, std::rc::Rc) { + (t, t) //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr new file mode 100644 index 00000000000..c25981e6f80 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_clone_suggestions.rs:3:9 + | +LL | fn duplicate_rc(t: std::rc::Rc) -> (std::rc::Rc, std::rc::Rc) { + | - move occurs because `t` has type `Rc`, which does not implement the `Copy` trait +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed new file mode 100644 index 00000000000..d31046c7700 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -0,0 +1,72 @@ +// run-rustfix +#![allow(dead_code)] + +fn duplicate_t(t: T) -> (T, T) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_opt(t: Option) -> (Option, Option) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { + //~^ HELP consider restricting type parameters + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom(t: S) -> (S, S) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +struct S(T); +trait Trait {} +impl Clone for S { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl Copy for S {} + +trait A {} +trait B {} + +// Test where bounds are added with different bound placements +fn duplicate_custom_1(t: S) -> (S, S) where { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_2(t: S) -> (S, S) +where + T: A + Trait + Copy, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_3(t: S) -> (S, S) +where + T: A, + T: B, T: Trait, T: Copy + //~^ HELP consider further restricting type parameter `T` +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_4(t: S) -> (S, S) +where + T: B + Trait + Copy, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs new file mode 100644 index 00000000000..7cc5189fac0 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -0,0 +1,72 @@ +// run-rustfix +#![allow(dead_code)] + +fn duplicate_t(t: T) -> (T, T) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_opt(t: Option) -> (Option, Option) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { + //~^ HELP consider restricting type parameters + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom(t: S) -> (S, S) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +struct S(T); +trait Trait {} +impl Clone for S { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl Copy for S {} + +trait A {} +trait B {} + +// Test where bounds are added with different bound placements +fn duplicate_custom_1(t: S) -> (S, S) where { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_2(t: S) -> (S, S) +where + T: A, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_3(t: S) -> (S, S) +where + T: A, + T: B, + //~^ HELP consider further restricting type parameter `T` +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_4(t: S) -> (S, S) +where + T: B, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr new file mode 100644 index 00000000000..8e72697ca30 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -0,0 +1,147 @@ +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9 + | +LL | fn duplicate_t(t: T) -> (T, T) { + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_t(t: T) -> (T, T) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9 + | +LL | fn duplicate_opt(t: Option) -> (Option, Option) { + | - move occurs because `t` has type `Option`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_opt(t: Option) -> (Option, Option) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9 + | +LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { + | - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_tup1(t: (T,)) -> ((T,), (T,)) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9 + | +LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { + | - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameters + | +LL | fn duplicate_tup2(t: (A, B)) -> ((A, B), (A, B)) { + | ++++++ ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9 + | +LL | fn duplicate_custom(t: S) -> (S, S) { + | - move occurs because `t` has type `S`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_custom(t: S) -> (S, S) { + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9 + | +LL | fn duplicate_custom_1(t: S) -> (S, S) where { + | - move occurs because `t` has type `S`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_custom_1(t: S) -> (S, S) where { + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9 + | +LL | fn duplicate_custom_2(t: S) -> (S, S) + | - move occurs because `t` has type `S`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting this bound + | +LL | T: A + Trait + Copy, + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9 + | +LL | fn duplicate_custom_3(t: S) -> (S, S) + | - move occurs because `t` has type `S`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting type parameter `T` + | +LL | T: B, T: Trait, T: Copy + | ~~~~~~~~~~~~~~~~~~~ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9 + | +LL | fn duplicate_custom_4(t: S) -> (S, S) + | - move occurs because `t` has type `S`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting this bound + | +LL | T: B + Trait + Copy, + | ++++++++++++++ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0382`.