diff --git a/Cargo.lock b/Cargo.lock index 3862f0b42cd0e..fdfbb372b14c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4010,9 +4010,7 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ - "rustc_ast", "rustc_data_structures", - "rustc_hir", "rustc_span", "serde", "serde_json", diff --git a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs index 1ca433a4d6d7b..890cb33d08720 100644 --- a/compiler/rustc_attr_parsing/src/attributes/autodiff.rs +++ b/compiler/rustc_attr_parsing/src/attributes/autodiff.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use rustc_ast::LitKind; use rustc_ast::expand::autodiff_attrs::{DiffActivity, DiffMode}; -use rustc_feature::{AttributeStability, AttributeTemplate, template}; +use rustc_feature::AttributeStability; use rustc_hir::attrs::{AttributeKind, RustcAutodiff}; use rustc_hir::{MethodKind, Target}; use rustc_span::{Symbol, sym}; @@ -13,7 +13,7 @@ use crate::attributes::prelude::Allow; use crate::context::AcceptContext; use crate::parser::{ArgParser, MetaItemOrLitParser}; use crate::target_checking::AllowedTargets; -use crate::unstable; +use crate::{AttributeTemplate, template, unstable}; pub(crate) struct RustcAutodiffParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index edbb4b2c2ead9..3a2f0ea74ba25 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -4,9 +4,7 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{AttrItem, Attribute, LitKind, ast, token}; use rustc_errors::{Applicability, Diagnostic, PResult, msg}; -use rustc_feature::{ - AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template, -}; +use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::attrs::CfgEntry; use rustc_hir::{AttrPath, RustcVersion, Target}; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; @@ -28,7 +26,10 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{AttributeParser, check_cfg, parse_version, session_diagnostics}; +use crate::{ + AttrSuggestionStyle, AttributeParser, AttributeTemplate, check_cfg, parse_version, + session_diagnostics, template, +}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs index d72aac488f8e9..934dfb54f6deb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -3,7 +3,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrStyle, NodeId, token}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diagnostic, MultiSpan}; -use rustc_feature::{AttributeTemplate, Features}; +use rustc_feature::Features; use rustc_hir::attrs::CfgEntry; use rustc_hir::{AttrPath, Target}; use rustc_parse::exp; @@ -14,7 +14,9 @@ use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::AttributeSafety; use crate::parser::{AllowExprMetavar, MetaItemOrLitParser}; -use crate::{AttributeParser, ParsedDescription, ShouldEmit, diagnostics, parse_cfg_entry}; +use crate::{ + AttributeParser, AttributeTemplate, ParsedDescription, ShouldEmit, diagnostics, parse_cfg_entry, +}; #[derive(Clone)] pub enum CfgSelectPredicate { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index 3b36889d38f09..5b61e83b5e6bd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -1,4 +1,4 @@ -use rustc_feature::{AttributeStability, AttributeTemplate, template}; +use rustc_feature::AttributeStability; use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_session::lint::builtin::{ @@ -11,6 +11,7 @@ use crate::context::AcceptContext; use crate::diagnostics::IncorrectDoNotRecommendLocation; use crate::parser::ArgParser; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; +use crate::{AttributeTemplate, template}; pub(crate) struct DoNotRecommendParser; impl SingleAttributeParser for DoNotRecommendParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index 45d2d454582ad..38d2e7f8f53e6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -1,4 +1,4 @@ -use rustc_feature::{AttributeStability, template}; +use rustc_feature::AttributeStability; use rustc_hir::attrs::AttributeKind; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::sym; @@ -9,6 +9,7 @@ use crate::context::AcceptContext; use crate::diagnostics::DiagnosticOnMoveOnlyForAdt; use crate::parser::ArgParser; use crate::target_checking::{ALL_TARGETS, AllowedTargets}; +use crate::template; #[derive(Default)] pub(crate) struct OnMoveParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 7df11cd7108ef..382f0539f7678 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,6 +1,6 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; use rustc_errors::{Applicability, msg}; -use rustc_feature::{AttributeStability, template}; +use rustc_feature::AttributeStability; use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, @@ -10,7 +10,7 @@ use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; use super::prelude::{ALL_TARGETS, AllowedTargets}; -use super::{AcceptMapping, AttributeParser}; +use super::{AcceptMapping, AttributeParser, template}; use crate::context::{AcceptContext, FinalizeContext}; use crate::diagnostics::{ AttrCrateLevelOnly, DocAliasDuplicated, DocAutoCfgExpectsHideOrShow, diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 9e2c642d1bbb6..d436c7f232ec7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -1,4 +1,4 @@ -use rustc_feature::{AttributeStability, AttributeTemplate, template}; +use rustc_feature::AttributeStability; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; @@ -6,7 +6,7 @@ use crate::attributes::{OnDuplicate, SingleAttributeParser}; use crate::context::AcceptContext; use crate::parser::ArgParser; use crate::target_checking::AllowedTargets; -use crate::unstable; +use crate::{AttributeTemplate, template, unstable}; pub(crate) struct RustcDummyParser; impl SingleAttributeParser for RustcDummyParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 73662bb4a28b2..325db4f0250b6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -20,7 +20,7 @@ use std::marker::PhantomData; -use rustc_feature::{AttributeStability, AttributeTemplate, template}; +use rustc_feature::AttributeStability; use rustc_hir::attrs::AttributeKind; use rustc_span::edition::Edition; use rustc_span::{Span, Symbol}; @@ -30,6 +30,7 @@ use crate::context::{AcceptContext, FinalizeContext}; use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; use crate::target_checking::AllowedTargets; +use crate::{AttributeTemplate, template}; /// All the parsers require roughly the same imports, so this prelude has most of the often-needed ones. mod prelude; diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 15d548501cb65..4dd8f715f4387 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -1,7 +1,5 @@ // data structures #[doc(hidden)] -pub(super) use rustc_feature::{AttributeTemplate, template}; -#[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; #[doc(hidden)] pub(super) use rustc_hir::{MethodKind, Target}; @@ -27,3 +25,4 @@ pub(super) use crate::target_checking::Policy::{Allow, Error, Warn}; pub(super) use crate::target_checking::{ALL_TARGETS, AllowedTargets}; #[doc(hidden)] pub(super) use crate::unstable; +pub(super) use crate::{AttributeTemplate, template}; diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index 40d6a80a398fc..ddc40e62a7e8e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -1,6 +1,6 @@ //! Attributes that are only used on function prototypes. -use rustc_feature::{AttributeStability, AttributeTemplate, template}; +use rustc_feature::AttributeStability; use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase}; use rustc_span::{Span, Symbol, sym}; @@ -10,7 +10,7 @@ use crate::context::AcceptContext; use crate::parser::{ArgParser, NameValueParser}; use crate::target_checking::AllowedTargets; use crate::target_checking::Policy::Allow; -use crate::{session_diagnostics, unstable}; +use crate::{AttributeTemplate, session_diagnostics, template, unstable}; pub(crate) struct CustomMirParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d9fa8071a927d..8da5058da7ac8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_ast::{AttrStyle, MetaItemLit, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; -use rustc_feature::{AttrSuggestionStyle, AttributeStability, AttributeTemplate}; +use rustc_feature::AttributeStability; use rustc_hir::AttrPath; use rustc_hir::attrs::AttributeKind; use rustc_parse::parser::Recovery; @@ -71,7 +71,7 @@ use crate::session_diagnostics::{ ParsedDescription, }; use crate::target_checking::AllowedTargets; -use crate::{AttributeParser, EmitAttribute}; +use crate::{AttrSuggestionStyle, AttributeParser, AttributeTemplate, EmitAttribute}; type GroupType = LazyLock; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 27960e96bc111..e8bef70be550a 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -8,7 +8,7 @@ use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; -use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, Features}; +use rustc_feature::{BUILTIN_ATTRIBUTE_MAP, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; use rustc_lint_defs::RegisteredTools; @@ -23,7 +23,7 @@ use crate::context::{ use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; -use crate::{OmitDoc, ShouldEmit}; +use crate::{AttributeTemplate, OmitDoc, ShouldEmit}; pub struct EmitAttribute( pub Box< diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 8251ffc7c2ad0..3d6148f69537c 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -105,6 +105,7 @@ mod safety; mod session_diagnostics; mod stability; mod target_checking; +mod template; pub mod validate_attr; pub use attributes::AttributeSafety; @@ -117,3 +118,4 @@ pub use context::{OmitDoc, ShouldEmit}; pub use interface::{AttributeParser, EmitAttribute}; pub use rustc_parse::parser::Recovery; pub use session_diagnostics::ParsedDescription; +pub use template::{AttrSuggestionStyle, AttributeTemplate}; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index f610ff4e8915f..121cac79e6382 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -4,13 +4,13 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, }; -use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; use rustc_hir::attrs::{MirDialect, MirPhase}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use rustc_target::spec::TargetTuple; +use crate::AttributeTemplate; use crate::context::Suggestion; #[derive(Diagnostic)] diff --git a/compiler/rustc_attr_parsing/src/template.rs b/compiler/rustc_attr_parsing/src/template.rs new file mode 100644 index 0000000000000..b8de6baa87780 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/template.rs @@ -0,0 +1,118 @@ +use rustc_ast::ast::Safety; +use rustc_hir::AttrStyle; +use rustc_span::Symbol; + +/// A template that the attribute input must match. +/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. +#[derive(Clone, Copy, Default)] +pub struct AttributeTemplate { + /// If `true`, the attribute is allowed to be a bare word like `#[test]`. + pub word: bool, + /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`. + pub list: Option<&'static [&'static str]>, + /// If non-empty, the attribute is allowed to take a list containing exactly + /// one of the listed words, like `#[coverage(off)]`. + pub one_of: &'static [Symbol], + /// If `Some`, the attribute is allowed to be a name/value pair where the + /// value is a string, like `#[must_use = "reason"]`. + pub name_value_str: Option<&'static [&'static str]>, + /// A link to the document for this attribute. + pub docs: Option<&'static str>, +} + +pub enum AttrSuggestionStyle { + /// The suggestion is styled for a normal attribute. + /// The `AttrStyle` determines whether this is an inner or outer attribute. + Attribute(AttrStyle), + /// The suggestion is styled for an attribute embedded into another attribute. + /// For example, attributes inside `#[cfg_attr(true, attr(...)]`. + EmbeddedAttribute, + /// The suggestion is styled for macros that are parsed with attribute parsers. + /// For example, the `cfg!(predicate)` macro. + Macro, +} + +impl AttributeTemplate { + pub fn suggestions( + &self, + style: AttrSuggestionStyle, + safety: Safety, + name: impl std::fmt::Display, + ) -> Vec { + let (start, macro_call, end) = match style { + AttrSuggestionStyle::Attribute(AttrStyle::Outer) => ("#[", "", "]"), + AttrSuggestionStyle::Attribute(AttrStyle::Inner) => ("#![", "", "]"), + AttrSuggestionStyle::Macro => ("", "!", ""), + AttrSuggestionStyle::EmbeddedAttribute => ("", "", ""), + }; + + let mut suggestions = vec![]; + + let (safety_start, safety_end) = match safety { + Safety::Unsafe(_) => ("unsafe(", ")"), + _ => ("", ""), + }; + + if self.word { + debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); + suggestions.push(format!("{start}{safety_start}{name}{safety_end}{end}")); + } + if let Some(descr) = self.list { + for descr in descr { + suggestions.push(format!( + "{start}{safety_start}{name}{macro_call}({descr}){safety_end}{end}" + )); + } + } + suggestions.extend( + self.one_of + .iter() + .map(|&word| format!("{start}{safety_start}{name}({word}){safety_end}{end}")), + ); + if let Some(descr) = self.name_value_str { + debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); + for descr in descr { + suggestions + .push(format!("{start}{safety_start}{name} = \"{descr}\"{safety_end}{end}")); + } + } + suggestions.sort(); + + suggestions + } +} + +/// A convenience macro for constructing attribute templates. +/// E.g., `template!(Word, List: "description")` means that the attribute +/// supports forms `#[attr]` and `#[attr(description)]`. +#[macro_export] +macro_rules! template { + (Word) => { $crate::template!(@ true, None, &[], None, None) }; + (Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) }; + (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) }; + (List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) }; + (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) }; + (NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) }; + (NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) }; + (NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) }; + (NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) }; + (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) }; + (Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) }; + (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) }; + (Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) }; + (List: $descr1: expr, NameValueStr: $descr2: expr) => { + $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None) + }; + (List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => { + $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link)) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { + $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => { + $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link)) + }; + (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate { + word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link, + } }; +} diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 433ee26850d7f..22a47434e5873 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -9,7 +9,7 @@ use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, }; use rustc_errors::{Applicability, Diagnostic, PResult}; -use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, template}; +use rustc_feature::BUILTIN_ATTRIBUTE_MAP; use rustc_hir::AttrPath; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; @@ -17,7 +17,7 @@ use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; use rustc_span::{Span, Symbol, sym}; -use crate::{AttributeParser, session_diagnostics as errors}; +use crate::{AttributeParser, AttributeTemplate, session_diagnostics as errors, template}; pub fn check_attr(psess: &ParseSess, attr: &Attribute) { if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 48e75719c0b16..cc02206c50649 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -96,6 +96,12 @@ enum GroupedMoveError<'tcx> { }, } +struct PatternBindingInfo { + pat_span: Span, + binding_spans: Vec, + has_mutable_by_value_binding: bool, +} + impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { pub(crate) fn report_move_errors(&mut self) { let grouped_errors = self.group_move_errors(); @@ -735,8 +741,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - self.add_borrow_suggestions(err, span, !binds_to.is_empty()); + binds_to.sort(); + binds_to.dedup(); + if binds_to.is_empty() { + self.add_borrow_suggestions(err, span, false); let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(move_from.as_ref()) { Some(desc) => format!("`{desc}`"), @@ -754,16 +763,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { span, }); } else { - binds_to.sort(); - binds_to.dedup(); - - self.add_move_error_details(err, &binds_to, &[]); + let binding_info = self.pattern_binding_info(&binds_to); + let suggest_pattern_binding = binding_info.as_ref().is_some_and(|info| { + self.should_suggest_pattern_binding_instead(span, info) + }); + let desugar_spans = if suggest_pattern_binding { + self.add_move_error_suggestions(err, &binds_to) + } else { + if self.should_suggest_borrow_instead(span, binding_info.as_ref()) { + self.add_borrow_suggestions(err, span, true); + } + None + }; + self.add_move_error_details( + err, + &binds_to, + desugar_spans.as_deref().unwrap_or_default(), + ); } } GroupedMoveError::MovesFromValue { mut binds_to, .. } => { binds_to.sort(); binds_to.dedup(); - let desugar_spans = self.add_move_error_suggestions(err, &binds_to); + let desugar_spans = + self.add_move_error_suggestions(err, &binds_to).unwrap_or_default(); self.add_move_error_details(err, &binds_to, &desugar_spans); } // No binding. Nothing to suggest. @@ -947,7 +970,102 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) -> Vec { + fn should_suggest_pattern_binding_instead( + &self, + span: Span, + binding_info: &PatternBindingInfo, + ) -> bool { + let Some(expr) = self.find_expr(span) else { + return false; + }; + + let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); + let projection_qualifies = match expr.kind { + hir::ExprKind::Field(base, ..) => { + !typeck_results.node_type_opt(base.hir_id).is_some_and(|base_ty| { + binding_info.has_mutable_by_value_binding + && matches!(base_ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) + }) + } + hir::ExprKind::Index(base, ..) => typeck_results + .node_type_opt(base.hir_id) + .is_some_and(|base_ty| match base_ty.kind() { + ty::Ref(_, _, hir::Mutability::Not) | ty::RawPtr(..) => false, + ty::Ref(_, _, hir::Mutability::Mut) => { + binding_info.has_mutable_by_value_binding + } + _ => true, + }), + _ => false, + }; + if !projection_qualifies { + return false; + } + + let is_single_binding = binding_info.binding_spans.len() == 1 + && binding_info.binding_spans[0] == binding_info.pat_span; + !is_single_binding + } + + fn should_suggest_borrow_instead( + &self, + span: Span, + binding_info: Option<&PatternBindingInfo>, + ) -> bool { + if !binding_info.is_some_and(|info| info.has_mutable_by_value_binding) { + return true; + } + + let Some(expr) = self.find_expr(span) else { + return true; + }; + + let Some(base) = (match expr.kind { + hir::ExprKind::Field(base, _) | hir::ExprKind::Index(base, ..) => Some(base), + _ => None, + }) else { + return true; + }; + + !self + .infcx + .tcx + .typeck(self.mir_def_id()) + .node_type_opt(base.hir_id) + .is_some_and(|base_ty| matches!(base_ty.kind(), ty::Ref(_, _, hir::Mutability::Not))) + } + + fn pattern_binding_info(&self, binds_to: &[Local]) -> Option { + let mut pat_span = None; + let mut binding_spans = Vec::new(); + let mut has_mutable_by_value_binding = false; + for local in binds_to { + let bind_to = &self.body.local_decls[*local]; + if let LocalInfo::User(BindingForm::Var(VarBindingForm { + pat_span: pat_sp, + binding_mode, + .. + })) = *bind_to.local_info() + { + pat_span = Some(pat_sp); + binding_spans.push(bind_to.source_info.span); + has_mutable_by_value_binding |= + matches!(binding_mode, hir::BindingMode(hir::ByRef::No, hir::Mutability::Mut)); + } + } + + Some(PatternBindingInfo { + pat_span: pat_span?, + binding_spans, + has_mutable_by_value_binding, + }) + } + + fn add_move_error_suggestions( + &self, + err: &mut Diag<'_>, + binds_to: &[Local], + ) -> Option> { /// A HIR visitor to associate each binding with a `&` or `&mut` that could be removed to /// make it bind by reference instead (if possible) struct BindingFinder<'tcx> { @@ -1050,27 +1168,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.has_adjustments = parent_has_adjustments; } } - let mut pat_span = None; - let mut binding_spans = Vec::new(); - for local in binds_to { - let bind_to = &self.body.local_decls[*local]; - if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span: pat_sp, .. })) = - *bind_to.local_info() - { - pat_span = Some(pat_sp); - binding_spans.push(bind_to.source_info.span); - } - } - let Some(pat_span) = pat_span else { return Vec::new() }; + let Some(binding_info) = self.pattern_binding_info(binds_to) else { + return None; + }; let tcx = self.infcx.tcx; - let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return Vec::new() }; + let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { + return None; + }; let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let mut finder = BindingFinder { typeck_results, tcx, - pat_span, - binding_spans, + pat_span: binding_info.pat_span, + binding_spans: binding_info.binding_spans, found_pat: false, ref_pat: None, has_adjustments: false, @@ -1101,7 +1212,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { for (span, msg, suggestion) in suggestions { err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable); } - finder.desugar_binding_spans + + Some(finder.desugar_binding_spans) } fn add_move_error_details( diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 4d48a38ac2848..25964c9355eb9 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,9 +1,8 @@ //! Implementation of the `#[cfg_accessible(path)]` attribute macro. use rustc_ast as ast; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{AttributeTemplate, validate_attr}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; -use rustc_feature::AttributeTemplate; use rustc_span::{Span, sym}; use crate::diagnostics; diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 79c0563b9d183..da85a8a763b01 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,10 +1,9 @@ use rustc_ast as ast; use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind}; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{AttributeTemplate, validate_attr}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; -use rustc_feature::AttributeTemplate; use rustc_session::Session; use rustc_span::{ErrorGuaranteed, Ident, Span, sym}; diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 769016ecac2a7..c6ea73295efba 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,10 +1,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token}; -use rustc_attr_parsing::validate_attr; +use rustc_attr_parsing::{AttributeTemplate, validate_attr}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; use rustc_expand::expand::AstFragment; -use rustc_feature::AttributeTemplate; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; use rustc_parse::{exp, parser}; use rustc_session::errors::report_lit_error; diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index f64ff982e5238..d4bda53ece04b 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -2,9 +2,9 @@ use std::iter::once; use std::path::{self, Path, PathBuf}; use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans}; +use rustc_attr_parsing::template; use rustc_attr_parsing::validate_attr::emit_malformed_attribute; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_feature::template; use rustc_parse::lexer::StripTokens; use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::Session; diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index 3cd88cc4bc116..454fa20032aca 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -5,9 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index eab60460903aa..6f55becdc9a7a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -2,9 +2,7 @@ use std::sync::LazyLock; -use rustc_ast::ast::Safety; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::AttrStyle; use rustc_span::{Symbol, sym}; use crate::Features; @@ -75,122 +73,6 @@ pub enum AttributeStability { Stable, } -// FIXME(jdonszelmann): move to rustc_hir::attrs -/// A template that the attribute input must match. -/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. -#[derive(Clone, Copy, Default)] -pub struct AttributeTemplate { - /// If `true`, the attribute is allowed to be a bare word like `#[test]`. - pub word: bool, - /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`. - pub list: Option<&'static [&'static str]>, - /// If non-empty, the attribute is allowed to take a list containing exactly - /// one of the listed words, like `#[coverage(off)]`. - pub one_of: &'static [Symbol], - /// If `Some`, the attribute is allowed to be a name/value pair where the - /// value is a string, like `#[must_use = "reason"]`. - pub name_value_str: Option<&'static [&'static str]>, - /// A link to the document for this attribute. - pub docs: Option<&'static str>, -} - -pub enum AttrSuggestionStyle { - /// The suggestion is styled for a normal attribute. - /// The `AttrStyle` determines whether this is an inner or outer attribute. - Attribute(AttrStyle), - /// The suggestion is styled for an attribute embedded into another attribute. - /// For example, attributes inside `#[cfg_attr(true, attr(...)]`. - EmbeddedAttribute, - /// The suggestion is styled for macros that are parsed with attribute parsers. - /// For example, the `cfg!(predicate)` macro. - Macro, -} - -impl AttributeTemplate { - pub fn suggestions( - &self, - style: AttrSuggestionStyle, - safety: Safety, - name: impl std::fmt::Display, - ) -> Vec { - let (start, macro_call, end) = match style { - AttrSuggestionStyle::Attribute(AttrStyle::Outer) => ("#[", "", "]"), - AttrSuggestionStyle::Attribute(AttrStyle::Inner) => ("#![", "", "]"), - AttrSuggestionStyle::Macro => ("", "!", ""), - AttrSuggestionStyle::EmbeddedAttribute => ("", "", ""), - }; - - let mut suggestions = vec![]; - - let (safety_start, safety_end) = match safety { - Safety::Unsafe(_) => ("unsafe(", ")"), - _ => ("", ""), - }; - - if self.word { - debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); - suggestions.push(format!("{start}{safety_start}{name}{safety_end}{end}")); - } - if let Some(descr) = self.list { - for descr in descr { - suggestions.push(format!( - "{start}{safety_start}{name}{macro_call}({descr}){safety_end}{end}" - )); - } - } - suggestions.extend( - self.one_of - .iter() - .map(|&word| format!("{start}{safety_start}{name}({word}){safety_end}{end}")), - ); - if let Some(descr) = self.name_value_str { - debug_assert!(macro_call.is_empty(), "Macro suggestions use list style"); - for descr in descr { - suggestions - .push(format!("{start}{safety_start}{name} = \"{descr}\"{safety_end}{end}")); - } - } - suggestions.sort(); - - suggestions - } -} - -/// A convenience macro for constructing attribute templates. -/// E.g., `template!(Word, List: "description")` means that the attribute -/// supports forms `#[attr]` and `#[attr(description)]`. -#[macro_export] -macro_rules! template { - (Word) => { $crate::template!(@ true, None, &[], None, None) }; - (Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) }; - (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) }; - (List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) }; - (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) }; - (NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) }; - (NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) }; - (NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) }; - (NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) }; - (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) }; - (Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) }; - (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) }; - (Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) }; - (List: $descr1: expr, NameValueStr: $descr2: expr) => { - $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None) - }; - (List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => { - $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link)) - }; - (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None) - }; - (Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => { - $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link)) - }; - (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate { - word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link, - } }; -} - /// Attributes that have a special meaning to rustc or rustdoc. #[rustfmt::skip] pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index eea9474a9507b..859b2025619e4 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -129,8 +129,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option, span: Span, def_id: LocalDefId, scalab pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { + // `#[pin_v2]` on a packed type is unsound: drop glue for a packed type moves an + // over-aligned field to an aligned location before running its destructor, which would + // move a structurally pinned field out from under a `Pin<&mut _>` that was handed out. + if def.is_pin_project() { + tcx.dcx().emit_err(errors::PinV2OnPacked { + span: sp, + pin_v2_span: find_attr!(tcx, def.did(), PinV2(span) => *span), + adt_name: tcx.item_name(def.did()), + }); + } if let Some(reprs) = find_attr!(tcx, def.did(), Repr { reprs, .. } => reprs) { for (r, _) in reprs { if let ReprPacked(pack) = r diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index b968a626d398f..e7518e46e3654 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -2035,3 +2035,16 @@ pub(crate) struct PinV2WithoutPinDrop { pub pin_v2_span: Option, pub adt_name: Symbol, } + +#[derive(Diagnostic)] +#[diag("`#[pin_v2]` types may not have `#[repr(packed)]`")] +#[note( + "fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow" +)] +pub(crate) struct PinV2OnPacked { + #[primary_span] + pub span: Span, + #[note("`{$adt_name}` is marked `#[pin_v2]` here")] + pub pin_v2_span: Option, + pub adt_name: Symbol, +} diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b03a07538ccd8..5dcaa5f6f84b8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1503,12 +1503,19 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, DenseSet CfiFunctionDecls; // Based on the 'InProcessThinBackend' constructor in LLVM +#if LLVM_VERSION_GE(23, 0) + CfiFunctionDefs.insert_range( + Data->Index.cfiFunctionDefs().getExportedThinLTOGUIDs()); + CfiFunctionDecls.insert_range( + Data->Index.cfiFunctionDecls().getExportedThinLTOGUIDs()); +#else for (auto &Name : Data->Index.cfiFunctionDefs().symbols()) CfiFunctionDefs.insert(GlobalValue::getGUIDAssumingExternalLinkage( GlobalValue::dropLLVMManglingEscape(Name))); for (auto &Name : Data->Index.cfiFunctionDecls().symbols()) CfiFunctionDecls.insert(GlobalValue::getGUIDAssumingExternalLinkage( GlobalValue::dropLLVMManglingEscape(Name))); +#endif Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList, ExportList, ResolvedODR, DefinedGlobals, diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index 2135eb6d2e578..fc250e6ab7de9 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -40,9 +40,10 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> { self.buffer.buffer() } - /// Flushes the buffer iff the last byte is a newline (indicating that an - /// earlier write only succeeded partially, and we want to retry flushing - /// the buffered line before continuing with a subsequent write). + /// Flushes the buffer if and only if the last byte is a newline + /// (indicating that an earlier write only succeeded partially, and we + /// want to retry flushing the buffered line before continuing with a + /// subsequent write). fn flush_if_completed_line(&mut self) -> io::Result<()> { match self.buffered().last().copied() { Some(b'\n') => self.buffer.flush_buf(), diff --git a/tests/ui/binding/issue-40402-2.stderr b/tests/ui/binding/issue-40402-2.stderr index 987558903ee42..571dbe47d77b7 100644 --- a/tests/ui/binding/issue-40402-2.stderr +++ b/tests/ui/binding/issue-40402-2.stderr @@ -8,10 +8,14 @@ LL | let (a, b) = x[0]; | data moved here | = note: move occurs because these variables have types that don't implement the `Copy` trait -help: consider borrowing here +help: consider borrowing the pattern binding | -LL | let (a, b) = &x[0]; - | + +LL | let (ref a, b) = x[0]; + | +++ +help: consider borrowing the pattern binding + | +LL | let (a, ref b) = x[0]; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.fixed b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.fixed new file mode 100644 index 0000000000000..1e70933ae7381 --- /dev/null +++ b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.fixed @@ -0,0 +1,40 @@ +//@ run-rustfix +#![allow(dead_code)] + +use std::ops::{Deref, DerefMut}; + +fn take(mut wrap: Wrap) { + if let Some(ref mut val) = wrap.field { + //~^ ERROR cannot move out of dereference of `Wrap` + val.0 = (); + } +} + +fn take_mut_ref_base(mut wrap: Wrap) { + if let Some(ref mut val) = (&mut wrap).field { + //~^ ERROR cannot move out of dereference of `Wrap` + val.0 = (); + } +} + +struct Wrap(T); +struct Struct { + field: Option, +} +struct NonCopy(()); + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Wrap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +fn main() {} diff --git a/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.rs b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.rs new file mode 100644 index 0000000000000..ff9d4409b86bb --- /dev/null +++ b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.rs @@ -0,0 +1,40 @@ +//@ run-rustfix +#![allow(dead_code)] + +use std::ops::{Deref, DerefMut}; + +fn take(mut wrap: Wrap) { + if let Some(mut val) = wrap.field { + //~^ ERROR cannot move out of dereference of `Wrap` + val.0 = (); + } +} + +fn take_mut_ref_base(mut wrap: Wrap) { + if let Some(mut val) = (&mut wrap).field { + //~^ ERROR cannot move out of dereference of `Wrap` + val.0 = (); + } +} + +struct Wrap(T); +struct Struct { + field: Option, +} +struct NonCopy(()); + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Wrap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +fn main() {} diff --git a/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.stderr b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.stderr new file mode 100644 index 0000000000000..506ddd3bedae8 --- /dev/null +++ b/tests/ui/borrowck/deref-field-pattern-ref-suggestion-issue-146995.stderr @@ -0,0 +1,29 @@ +error[E0507]: cannot move out of dereference of `Wrap` + --> $DIR/deref-field-pattern-ref-suggestion-issue-146995.rs:7:28 + | +LL | if let Some(mut val) = wrap.field { + | ------- ^^^^^^^^^^ + | | + | data moved here because `val` has type `NonCopy`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | if let Some(ref mut val) = wrap.field { + | +++ + +error[E0507]: cannot move out of dereference of `Wrap` + --> $DIR/deref-field-pattern-ref-suggestion-issue-146995.rs:14:28 + | +LL | if let Some(mut val) = (&mut wrap).field { + | ------- ^^^^^^^^^^^^^^^^^ + | | + | data moved here because `val` has type `NonCopy`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | if let Some(ref mut val) = (&mut wrap).field { + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/deref-index-pattern-ref-suggestion.fixed b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.fixed new file mode 100644 index 0000000000000..155a7c76e995d --- /dev/null +++ b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.fixed @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(dead_code)] + +use std::ops::{Deref, DerefMut}; + +fn take(mut wrap: Wrap<[Option; 1]>) { + if let Some(ref mut val) = wrap[0] { + //~^ ERROR cannot move out of type `[Option; 1]`, a non-copy array + val.0 = (); + } +} + +fn take_mut_ref_base(mut wrap: Wrap<[Option; 1]>) { + if let Some(ref mut val) = (&mut wrap)[0] { + //~^ ERROR cannot move out of type `[Option; 1]`, a non-copy array + val.0 = (); + } +} + +struct Wrap(T); +struct NonCopy(()); + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Wrap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +fn main() {} diff --git a/tests/ui/borrowck/deref-index-pattern-ref-suggestion.rs b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.rs new file mode 100644 index 0000000000000..5cfb2297418ea --- /dev/null +++ b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.rs @@ -0,0 +1,37 @@ +//@ run-rustfix +#![allow(dead_code)] + +use std::ops::{Deref, DerefMut}; + +fn take(mut wrap: Wrap<[Option; 1]>) { + if let Some(mut val) = wrap[0] { + //~^ ERROR cannot move out of type `[Option; 1]`, a non-copy array + val.0 = (); + } +} + +fn take_mut_ref_base(mut wrap: Wrap<[Option; 1]>) { + if let Some(mut val) = (&mut wrap)[0] { + //~^ ERROR cannot move out of type `[Option; 1]`, a non-copy array + val.0 = (); + } +} + +struct Wrap(T); +struct NonCopy(()); + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Wrap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +fn main() {} diff --git a/tests/ui/borrowck/deref-index-pattern-ref-suggestion.stderr b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.stderr new file mode 100644 index 0000000000000..fbaf6596bb6e4 --- /dev/null +++ b/tests/ui/borrowck/deref-index-pattern-ref-suggestion.stderr @@ -0,0 +1,29 @@ +error[E0508]: cannot move out of type `[Option; 1]`, a non-copy array + --> $DIR/deref-index-pattern-ref-suggestion.rs:7:28 + | +LL | if let Some(mut val) = wrap[0] { + | ------- ^^^^^^^ cannot move out of here + | | + | data moved here because `val` has type `NonCopy`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | if let Some(ref mut val) = wrap[0] { + | +++ + +error[E0508]: cannot move out of type `[Option; 1]`, a non-copy array + --> $DIR/deref-index-pattern-ref-suggestion.rs:14:28 + | +LL | if let Some(mut val) = (&mut wrap)[0] { + | ------- ^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here because `val` has type `NonCopy`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | if let Some(ref mut val) = (&mut wrap)[0] { + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/moves/moves-based-on-type-block-bad.fixed b/tests/ui/moves/moves-based-on-type-block-bad.fixed new file mode 100644 index 0000000000000..c272203c7f0bf --- /dev/null +++ b/tests/ui/moves/moves-based-on-type-block-bad.fixed @@ -0,0 +1,31 @@ +//@ run-rustfix +#![feature(box_patterns)] +#![allow(dead_code)] + + +struct S { + x: Box +} + +enum E { + Foo(Box), + Bar(Box), + Baz +} + +fn f(s: &S, g: G) where G: FnOnce(&S) { + g(s) +} + +fn main() { + let s = S { x: Box::new(E::Bar(Box::new(42))) }; + loop { + f(&s, |hellothere| { + match hellothere.x { //~ ERROR cannot move out + box E::Foo(_) => {} + box E::Bar(ref x) => println!("{}", x.to_string()), + box E::Baz => {} + } + }) + } +} diff --git a/tests/ui/moves/moves-based-on-type-block-bad.rs b/tests/ui/moves/moves-based-on-type-block-bad.rs index eca33167f454a..e036e10fb180a 100644 --- a/tests/ui/moves/moves-based-on-type-block-bad.rs +++ b/tests/ui/moves/moves-based-on-type-block-bad.rs @@ -1,4 +1,6 @@ +//@ run-rustfix #![feature(box_patterns)] +#![allow(dead_code)] struct S { diff --git a/tests/ui/moves/moves-based-on-type-block-bad.stderr b/tests/ui/moves/moves-based-on-type-block-bad.stderr index 31417b59f0993..8e93b62fa8c65 100644 --- a/tests/ui/moves/moves-based-on-type-block-bad.stderr +++ b/tests/ui/moves/moves-based-on-type-block-bad.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference - --> $DIR/moves-based-on-type-block-bad.rs:22:19 + --> $DIR/moves-based-on-type-block-bad.rs:24:19 | LL | match hellothere.x { | ^^^^^^^^^^^^ @@ -7,10 +7,10 @@ LL | box E::Foo(_) => {} LL | box E::Bar(x) => println!("{}", x.to_string()), | - data moved here because `x` has type `Box`, which does not implement the `Copy` trait | -help: consider borrowing here +help: consider borrowing the pattern binding | -LL | match &hellothere.x { - | + +LL | box E::Bar(ref x) => println!("{}", x.to_string()), + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/move-errors.stderr b/tests/ui/nll/move-errors.stderr index c1ec357cab069..ea186fdc5aa20 100644 --- a/tests/ui/nll/move-errors.stderr +++ b/tests/ui/nll/move-errors.stderr @@ -156,10 +156,14 @@ LL | B::V(s) => (), | - ...and here | = note: move occurs because these variables have types that don't implement the `Copy` trait -help: consider borrowing here +help: consider borrowing the pattern binding + | +LL | B::U(ref d) => (), + | +++ +help: consider borrowing the pattern binding | -LL | match &x[0] { - | + +LL | B::V(ref s) => (), + | +++ error[E0509]: cannot move out of type `D`, which implements the `Drop` trait --> $DIR/move-errors.rs:83:11 diff --git a/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr b/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr index f9ef1efa6b2e5..afbf67f203a5a 100644 --- a/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr +++ b/tests/ui/pattern/mut-pattern-of-immutable-borrow.stderr @@ -6,10 +6,10 @@ LL | match arg.field { LL | Some(s) => s.push('a'), | - data moved here because `s` has type `String`, which does not implement the `Copy` trait | -help: consider borrowing here +help: consider borrowing the pattern binding | -LL | match &arg.field { - | + +LL | Some(ref s) => s.push('a'), + | +++ error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable --> $DIR/mut-pattern-of-immutable-borrow.rs:7:20 diff --git a/tests/ui/pin-ergonomics/pin_v2-packed.rs b/tests/ui/pin-ergonomics/pin_v2-packed.rs new file mode 100644 index 0000000000000..b10c7565de0c9 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin_v2-packed.rs @@ -0,0 +1,42 @@ +//! `#[pin_v2]` is not allowed on `#[repr(packed)]` types. +//! +//! Drop glue for a packed type moves an over-aligned field to an aligned location before running +//! its destructor. That move carries along any structurally pinned leaf, so a value handed out as +//! `Pin<&mut _>` would be moved before it is dropped, violating `Pin`'s invariant. +//! +//! Regression test for . + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +use std::marker::PhantomPinned; + +#[pin_v2] +#[repr(packed)] +struct Packed { //~ ERROR `#[pin_v2]` types may not have `#[repr(packed)]` + field: PhantomPinned, +} + +// The generic case from the issue: alignment of `T` is unknown at definition time, so this is +// rejected regardless of how it is later monomorphized. +#[pin_v2] +#[repr(C, packed(4))] +struct PackedN(T); +//~^ ERROR `#[pin_v2]` types may not have `#[repr(packed)]` + +#[pin_v2] +#[repr(packed)] +union PackedUnion { //~ ERROR `#[pin_v2]` types may not have `#[repr(packed)]` + field: (), +} + +// Allowed: `#[pin_v2]` without `#[repr(packed)]` still compiles. +#[pin_v2] +#[repr(C)] +struct Unpacked(T); + +// Allowed: `#[repr(packed)]` without `#[pin_v2]` is unaffected by the ban. +#[repr(packed)] +struct PackedNoPin(u8); + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pin_v2-packed.stderr b/tests/ui/pin-ergonomics/pin_v2-packed.stderr new file mode 100644 index 0000000000000..975b74e419687 --- /dev/null +++ b/tests/ui/pin-ergonomics/pin_v2-packed.stderr @@ -0,0 +1,41 @@ +error: `#[pin_v2]` types may not have `#[repr(packed)]` + --> $DIR/pin_v2-packed.rs:16:1 + | +LL | struct Packed { + | ^^^^^^^^^^^^^ + | + = note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow +note: `Packed` is marked `#[pin_v2]` here + --> $DIR/pin_v2-packed.rs:14:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + +error: `#[pin_v2]` types may not have `#[repr(packed)]` + --> $DIR/pin_v2-packed.rs:24:1 + | +LL | struct PackedN(T); + | ^^^^^^^^^^^^^^^^^ + | + = note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow +note: `PackedN` is marked `#[pin_v2]` here + --> $DIR/pin_v2-packed.rs:22:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + +error: `#[pin_v2]` types may not have `#[repr(packed)]` + --> $DIR/pin_v2-packed.rs:29:1 + | +LL | union PackedUnion { + | ^^^^^^^^^^^^^^^^^ + | + = note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow +note: `PackedUnion` is marked `#[pin_v2]` here + --> $DIR/pin_v2-packed.rs:27:1 + | +LL | #[pin_v2] + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/suggestions/dont-suggest-ref/simple.rs b/tests/ui/suggestions/dont-suggest-ref/simple.rs index 4dea5319264ed..07f2dcaa276ce 100644 --- a/tests/ui/suggestions/dont-suggest-ref/simple.rs +++ b/tests/ui/suggestions/dont-suggest-ref/simple.rs @@ -10,6 +10,26 @@ struct X(Y); #[derive(Clone)] struct Y; +struct Wrap(T); + +struct WrappedField { + field: Option, +} + +impl std::ops::Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for Wrap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + pub fn main() { let e = Either::One(X(Y)); let mut em = Either::One(X(Y)); @@ -141,6 +161,14 @@ pub fn main() { // FIXME: should suggest removing `ref` too } + let wrapped_field = Wrap(WrappedField { field: Some(X(Y)) }); + if let Some(mut _t) = (&wrapped_field).field { } + //~^ ERROR cannot move + + let wrapped_index = Wrap([Some(X(Y))]); + if let Some(mut _t) = (&wrapped_index)[0] { } + //~^ ERROR cannot move + // move from &Either/&X place let &X(_t) = s; diff --git a/tests/ui/suggestions/dont-suggest-ref/simple.stderr b/tests/ui/suggestions/dont-suggest-ref/simple.stderr index 8e7582fbe588e..b41ebcb3b4e83 100644 --- a/tests/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/tests/ui/suggestions/dont-suggest-ref/simple.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `s` which is behind a shared reference - --> $DIR/simple.rs:38:17 + --> $DIR/simple.rs:58:17 | LL | let X(_t) = *s; | -- ^^ @@ -13,7 +13,7 @@ LL + let X(_t) = s; | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:41:30 + --> $DIR/simple.rs:61:30 | LL | if let Either::One(_t) = *r { } | -- ^^ @@ -27,7 +27,7 @@ LL + if let Either::One(_t) = r { } | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:44:33 + --> $DIR/simple.rs:64:33 | LL | while let Either::One(_t) = *r { } | -- ^^ @@ -41,7 +41,7 @@ LL + while let Either::One(_t) = r { } | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:47:11 + --> $DIR/simple.rs:67:11 | LL | match *r { | ^^ @@ -56,7 +56,7 @@ LL + match r { | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:53:11 + --> $DIR/simple.rs:73:11 | LL | match *r { | ^^ @@ -71,7 +71,7 @@ LL + match r { | error[E0507]: cannot move out of `sm` which is behind a mutable reference - --> $DIR/simple.rs:61:17 + --> $DIR/simple.rs:81:17 | LL | let X(_t) = *sm; | -- ^^^ @@ -85,7 +85,7 @@ LL + let X(_t) = sm; | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:64:30 + --> $DIR/simple.rs:84:30 | LL | if let Either::One(_t) = *rm { } | -- ^^^ @@ -99,7 +99,7 @@ LL + if let Either::One(_t) = rm { } | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:67:33 + --> $DIR/simple.rs:87:33 | LL | while let Either::One(_t) = *rm { } | -- ^^^ @@ -113,7 +113,7 @@ LL + while let Either::One(_t) = rm { } | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:70:11 + --> $DIR/simple.rs:90:11 | LL | match *rm { | ^^^ @@ -128,7 +128,7 @@ LL + match rm { | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:76:11 + --> $DIR/simple.rs:96:11 | LL | match *rm { | ^^^ @@ -143,7 +143,7 @@ LL + match rm { | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:83:11 + --> $DIR/simple.rs:103:11 | LL | match *rm { | ^^^ @@ -158,7 +158,7 @@ LL + match rm { | error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:91:17 + --> $DIR/simple.rs:111:17 | LL | let X(_t) = vs[0]; | -- ^^^^^ @@ -171,7 +171,7 @@ LL | let X(_t) = &vs[0]; | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:94:30 + --> $DIR/simple.rs:114:30 | LL | if let Either::One(_t) = vr[0] { } | -- ^^^^^ @@ -184,7 +184,7 @@ LL | if let Either::One(_t) = &vr[0] { } | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:97:33 + --> $DIR/simple.rs:117:33 | LL | while let Either::One(_t) = vr[0] { } | -- ^^^^^ @@ -197,7 +197,7 @@ LL | while let Either::One(_t) = &vr[0] { } | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:100:11 + --> $DIR/simple.rs:120:11 | LL | match vr[0] { | ^^^^^ @@ -211,7 +211,7 @@ LL | match &vr[0] { | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:106:11 + --> $DIR/simple.rs:126:11 | LL | match vr[0] { | ^^^^^ @@ -225,7 +225,7 @@ LL | match &vr[0] { | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:114:17 + --> $DIR/simple.rs:134:17 | LL | let X(_t) = vsm[0]; | -- ^^^^^^ @@ -238,7 +238,7 @@ LL | let X(_t) = &vsm[0]; | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:117:30 + --> $DIR/simple.rs:137:30 | LL | if let Either::One(_t) = vrm[0] { } | -- ^^^^^^ @@ -251,7 +251,7 @@ LL | if let Either::One(_t) = &vrm[0] { } | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:120:33 + --> $DIR/simple.rs:140:33 | LL | while let Either::One(_t) = vrm[0] { } | -- ^^^^^^ @@ -264,7 +264,7 @@ LL | while let Either::One(_t) = &vrm[0] { } | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:123:11 + --> $DIR/simple.rs:143:11 | LL | match vrm[0] { | ^^^^^^ @@ -278,7 +278,7 @@ LL | match &vrm[0] { | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:129:11 + --> $DIR/simple.rs:149:11 | LL | match vrm[0] { | ^^^^^^ @@ -292,7 +292,7 @@ LL | match &vrm[0] { | + error[E0507]: cannot move out of index of `Vec` - --> $DIR/simple.rs:136:11 + --> $DIR/simple.rs:156:11 | LL | match vrm[0] { | ^^^^^^ @@ -305,8 +305,24 @@ help: consider borrowing here LL | match &vrm[0] { | + +error[E0507]: cannot move out of dereference of `Wrap` + --> $DIR/simple.rs:165:27 + | +LL | if let Some(mut _t) = (&wrapped_field).field { } + | ------ ^^^^^^^^^^^^^^^^^^^^^^ + | | + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[Option; 1]`, a non-copy array + --> $DIR/simple.rs:169:27 + | +LL | if let Some(mut _t) = (&wrapped_index)[0] { } + | ------ ^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here because `_t` has type `X`, which does not implement the `Copy` trait + error[E0507]: cannot move out of `s` which is behind a shared reference - --> $DIR/simple.rs:146:18 + --> $DIR/simple.rs:174:18 | LL | let &X(_t) = s; | -- ^ @@ -320,7 +336,7 @@ LL + let X(_t) = s; | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:149:31 + --> $DIR/simple.rs:177:31 | LL | if let &Either::One(_t) = r { } | -- ^ @@ -334,7 +350,7 @@ LL + if let Either::One(_t) = r { } | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:152:34 + --> $DIR/simple.rs:180:34 | LL | while let &Either::One(_t) = r { } | -- ^ @@ -348,7 +364,7 @@ LL + while let Either::One(_t) = r { } | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:155:11 + --> $DIR/simple.rs:183:11 | LL | match r { | ^ @@ -363,7 +379,7 @@ LL + Either::One(_t) | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:162:11 + --> $DIR/simple.rs:190:11 | LL | match r { | ^ @@ -378,7 +394,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference - --> $DIR/simple.rs:168:11 + --> $DIR/simple.rs:196:11 | LL | match r { | ^ @@ -393,7 +409,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of `sm` which is behind a mutable reference - --> $DIR/simple.rs:178:22 + --> $DIR/simple.rs:206:22 | LL | let &mut X(_t) = sm; | -- ^^ @@ -407,7 +423,7 @@ LL + let X(_t) = sm; | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:181:35 + --> $DIR/simple.rs:209:35 | LL | if let &mut Either::One(_t) = rm { } | -- ^^ @@ -421,7 +437,7 @@ LL + if let Either::One(_t) = rm { } | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:184:38 + --> $DIR/simple.rs:212:38 | LL | while let &mut Either::One(_t) = rm { } | -- ^^ @@ -435,7 +451,7 @@ LL + while let Either::One(_t) = rm { } | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:187:11 + --> $DIR/simple.rs:215:11 | LL | match rm { | ^^ @@ -459,7 +475,7 @@ LL + Either::Two(_t) => (), | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:194:11 + --> $DIR/simple.rs:222:11 | LL | match rm { | ^^ @@ -474,7 +490,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:200:11 + --> $DIR/simple.rs:228:11 | LL | match rm { | ^^ @@ -489,7 +505,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference - --> $DIR/simple.rs:206:11 + --> $DIR/simple.rs:234:11 | LL | match rm { | ^^ @@ -504,7 +520,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:220:21 + --> $DIR/simple.rs:248:21 | LL | let (&X(_t),) = (&x.clone(),); | -- ^^^^^^^^^^^^^ @@ -518,7 +534,7 @@ LL + let (X(_t),) = (&x.clone(),); | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:223:34 + --> $DIR/simple.rs:251:34 | LL | if let (&Either::One(_t),) = (&e.clone(),) { } | -- ^^^^^^^^^^^^^ @@ -532,7 +548,7 @@ LL + if let (Either::One(_t),) = (&e.clone(),) { } | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:226:37 + --> $DIR/simple.rs:254:37 | LL | while let (&Either::One(_t),) = (&e.clone(),) { } | -- ^^^^^^^^^^^^^ @@ -546,7 +562,7 @@ LL + while let (Either::One(_t),) = (&e.clone(),) { } | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:229:11 + --> $DIR/simple.rs:257:11 | LL | match (&e.clone(),) { | ^^^^^^^^^^^^^ @@ -561,7 +577,7 @@ LL + (Either::One(_t),) | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:239:25 + --> $DIR/simple.rs:267:25 | LL | let (&mut X(_t),) = (&mut xm.clone(),); | -- ^^^^^^^^^^^^^^^^^^ @@ -575,7 +591,7 @@ LL + let (X(_t),) = (&mut xm.clone(),); | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:242:38 + --> $DIR/simple.rs:270:38 | LL | if let (&mut Either::One(_t),) = (&mut em.clone(),) { } | -- ^^^^^^^^^^^^^^^^^^ @@ -589,7 +605,7 @@ LL + if let (Either::One(_t),) = (&mut em.clone(),) { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:245:41 + --> $DIR/simple.rs:273:41 | LL | while let (&mut Either::One(_t),) = (&mut em.clone(),) { } | -- ^^^^^^^^^^^^^^^^^^ @@ -603,7 +619,7 @@ LL + while let (Either::One(_t),) = (&mut em.clone(),) { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:248:11 + --> $DIR/simple.rs:276:11 | LL | match (&mut em.clone(),) { | ^^^^^^^^^^^^^^^^^^ @@ -627,7 +643,7 @@ LL + (Either::Two(_t),) => (), | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:261:18 + --> $DIR/simple.rs:289:18 | LL | let &X(_t) = &x; | -- ^^ @@ -641,7 +657,7 @@ LL + let X(_t) = &x; | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:264:31 + --> $DIR/simple.rs:292:31 | LL | if let &Either::One(_t) = &e { } | -- ^^ @@ -655,7 +671,7 @@ LL + if let Either::One(_t) = &e { } | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:267:34 + --> $DIR/simple.rs:295:34 | LL | while let &Either::One(_t) = &e { } | -- ^^ @@ -669,7 +685,7 @@ LL + while let Either::One(_t) = &e { } | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:270:11 + --> $DIR/simple.rs:298:11 | LL | match &e { | ^^ @@ -684,7 +700,7 @@ LL + Either::One(_t) | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:277:11 + --> $DIR/simple.rs:305:11 | LL | match &e { | ^^ @@ -699,7 +715,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:283:11 + --> $DIR/simple.rs:311:11 | LL | match &e { | ^^ @@ -714,7 +730,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:290:22 + --> $DIR/simple.rs:318:22 | LL | let &mut X(_t) = &mut xm; | -- ^^^^^^^ @@ -728,7 +744,7 @@ LL + let X(_t) = &mut xm; | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:293:35 + --> $DIR/simple.rs:321:35 | LL | if let &mut Either::One(_t) = &mut em { } | -- ^^^^^^^ @@ -742,7 +758,7 @@ LL + if let Either::One(_t) = &mut em { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:296:38 + --> $DIR/simple.rs:324:38 | LL | while let &mut Either::One(_t) = &mut em { } | -- ^^^^^^^ @@ -756,7 +772,7 @@ LL + while let Either::One(_t) = &mut em { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:299:11 + --> $DIR/simple.rs:327:11 | LL | match &mut em { | ^^^^^^^ @@ -771,7 +787,7 @@ LL + Either::One(_t) | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:306:11 + --> $DIR/simple.rs:334:11 | LL | match &mut em { | ^^^^^^^ @@ -786,7 +802,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:312:11 + --> $DIR/simple.rs:340:11 | LL | match &mut em { | ^^^^^^^ @@ -801,7 +817,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:318:11 + --> $DIR/simple.rs:346:11 | LL | match &mut em { | ^^^^^^^ @@ -816,7 +832,7 @@ LL + Either::One(_t) => (), | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:174:11 + --> $DIR/simple.rs:202:11 | LL | fn f1(&X(_t): &X) { } | ^^^--^ @@ -830,7 +846,7 @@ LL + fn f1(X(_t): &X) { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:212:11 + --> $DIR/simple.rs:240:11 | LL | fn f2(&mut X(_t): &mut X) { } | ^^^^^^^--^ @@ -844,7 +860,7 @@ LL + fn f2(X(_t): &mut X) { } | error[E0507]: cannot move out of a shared reference - --> $DIR/simple.rs:235:11 + --> $DIR/simple.rs:263:11 | LL | fn f3((&X(_t),): (&X,)) { } | ^^^^--^^^ @@ -858,7 +874,7 @@ LL + fn f3((X(_t),): (&X,)) { } | error[E0507]: cannot move out of a mutable reference - --> $DIR/simple.rs:255:11 + --> $DIR/simple.rs:283:11 | LL | fn f4((&mut X(_t),): (&mut X,)) { } | ^^^^^^^^--^^^ @@ -872,7 +888,7 @@ LL + fn f4((X(_t),): (&mut X,)) { } | error[E0507]: cannot move out of `a.a` as enum variant `Some` which is behind a shared reference - --> $DIR/simple.rs:331:20 + --> $DIR/simple.rs:359:20 | LL | let Some(_s) = a.a else { | -- ^^^ @@ -884,6 +900,7 @@ help: consider borrowing the pattern binding LL | let Some(ref _s) = a.a else { | +++ -error: aborting due to 61 previous errors +error: aborting due to 63 previous errors -For more information about this error, try `rustc --explain E0507`. +Some errors have detailed explanations: E0507, E0508. +For more information about an error, try `rustc --explain E0507`.