diff --git a/Cargo.lock b/Cargo.lock index 98567f858e9f1..539f66ffb3bb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1140,9 +1140,9 @@ version = "0.1.96" [[package]] name = "derive-where" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index be97d4f17dba8..a72ed842b8e35 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -329,6 +329,19 @@ fn print_crate_inner<'a>( /// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,` /// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` /// +/// Returns `true` if both token trees are identifier-like tokens that would +/// merge into a single token if printed without a space between them. +/// E.g. `ident` + `where` would merge into `identwhere`. +fn idents_would_merge(tt1: &TokenTree, tt2: &TokenTree) -> bool { + fn is_ident_like(tt: &TokenTree) -> bool { + matches!( + tt, + TokenTree::Token(Token { kind: token::Ident(..) | token::NtIdent(..), .. }, _,) + ) + } + is_ident_like(tt1) && is_ident_like(tt2) +} + fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { use Delimiter::*; use TokenTree::{Delimited as Del, Token as Tok}; @@ -811,6 +824,13 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere if let Some(next) = iter.peek() { if spacing == Spacing::Alone && space_between(tt, next) { self.space(); + } else if spacing != Spacing::Alone && idents_would_merge(tt, next) { + // When tokens from macro `tt` captures preserve their + // original `Joint`/`JointHidden` spacing, adjacent + // identifier-like tokens can be concatenated without a + // space (e.g. `$x:identwhere`). Insert a space to + // prevent this. + self.space(); } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9b4ff2b63bd45..0c5928765bfa5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -260,12 +260,15 @@ impl<'a> State<'a> { // // loop { break x; }.method(); // - self.print_expr_cond_paren( - receiver, - receiver.precedence() < ExprPrecedence::Unambiguous, - fixup.leftmost_subexpression_with_dot(), - ); + let needs_paren = receiver.precedence() < ExprPrecedence::Unambiguous; + self.print_expr_cond_paren(receiver, needs_paren, fixup.leftmost_subexpression_with_dot()); + // If the receiver is an unsuffixed float literal like `0.`, insert + // a space so the `.` of the method call doesn't merge with the + // trailing dot: `0. .method()` instead of `0..method()`. + if !needs_paren && expr_ends_with_dot(receiver) { + self.word(" "); + } self.word("."); self.print_ident(segment.ident); if let Some(args) = &segment.args { @@ -658,11 +661,15 @@ impl<'a> State<'a> { ); } ast::ExprKind::Field(expr, ident) => { + let needs_paren = expr.precedence() < ExprPrecedence::Unambiguous; self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Unambiguous, + needs_paren, fixup.leftmost_subexpression_with_dot(), ); + if !needs_paren && expr_ends_with_dot(expr) { + self.word(" "); + } self.word("."); self.print_ident(*ident); } @@ -685,11 +692,15 @@ impl<'a> State<'a> { let fake_prec = ExprPrecedence::LOr; if let Some(e) = start { let start_fixup = fixup.leftmost_subexpression_with_operator(true); - self.print_expr_cond_paren( - e, - start_fixup.precedence(e) < fake_prec, - start_fixup, - ); + let needs_paren = start_fixup.precedence(e) < fake_prec; + self.print_expr_cond_paren(e, needs_paren, start_fixup); + // If the start expression is a float literal ending with + // `.`, we need a space before `..` or `..=` so that the + // dots don't merge. E.g. `0. ..45.` must not become + // `0...45.`. + if !needs_paren && expr_ends_with_dot(e) { + self.word(" "); + } } match limits { ast::RangeLimits::HalfOpen => self.word(".."), @@ -1025,3 +1036,18 @@ fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String template.push('"'); template } + +/// Returns `true` if the printed representation of this expression ends with +/// a `.` character — specifically, an unsuffixed float literal like `0.` or +/// `45.`. This is used to insert whitespace before range operators (`..`, +/// `..=`) so that the dots don't merge (e.g. `0. ..45.` instead of `0...45.`). +fn expr_ends_with_dot(expr: &ast::Expr) -> bool { + match &expr.kind { + ast::ExprKind::Lit(token_lit) => { + token_lit.kind == token::Float + && token_lit.suffix.is_none() + && token_lit.symbol.as_str().ends_with('.') + } + _ => false, + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3407feb3dcc3a..e997fdf498202 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -881,7 +881,13 @@ impl<'a> State<'a> { } if items.is_empty() { self.word("{}"); - } else if let [(item, _)] = items.as_slice() { + } else if let [(item, _)] = items.as_slice() + && !item + .prefix + .segments + .first() + .is_some_and(|seg| seg.ident.name == rustc_span::symbol::kw::SelfLower) + { self.print_use_tree(item); } else { let cb = self.cbox(INDENT_UNIT); diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 8f114b3284485..63780676bead9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -22,6 +22,7 @@ use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItem pub(crate) mod do_not_recommend; pub(crate) mod on_const; +pub(crate) mod on_move; pub(crate) mod on_unimplemented; #[derive(Copy, Clone)] @@ -32,6 +33,8 @@ pub(crate) enum Mode { DiagnosticOnUnimplemented, /// `#[diagnostic::on_const]` DiagnosticOnConst, + /// `#[diagnostic::on_move]` + DiagnosticOnMove, } fn merge_directives( @@ -113,6 +116,13 @@ fn parse_directive_items<'p, S: Stage>( span, ); } + Mode::DiagnosticOnMove => { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::MalformedOnMoveAttr { span }, + span, + ); + } } continue; }} @@ -132,7 +142,7 @@ fn parse_directive_items<'p, S: Stage>( Mode::RustcOnUnimplemented => { cx.emit_err(NoValueInOnUnimplemented { span: item.span() }); } - Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst => { + Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => { cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, AttributeLintKind::IgnoredDiagnosticOption { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs new file mode 100644 index 0000000000000..006b3b66658e0 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -0,0 +1,72 @@ +use rustc_feature::template; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::AttributeLintKind; +use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES; +use rustc_span::sym; + +use crate::attributes::diagnostic::*; +use crate::attributes::prelude::*; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; +use crate::target_checking::{ALL_TARGETS, AllowedTargets}; + +#[derive(Default)] +pub(crate) struct OnMoveParser { + span: Option, + directive: Option<(Span, Directive)>, +} + +impl OnMoveParser { + fn parse<'sess, S: Stage>( + &mut self, + cx: &mut AcceptContext<'_, 'sess, S>, + args: &ArgParser, + mode: Mode, + ) { + if !cx.features().diagnostic_on_move() { + return; + } + + let span = cx.attr_span; + self.span = Some(span); + let Some(list) = args.list() else { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::MissingOptionsForOnMove, + span, + ); + return; + }; + + if list.is_empty() { + cx.emit_lint( + MALFORMED_DIAGNOSTIC_ATTRIBUTES, + AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter, + list.span, + ); + return; + } + + if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) { + merge_directives(cx, &mut self.directive, (span, directive)); + } + } +} +impl AttributeParser for OnMoveParser { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::diagnostic, sym::on_move], + template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]), + |this, cx, args| { + this.parse(cx, args, Mode::DiagnosticOnMove); + }, + )]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { + if let Some(span) = self.span { + Some(AttributeKind::OnMove { span, directive: self.directive.map(|d| Box::new(d.1)) }) + } else { + None + } + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 190568bed508d..259a73de59853 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -29,6 +29,7 @@ use crate::attributes::debugger::*; use crate::attributes::deprecation::*; use crate::attributes::diagnostic::do_not_recommend::*; use crate::attributes::diagnostic::on_const::*; +use crate::attributes::diagnostic::on_move::*; use crate::attributes::diagnostic::on_unimplemented::*; use crate::attributes::doc::*; use crate::attributes::dummy::*; @@ -149,6 +150,7 @@ attribute_parsers!( MacroUseParser, NakedParser, OnConstParser, + OnMoveParser, OnUnimplementedParser, RustcAlignParser, RustcAlignStaticParser, diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 0d3c554e41765..4fcb5f3b5a94d 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -324,18 +324,23 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { verb: &str, optional_adverb_for_moved: &str, moved_path: Option, + primary_message: Option, ) -> Diag<'infcx> { - let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); + if let Some(primary_message) = primary_message { + struct_span_code_err!(self.dcx(), use_span, E0382, "{}", primary_message) + } else { + let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default(); - struct_span_code_err!( - self.dcx(), - use_span, - E0382, - "{} of {}moved value{}", - verb, - optional_adverb_for_moved, - moved_path, - ) + struct_span_code_err!( + self.dcx(), + use_span, + E0382, + "{} of {}moved value{}", + verb, + optional_adverb_for_moved, + moved_path, + ) + } } pub(crate) fn cannot_borrow_path_as_mutable_because( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 641121597848c..7bbce730c1658 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,12 +6,16 @@ use std::ops::ControlFlow; use either::Either; use hir::{ClosureKind, Path}; use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err}; use rustc_hir as hir; +use rustc_hir::attrs::diagnostic::FormatArgs; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr}; -use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField}; +use rustc_hir::{ + CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr, +}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::{ @@ -138,6 +142,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let partial_str = if is_partial_move { "partial " } else { "" }; let partially_str = if is_partial_move { "partially " } else { "" }; + let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) = + self.body.local_decls[moved_place.local].ty.kind() + && let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. } => directive) + { + let item_name = self.infcx.tcx.item_name(item_def.did()).to_string(); + let mut generic_args: Vec<_> = self + .infcx + .tcx + .generics_of(item_def.did()) + .own_params + .iter() + .filter_map(|param| Some((param.name, args[param.index as usize].to_string()))) + .collect(); + generic_args.push((kw::SelfUpper, item_name)); + + let args = FormatArgs { + this: String::new(), + trait_sugared: String::new(), + item_context: "", + generic_args, + }; + ( + directive.message.as_ref().map(|e| e.1.format(&args)), + directive.label.as_ref().map(|e| e.1.format(&args)), + directive.notes.iter().map(|e| e.format(&args)).collect(), + ) + } else { + (None, None, ThinVec::new()) + }; + let mut err = self.cannot_act_on_moved_value( span, desired_action.as_noun(), @@ -146,8 +180,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { moved_place, DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, ), + on_move_message, ); + for note in on_move_notes { + err.note(note); + } + let reinit_spans = maybe_reinitialized_locations .iter() .take(3) @@ -275,12 +314,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if needs_note { if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; - err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { - is_partial_move, - ty, - place: ¬e_msg, - span, - }); + if let Some(on_move_label) = on_move_label { + err.span_label(span, on_move_label); + } else { + err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { + is_partial_move, + ty, + place: ¬e_msg, + span, + }); + } } else { err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note { is_partial_move, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index efd4e55d5a856..ffa582737ca8c 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -23,9 +23,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym}; -use rustc_target::spec::{ - Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel, -}; +use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::{debug, trace}; use crate::back::lto::{Buffer, ModuleBuffer}; @@ -206,13 +204,7 @@ pub(crate) fn target_machine_factory( let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); - let float_abi = if sess.target.arch == Arch::Arm && sess.opts.cg.soft_float { - llvm::FloatAbi::Soft - } else { - // `validate_commandline_args_with_session_available` has already warned about this being - // ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets. - to_llvm_float_abi(sess.target.llvm_floatabi) - }; + let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi); let ffunction_sections = sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3a2f548902d11..d74450e67cf1d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1587,6 +1587,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool match sym { sym::on_unimplemented | sym::do_not_recommend => true, sym::on_const => features.diagnostic_on_const(), + sym::on_move => features.diagnostic_on_move(), _ => false, } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c508344b9cc1f..e8ca20d7f5f44 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -472,6 +472,8 @@ declare_features! ( (unstable, derive_from, "1.91.0", Some(144889)), /// Allows giving non-const impls custom diagnostic messages if attempted to be used as const (unstable, diagnostic_on_const, "1.93.0", Some(143874)), + /// Allows giving on-move borrowck custom diagnostic messages for a type + (unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(150935)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), /// Allows `#[doc(masked)]`. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index b5b9da1e8e00c..a18ddff947099 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1180,13 +1180,18 @@ pub enum AttributeKind { directive: Option>, }, + /// Represents `#[diagnostic::on_move]` + OnMove { + span: Span, + directive: Option>, + }, + /// Represents `#[rustc_on_unimplemented]` and `#[diagnostic::on_unimplemented]`. OnUnimplemented { span: Span, /// None if the directive was malformed in some way. directive: Option>, }, - /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 27128f6996370..c19fc6976c6e6 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -77,6 +77,7 @@ impl AttributeKind { NoStd(..) => No, NonExhaustive(..) => Yes, // Needed for rustdoc OnConst { .. } => Yes, + OnMove { .. } => Yes, OnUnimplemented { .. } => Yes, Optimize(..) => No, PanicRuntime => No, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6c2924dfe9bd8..f9d583bdf18c7 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -637,7 +637,6 @@ fn test_codegen_options_tracking_hash() { tracked!(profile_use, Some(PathBuf::from("abc"))); tracked!(relocation_model, Some(RelocModel::Pic)); tracked!(relro_level, Some(RelroLevel::Full)); - tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 458553fa747ca..c282eb34cf4d6 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -498,6 +498,18 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { &AttributeLintKind::MissingOptionsForOnConst => { lints::MissingOptionsForOnConstAttr.into_diag(dcx, level) } + &AttributeLintKind::MalformedOnMoveAttr { span } => { + lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level) + } + &AttributeLintKind::OnMoveMalformedFormatLiterals { name } => { + lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level) + } + &AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => { + lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level) + } + &AttributeLintKind::MissingOptionsForOnMove => { + lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level) + } } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d8b62e81b0cbc..02448035216ea 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3953,6 +3953,11 @@ pub(crate) struct MissingOptionsForOnUnimplementedAttr; #[help("at least one of the `message`, `note` and `label` options are expected")] pub(crate) struct MissingOptionsForOnConstAttr; +#[derive(Diagnostic)] +#[diag("missing options for `on_move` attribute")] +#[help("at least one of the `message`, `note` and `label` options are expected")] +pub(crate) struct MissingOptionsForOnMoveAttr; + #[derive(Diagnostic)] #[diag("malformed `on_unimplemented` attribute")] #[help("only `message`, `note` and `label` are allowed as options")] @@ -3973,3 +3978,27 @@ pub(crate) struct MalformedOnConstAttrLint { #[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")] #[note("this method was used to add checks to the `Eq` derive macro")] pub(crate) struct EqInternalMethodImplemented; + +#[derive(Diagnostic)] +#[diag("unknown or malformed `on_move` attribute")] +#[help( + "only `message`, `note` and `label` are allowed as options. Their values must be string literals" +)] +pub(crate) struct MalformedOnMoveAttrLint { + #[label("invalid option found here")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("unknown parameter `{$name}`")] +#[help("expect `Self` as format argument")] +pub(crate) struct OnMoveMalformedFormatLiterals { + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag("expected a literal or missing delimiter")] +#[help( + "only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma" +)] +pub(crate) struct OnMoveMalformedAttrExpectedLiteralOrDelimiter; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1492df50a418a..ef7067b25baa3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -840,6 +840,9 @@ pub enum AttributeLintKind { MalformedOnConstAttr { span: Span, }, + MalformedOnMoveAttr { + span: Span, + }, MalformedDiagnosticFormat { warning: FormatWarning, }, @@ -855,6 +858,11 @@ pub enum AttributeLintKind { }, MissingOptionsForOnUnimplemented, MissingOptionsForOnConst, + MissingOptionsForOnMove, + OnMoveMalformedFormatLiterals { + name: Symbol, + }, + OnMoveMalformedAttrExpectedLiteralOrDelimiter, } #[derive(Debug, Clone, HashStable_Generic)] diff --git a/compiler/rustc_middle/src/query/inner.rs b/compiler/rustc_middle/src/query/inner.rs index c2525d26d4c67..402c448a1fa3a 100644 --- a/compiler/rustc_middle/src/query/inner.rs +++ b/compiler/rustc_middle/src/query/inner.rs @@ -77,23 +77,34 @@ where C: QueryCache>>, Result: Erasable, { + let convert = |value: Erased>| -> Result<(), ErrorGuaranteed> { + match erase::restore_val(value) { + Ok(_) => Ok(()), + Err(guar) => Err(guar), + } + }; + match try_get_cached(tcx, &query.cache, key) { - Some(value) => erase::restore_val(value).map(drop), - None => (query.execute_query_fn)( - tcx, - DUMMY_SP, - key, - QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, - ) - .map(erase::restore_val) - .map(|value| value.map(drop)) - // Either we actually executed the query, which means we got a full `Result`, - // or we can just assume the query succeeded, because it was green in the - // incremental cache. If it is green, that means that the previous compilation - // that wrote to the incremental cache compiles successfully. That is only - // possible if the cache entry was `Ok(())`, so we emit that here, without - // actually encoding the `Result` in the cache or loading it from there. - .unwrap_or(Ok(())), + Some(value) => convert(value), + None => { + match (query.execute_query_fn)( + tcx, + DUMMY_SP, + key, + QueryMode::Ensure { ensure_mode: EnsureMode::Ok }, + ) { + // We executed the query. Convert the successful result. + Some(res) => convert(res), + + // Reaching here means we didn't execute the query, but we can just assume the + // query succeeded, because it was green in the incremental cache. If it is green, + // that means that the previous compilation that wrote to the incremental cache + // compiles successfully. That is only possible if the cache entry was `Ok(())`, so + // we emit that here, without actually encoding the `Result` in the cache or + // loading it from there. + None => Ok(()), + } + } } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bec6ab7e83551..e495088c55649 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -74,6 +74,10 @@ struct DiagnosticOnConstOnlyForNonConstTraitImpls { item_span: Span, } +#[derive(Diagnostic)] +#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")] +struct DiagnosticOnMoveOnlyForAdt; + fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { match impl_item.kind { hir::ImplItemKind::Const(..) => Target::AssocConst, @@ -233,6 +237,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)}, Attribute::Parsed(AttributeKind::OnUnimplemented{span, directive}) => {self.check_diagnostic_on_unimplemented(*span, hir_id, target,directive.as_deref())}, Attribute::Parsed(AttributeKind::OnConst{span, ..}) => {self.check_diagnostic_on_const(*span, hir_id, target, item)} + Attribute::Parsed(AttributeKind::OnMove { span, directive }) => { + self.check_diagnostic_on_move(*span, hir_id, target, directive.as_deref()) + }, Attribute::Parsed( // tidy-alphabetical-start AttributeKind::RustcAllowIncoherentImpl(..) @@ -684,6 +691,56 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // The traits' or the impls'? } + /// Checks if `#[diagnostic::on_move]` is applied to an ADT definition + fn check_diagnostic_on_move( + &self, + attr_span: Span, + hir_id: HirId, + target: Target, + directive: Option<&Directive>, + ) { + if !matches!(target, Target::Enum | Target::Struct | Target::Union) { + self.tcx.emit_node_span_lint( + MISPLACED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + DiagnosticOnMoveOnlyForAdt, + ); + } + + if let Some(directive) = directive { + if let Node::Item(Item { + kind: + ItemKind::Struct(_, generics, _) + | ItemKind::Enum(_, generics, _) + | ItemKind::Union(_, generics, _), + .. + }) = self.tcx.hir_node(hir_id) + { + directive.visit_params(&mut |argument_name, span| { + let has_generic = generics.params.iter().any(|p| { + if !matches!(p.kind, GenericParamKind::Lifetime { .. }) + && let ParamName::Plain(name) = p.name + && name.name == argument_name + { + true + } else { + false + } + }); + if !has_generic { + self.tcx.emit_node_span_lint( + MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, + hir_id, + span, + errors::OnMoveMalformedFormatLiterals { name: argument_name }, + ) + } + }); + } + } + } + /// Checks if an `#[inline]` is applied to a function or a closure. fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) { match target { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 228f21c81b947..cf0b9afbade68 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1432,3 +1432,10 @@ pub(crate) struct UnknownFormatParameterForOnUnimplementedAttr { #[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)] pub help: bool, } + +#[derive(Diagnostic)] +#[diag("unknown parameter `{$name}`")] +#[help(r#"expect either a generic argument name or {"`{Self}`"} as format argument"#)] +pub(crate) struct OnMoveMalformedFormatLiterals { + pub name: Symbol, +} diff --git a/compiler/rustc_query_impl/src/job.rs b/compiler/rustc_query_impl/src/job.rs index 29877c8aac88f..213fc79a68434 100644 --- a/compiler/rustc_query_impl/src/job.rs +++ b/compiler/rustc_query_impl/src/job.rs @@ -155,11 +155,11 @@ fn abstracted_waiters_of(job_map: &QueryJobMap<'_>, query: QueryJobId) -> Vec( +/// the cycle. `stack` will contain just the cycle on return if detected. +fn find_cycle<'tcx>( job_map: &QueryJobMap<'tcx>, query: QueryJobId, span: Span, @@ -190,7 +190,7 @@ fn cycle_check<'tcx>( continue; }; if let ControlFlow::Break(maybe_resumable) = - cycle_check(job_map, parent, abstracted_waiter.span, stack, visited) + find_cycle(job_map, parent, abstracted_waiter.span, stack, visited) { // Return the resumable waiter in `waiter.resumable` if present return ControlFlow::Break(abstracted_waiter.resumable.or(maybe_resumable)); @@ -232,7 +232,7 @@ fn connected_to_root<'tcx>( false } -/// Looks for query cycles starting from the last query in `jobs`. +/// Looks for a query cycle using the last query in `jobs`. /// If a cycle is found, all queries in the cycle is removed from `jobs` and /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and @@ -246,7 +246,7 @@ fn remove_cycle<'tcx>( let mut stack = Vec::new(); // Look for a cycle starting with the last query in `jobs` if let ControlFlow::Break(resumable) = - cycle_check(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) + find_cycle(job_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) { // The stack is a vector of pairs of spans and queries; reverse it so that // the earlier entries require later entries diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 5aa09657a8071..6f094984ab3d1 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -560,6 +560,10 @@ pub(crate) struct ExpectedModuleFound { #[diag("cannot determine resolution for the visibility", code = E0578)] pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span); +#[derive(Diagnostic)] +#[diag("trait implementation can only be restricted to ancestor modules")] +pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span); + #[derive(Diagnostic)] #[diag("cannot use a tool module through an import")] pub(crate) struct ToolModuleImported { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 453fe9d7a8e0e..3a1d2c00fff6a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -452,6 +452,8 @@ pub(crate) enum PathSource<'a, 'ast, 'ra> { DefineOpaques, /// Resolving a macro Macro, + /// Paths for module or crate root. Used for restrictions. + Module, } impl PathSource<'_, '_, '_> { @@ -460,7 +462,8 @@ impl PathSource<'_, '_, '_> { PathSource::Type | PathSource::Trait(_) | PathSource::Struct(_) - | PathSource::DefineOpaques => TypeNS, + | PathSource::DefineOpaques + | PathSource::Module => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) @@ -485,7 +488,8 @@ impl PathSource<'_, '_, '_> { | PathSource::DefineOpaques | PathSource::Delegation | PathSource::PreciseCapturingArg(..) - | PathSource::Macro => false, + | PathSource::Macro + | PathSource::Module => false, } } @@ -528,6 +532,7 @@ impl PathSource<'_, '_, '_> { PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", PathSource::Macro => "macro", + PathSource::Module => "module", } } @@ -626,6 +631,7 @@ impl PathSource<'_, '_, '_> { ), PathSource::PreciseCapturingArg(MacroNS) => false, PathSource::Macro => matches!(res, Res::Def(DefKind::Macro(_), _)), + PathSource::Module => matches!(res, Res::Def(DefKind::Mod, _)), } } @@ -646,6 +652,12 @@ impl PathSource<'_, '_, '_> { (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, (PathSource::Macro, _) => E0425, + // FIXME: There is no dedicated error code for this case yet. + // E0577 already covers the same situation for visibilities, + // so we reuse it here for now. It may make sense to generalize + // it for restrictions in the future. + (PathSource::Module, true) => E0577, + (PathSource::Module, false) => E0433, } } } @@ -2174,7 +2186,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::Type | PathSource::PreciseCapturingArg(..) | PathSource::ReturnTypeNotation - | PathSource::Macro => false, + | PathSource::Macro + | PathSource::Module => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct(_) @@ -2800,7 +2813,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.diag_metadata.current_impl_items = None; } - ItemKind::Trait(box Trait { generics, bounds, items, .. }) => { + ItemKind::Trait(box Trait { generics, bounds, items, impl_restriction, .. }) => { + // resolve paths for `impl` restrictions + self.resolve_impl_restriction_path(impl_restriction); + // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, @@ -4389,6 +4405,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } + fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) { + match &restriction.kind { + ast::RestrictionKind::Unrestricted => (), + ast::RestrictionKind::Restricted { path, id, shorthand: _ } => { + self.smart_resolve_path(*id, &None, path, PathSource::Module); + if let Some(res) = self.r.partial_res_map[&id].full_res() + && let Some(def_id) = res.opt_def_id() + { + if !self.r.is_accessible_from( + Visibility::Restricted(def_id), + self.parent_scope.module, + ) { + self.r.dcx().create_err(errors::RestrictionAncestorOnly(path.span)).emit(); + } + } + } + } + } + // High-level and context dependent path resolution routine. // Resolves the path and records the resolution into definition map. // If resolution fails tries several techniques to find likely diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index d6c708f7a12e1..6ae9d3aaeb236 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -707,7 +707,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } const DIAG_ATTRS: &[Symbol] = - &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const]; + &[sym::on_unimplemented, sym::do_not_recommend, sym::on_const, sym::on_move]; if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index cb3f7363957ef..d1899de067b4f 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -517,17 +517,6 @@ pub(crate) struct FailedToCreateProfiler { pub(crate) err: String, } -#[derive(Diagnostic)] -#[diag("`-Csoft-float` is ignored on this target; it only has an effect on *eabihf targets")] -#[note("this may become a hard error in a future version of Rust")] -pub(crate) struct SoftFloatIgnored; - -#[derive(Diagnostic)] -#[diag("`-Csoft-float` is unsound and deprecated; use a corresponding *eabi target instead")] -#[note("it will be removed or ignored in a future version of Rust")] -#[note("see issue #129893 for more information")] -pub(crate) struct SoftFloatDeprecated; - #[derive(Diagnostic)] #[diag("unexpected `--cfg {$cfg}` flag")] #[note("config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`")] diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 98731a235d41d..1741dde90f5cf 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,5 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![feature(const_option_ops)] +#![feature(const_trait_impl)] #![feature(default_field_values)] #![feature(iter_intersperse)] #![feature(macro_derive)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5db8ed823dfe3..fb1b3c8679481 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -611,7 +611,7 @@ macro_rules! options { $parse:ident, [$dep_tracking_marker:ident $( $tmod:ident )?], $desc:expr - $(, is_deprecated_and_do_nothing: $dnn:literal )?) + $(, removed: $removed:ident )?) ),* ,) => ( #[derive(Clone)] @@ -667,7 +667,7 @@ macro_rules! options { pub const $stat: OptionDescrs<$struct_name> = &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt, - type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?, + type_desc: desc::$parse, desc: $desc, removed: None $( .or(Some(RemovedOption::$removed)) )?, tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ]; mod $optmod { @@ -705,6 +705,12 @@ macro_rules! redirect_field { type OptionSetter = fn(&mut O, v: Option<&str>) -> bool; type OptionDescrs = &'static [OptionDesc]; +/// Indicates whether a removed option should warn or error. +enum RemovedOption { + Warn, + Err, +} + pub struct OptionDesc { name: &'static str, setter: OptionSetter, @@ -712,7 +718,7 @@ pub struct OptionDesc { type_desc: &'static str, // description for option from options table desc: &'static str, - is_deprecated_and_do_nothing: bool, + removed: Option, tmod: Option, } @@ -743,18 +749,18 @@ fn build_options( let option_to_lookup = key.replace('-', "_"); match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) { - Some(OptionDesc { - name: _, - setter, - type_desc, - desc, - is_deprecated_and_do_nothing, - tmod, - }) => { - if *is_deprecated_and_do_nothing { + Some(OptionDesc { name: _, setter, type_desc, desc, removed, tmod }) => { + if let Some(removed) = removed { // deprecation works for prefixed options only assert!(!prefix.is_empty()); - early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}")); + match removed { + RemovedOption::Warn => { + early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}")) + } + RemovedOption::Err => { + early_dcx.early_fatal(format!("`-{prefix} {key}`: {desc}")) + } + } } if !setter(&mut op, value) { match value { @@ -783,6 +789,7 @@ fn build_options( #[allow(non_upper_case_globals)] mod desc { + pub(crate) const parse_ignore: &str = ""; // should not be user-visible pub(crate) const parse_no_value: &str = "no value"; pub(crate) const parse_bool: &str = "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`"; @@ -889,6 +896,12 @@ pub mod parse { pub(crate) use super::*; pub(crate) const MAX_THREADS_CAP: usize = 256; + /// Ignore the value. Used for removed options where we don't actually want to store + /// anything in the session. + pub(crate) fn parse_ignore(_slot: &mut (), _v: Option<&str>) -> bool { + true + } + /// This is for boolean options that don't take a value, and are true simply /// by existing on the command-line. /// @@ -2059,7 +2072,7 @@ options! { #[rustc_lint_opt_deny_field_access("documented to do nothing")] ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing", - is_deprecated_and_do_nothing: true), + removed: Warn), #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")] code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), @@ -2098,7 +2111,7 @@ options! { inline_threshold: Option = (None, parse_opt_number, [UNTRACKED], "this option is deprecated and does nothing \ (consider using `-Cllvm-args=--inline-threshold=...`)", - is_deprecated_and_do_nothing: true), + removed: Warn), #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage reports \ @@ -2139,7 +2152,7 @@ options! { #[rustc_lint_opt_deny_field_access("documented to do nothing")] no_stack_check: bool = (false, parse_no_value, [UNTRACKED], "this option is deprecated and does nothing", - is_deprecated_and_do_nothing: true), + removed: Warn), no_vectorize_loops: bool = (false, parse_no_value, [TRACKED], "disable loop vectorization optimization passes"), no_vectorize_slp: bool = (false, parse_no_value, [TRACKED], @@ -2173,8 +2186,11 @@ options! { "set rpath values in libs/exes (default: no)"), save_temps: bool = (false, parse_bool, [UNTRACKED], "save all temporary output files during compilation (default: no)"), - soft_float: bool = (false, parse_bool, [TRACKED], - "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"), + #[rustc_lint_opt_deny_field_access("documented to do nothing")] + soft_float: () = ((), parse_ignore, [UNTRACKED], + "this option has been removed \ + (use a corresponding *eabi target instead)", + removed: Err), #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), @@ -2240,7 +2256,7 @@ options! { (default: no)"), box_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for box (default: yes)"), - branch_protection: Option = (None, parse_branch_protection, [TRACKED], + branch_protection: Option = (None, parse_branch_protection, [TRACKED TARGET_MODIFIER], "set options for branch target identification and pointer authentication on AArch64"), build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], "whether the stable interface is being built"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 8290bdf91a030..fece46dd9711d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1360,16 +1360,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } } - - if sess.opts.cg.soft_float { - if sess.target.arch == Arch::Arm { - sess.dcx().emit_warn(errors::SoftFloatDeprecated); - } else { - // All `use_softfp` does is the equivalent of `-mfloat-abi` in GCC/clang, which only exists on ARM targets. - // We document this flag to only affect `*eabihf` targets, so let's show a warning for all other targets. - sess.dcx().emit_warn(errors::SoftFloatIgnored); - } - } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 286fea7d90505..738c9b975fd00 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -797,6 +797,7 @@ symbols! { diagnostic, diagnostic_namespace, diagnostic_on_const, + diagnostic_on_move, dialect, direct, discriminant_kind, @@ -1407,6 +1408,7 @@ symbols! { omit_gdb_pretty_printer_section, on, on_const, + on_move, on_unimplemented, opaque, opaque_generic_const_args, diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 10c53c881a362..b00f9eebb8266 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" -derive-where = "1.2.7" +derive-where = "1.6.1" ena = "0.14.4" indexmap = "2.0.0" rustc-hash = "2.0.0" diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index fc8b39f7c01f0..0b0f0fd2f4249 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -26,11 +26,7 @@ use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex}; /// for more details. /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, T)] #[derive(GenericTypeVisitable)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Binder { @@ -365,12 +361,7 @@ impl TypeVisitor for ValidateBoundVars { /// `instantiate`. /// /// See for more details. -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Ord; I: Interner, T: Ord)] -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, PartialOrd, PartialEq, Hash, Debug; I: Interner, T)] +#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Hash, Debug; I: Interner, T)] #[derive(GenericTypeVisitable)] #[cfg_attr( feature = "nightly", @@ -964,12 +955,7 @@ pub enum BoundVarIndexKind { /// The "placeholder index" fully defines a placeholder region, type, or const. Placeholders are /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one -// FIXME(derive-where#136): Need to use separate `derive_where` for -// `Copy` and `Ord` to prevent the emitted `Clone` and `PartialOrd` -// impls from incorrectly relying on `T: Copy` and `T: Ord`. -#[derive_where(Ord; I: Interner, T: Ord)] -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Clone, PartialOrd, PartialEq, Eq, Hash; I: Interner, T)] +#[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 164c27464c607..35f93d8fb33b2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,8 +107,6 @@ #![feature(core_intrinsics)] #![feature(coverage_attribute)] #![feature(disjoint_bitor)] -#![feature(internal_impls_macro)] -#![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] #![feature(pattern_type_macro)] @@ -144,6 +142,7 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(link_cfg)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index becac514284e3..c79e8fc4060c1 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -52,9 +52,6 @@ use crate::pin::UnsafePinned; /// u32, /// } /// ``` -#[unstable(feature = "internal_impls_macro", issue = "none")] -// Allow implementations of `UnsizedConstParamTy` even though std cannot use that feature. -#[allow_internal_unstable(const_param_ty_trait)] macro marker_impls { ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6fcb28edc7d84..c8c8a6c897142 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -275,9 +275,7 @@ #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] -#![feature(const_default)] #![feature(const_trait_impl)] -#![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] @@ -287,16 +285,11 @@ #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] -#![feature(formatting_options)] -#![feature(funnel_shifts)] #![feature(intra_doc_pointers)] -#![feature(iter_advance_by)] -#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(link_cfg)] #![feature(linkage)] #![feature(macro_metavar_expr_concat)] -#![feature(maybe_uninit_fill)] #![feature(min_specialization)] #![feature(must_not_suspend)] #![feature(needs_panic_runtime)] @@ -314,7 +307,6 @@ #![feature(try_blocks)] #![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] -#![feature(uint_carryless_mul)] // tidy-alphabetical-end // // Library features (core): @@ -325,6 +317,8 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(const_convert)] +#![feature(const_default)] +#![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(cstr_display)] @@ -340,13 +334,18 @@ #![feature(float_minimum_maximum)] #![feature(fmt_internals)] #![feature(fn_ptr_trait)] +#![feature(formatting_options)] +#![feature(funnel_shifts)] #![feature(generic_atomic)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(hint_must_use)] #![feature(int_from_ascii)] #![feature(ip)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(maybe_uninit_array_assume_init)] +#![feature(maybe_uninit_fill)] #![feature(panic_can_unwind)] #![feature(panic_internals)] #![feature(pin_coerce_unsized_trait)] @@ -364,6 +363,7 @@ #![feature(sync_unsafe_cell)] #![feature(temporary_niche_types)] #![feature(ub_checks)] +#![feature(uint_carryless_mul)] #![feature(used_with_arg)] // tidy-alphabetical-end // diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index b264c961b6593..f9b0d2dbb2095 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -7,6 +7,7 @@ //! relevant to command execution in the bootstrap process. This includes settings such as //! dry-run mode, verbosity level, and failure behavior. +use std::backtrace::{Backtrace, BacktraceStatus}; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Formatter}; @@ -930,6 +931,16 @@ Executed at: {executed_at}"#, if stderr.captures() { writeln!(error_message, "\n--- STDERR vvv\n{}", output.stderr().trim()).unwrap(); } + let backtrace = if exec_ctx.verbosity > 1 { + Backtrace::force_capture() + } else if matches!(command.failure_behavior, BehaviorOnFailure::Ignore) { + Backtrace::disabled() + } else { + Backtrace::capture() + }; + if matches!(backtrace.status(), BacktraceStatus::Captured) { + writeln!(error_message, "\n--- BACKTRACE vvv\n{backtrace}").unwrap(); + } match command.failure_behavior { BehaviorOnFailure::DelayFail => { diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 40dfdb890d66f..a1578ab40209a 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -79,8 +79,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ProvidedAssocConstItem(..) | clean::ImplAssocConstItem(..) | clean::RequiredAssocTypeItem(..) - // check for trait impl - | clean::ImplItem(box clean::Impl { trait_: Some(_), .. }) + | clean::ImplItem(_) ) { return false; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 112a0519016a3..f382502c7068b 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1475,7 +1475,6 @@ ui/lint/issue-97094.rs ui/lint/issue-99387.rs ui/lint/let_underscore/issue-119696-err-on-fn.rs ui/lint/let_underscore/issue-119697-extra-let.rs -ui/lint/must_not_suspend/issue-89562.rs ui/lint/unused/issue-103320-must-use-ops.rs ui/lint/unused/issue-104397.rs ui/lint/unused/issue-105061-array-lint.rs diff --git a/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs index 860ecc3cfcd04..430d4a59da6df 100644 --- a/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs +++ b/tests/assembly-llvm/naked-functions/aarch64-naked-fn-no-bti-prolog.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti +//@ compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti -Cunsafe-allow-abi-mismatch=branch-protection //@ assembly-output: emit-asm //@ needs-asm-support //@ only-aarch64 diff --git a/tests/pretty/float-trailing-dot.rs b/tests/pretty/float-trailing-dot.rs new file mode 100644 index 0000000000000..63934bb8eaaa7 --- /dev/null +++ b/tests/pretty/float-trailing-dot.rs @@ -0,0 +1,8 @@ +//@ pp-exact + +fn main() { + let _ = 0. ..45.; + let _ = 0. ..=360.; + let _ = 0. ..; + let _ = 0. .to_string(); +} diff --git a/tests/pretty/macro-fragment-specifier-whitespace.pp b/tests/pretty/macro-fragment-specifier-whitespace.pp new file mode 100644 index 0000000000000..ee5a0f7a7c056 --- /dev/null +++ b/tests/pretty/macro-fragment-specifier-whitespace.pp @@ -0,0 +1,24 @@ +#![feature(prelude_import)] +#![no_std] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; +//@ pretty-mode:expanded +//@ pp-exact:macro-fragment-specifier-whitespace.pp + +// Test that fragment specifier names in macro definitions are properly +// separated from the following keyword/identifier token when pretty-printed. +// This is a regression test for a bug where `$x:ident` followed by `where` +// was pretty-printed as `$x:identwhere` (an invalid fragment specifier). + +macro_rules! outer { + ($d:tt $($params:tt)*) => + { + #[macro_export] macro_rules! inner + { ($($params)* where $d($rest:tt)*) => {}; } + }; +} +#[macro_export] +macro_rules! inner { ($x:ident where $ ($rest : tt)*) => {}; } + +fn main() {} diff --git a/tests/pretty/macro-fragment-specifier-whitespace.rs b/tests/pretty/macro-fragment-specifier-whitespace.rs new file mode 100644 index 0000000000000..54c6debd9a275 --- /dev/null +++ b/tests/pretty/macro-fragment-specifier-whitespace.rs @@ -0,0 +1,19 @@ +//@ pretty-mode:expanded +//@ pp-exact:macro-fragment-specifier-whitespace.pp + +// Test that fragment specifier names in macro definitions are properly +// separated from the following keyword/identifier token when pretty-printed. +// This is a regression test for a bug where `$x:ident` followed by `where` +// was pretty-printed as `$x:identwhere` (an invalid fragment specifier). + +macro_rules! outer { + ($d:tt $($params:tt)*) => { + #[macro_export] + macro_rules! inner { + ($($params)* where $d($rest:tt)*) => {}; + } + }; +} +outer!($ $x:ident); + +fn main() {} diff --git a/tests/pretty/use-self-braces.rs b/tests/pretty/use-self-braces.rs new file mode 100644 index 0000000000000..8db2568943616 --- /dev/null +++ b/tests/pretty/use-self-braces.rs @@ -0,0 +1,10 @@ +//@ pp-exact +//@ edition:2021 + +#![allow(unused_imports)] + +// Braces around `self` must be preserved, because `use foo::self` is not valid Rust. +use std::io::{self}; +use std::fmt::{self, Debug}; + +fn main() {} diff --git a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs index 2ac5fdee063c2..1d06fe118e067 100644 --- a/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c-lto-clang/rmake.rs @@ -32,6 +32,7 @@ fn main() { .opt_level("2") .linker(&env_var("CLANG")) .link_arg("-fuse-ld=lld") + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") .input("test.rs") .output("test.bin") diff --git a/tests/run-make/pointer-auth-link-with-c/rmake.rs b/tests/run-make/pointer-auth-link-with-c/rmake.rs index 1ddcb79d64ff4..1ac68c95559c6 100644 --- a/tests/run-make/pointer-auth-link-with-c/rmake.rs +++ b/tests/run-make/pointer-auth-link-with-c/rmake.rs @@ -15,7 +15,11 @@ use run_make_support::{build_native_static_lib, cc, is_windows_msvc, llvm_ar, ru fn main() { build_native_static_lib("test"); - rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); + rustc() + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") + .input("test.rs") + .run(); run("test"); cc().arg("-v") .arg("-c") @@ -25,7 +29,11 @@ fn main() { .run(); let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - rustc().arg("-Zbranch-protection=bti,gcs,pac-ret,leaf").input("test.rs").run(); + rustc() + .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + .arg("-Zbranch-protection=bti,gcs,pac-ret,leaf") + .input("test.rs") + .run(); run("test"); // FIXME: +pc was only recently added to LLVM @@ -37,6 +45,10 @@ fn main() { // .run(); // let obj_file = if is_windows_msvc() { "test.obj" } else { "test" }; // llvm_ar().obj_to_ar().output_input("libtest.a", &obj_file).run(); - // rustc().arg("-Zbranch-protection=bti,pac-ret,pc,leaf").input("test.rs").run(); + // rustc() + // .arg("-Cunsafe-allow-abi-mismatch=branch-protection") + // .arg("-Zbranch-protection=bti,pac-ret,pc,leaf") + // .input("test.rs") + // .run(); // run("test"); } diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs index 8e5c31d50edc7..731d19bffec52 100644 --- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs +++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.rs @@ -78,7 +78,11 @@ impl Clone for Struct { } } - +impl Struct { // No doc or code example and it's fine! + pub fn bar() {} + //~^ ERROR missing code example in this documentation + //~| ERROR missing documentation for an associated function +} /// doc /// diff --git a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr index 22533b9816a74..6382c5926e8fc 100644 --- a/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr +++ b/tests/rustdoc-ui/lints/lint-missing-doc-code-example.stderr @@ -1,3 +1,15 @@ +error: missing documentation for an associated function + --> $DIR/lint-missing-doc-code-example.rs:82:5 + | +LL | pub fn bar() {} + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-missing-doc-code-example.rs:2:9 + | +LL | #![deny(missing_docs)] + | ^^^^^^^^^^^^ + error: missing code example in this documentation --> $DIR/lint-missing-doc-code-example.rs:38:3 | @@ -28,5 +40,11 @@ error: missing code example in this documentation LL | /// Doc | ^^^^^^^ -error: aborting due to 4 previous errors +error: missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:82:5 + | +LL | pub fn bar() {} + | ^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs b/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs new file mode 100644 index 0000000000000..05505206b7139 --- /dev/null +++ b/tests/ui/async-await/async-closures/unifying-function-types-involving-hrtb.rs @@ -0,0 +1,33 @@ +//! Regresssion test for . + +//@ edition:2018 +//@ check-pass + +use std::future::Future; + +trait Foo<'a> { + type Future: Future + 'a; + + fn start(self, f: &'a u8) -> Self::Future; +} + +impl<'a, Fn, Fut> Foo<'a> for Fn +where + Fn: FnOnce(&'a u8) -> Fut, + Fut: Future + 'a, +{ + type Future = Fut; + + fn start(self, f: &'a u8) -> Self::Future { (self)(f) } +} + +fn foo(f: F) where F: for<'a> Foo<'a> { + let bar = 5; + f.start(&bar); +} + +fn main() { + foo(async move | f: &u8 | { *f }); + + foo({ async fn baz(f: &u8) -> u8 { *f } baz }); +} diff --git a/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs new file mode 100644 index 0000000000000..6cff8f4a19b52 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/auxiliary/other.rs @@ -0,0 +1,8 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +#[derive(Debug)] +pub struct Foo; diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs new file mode 100644 index 0000000000000..69c61e62cfc60 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.rs @@ -0,0 +1,14 @@ +//@ aux-build:other.rs + +extern crate other; + +use other::Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr new file mode 100644 index 0000000000000..8cfe8d6af3f6c --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/error_is_shown_in_downstream_crates.stderr @@ -0,0 +1,21 @@ +error[E0382]: Foo + --> $DIR/error_is_shown_in_downstream_crates.rs:12:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/error_is_shown_in_downstream_crates.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs new file mode 100644 index 0000000000000..e6112e783bd19 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.rs @@ -0,0 +1,17 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr new file mode 100644 index 0000000000000..483ff5a407bba --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_simple.stderr @@ -0,0 +1,29 @@ +error[E0382]: Foo + --> $DIR/on_move_simple.rs:15:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_simple.rs:10:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/on_move_simple.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs new file mode 100644 index 0000000000000..f2025c2b2271b --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.rs @@ -0,0 +1,32 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo for {Self}", + label = "Bar for {Self}", +)] +#[derive(Debug)] +struct Foo; + +#[diagnostic::on_move( + message="Foo for {X}", + label="Bar for {X}", +)] +struct MyType { + _x: X, +} + +fn takes_foo(_: Foo) {} + +fn takes_mytype(_: MyType) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo for Foo + + let mytype = MyType { _x: 0 }; + takes_mytype(mytype); + let baz = mytype; + //~^ERROR Foo for i32 +} diff --git a/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr new file mode 100644 index 0000000000000..6868f1571be8f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/on_move_with_format.stderr @@ -0,0 +1,55 @@ +error[E0382]: Foo for Foo + --> $DIR/on_move_with_format.rs:25:15 + | +LL | let foo = Foo; + | --- Bar for Foo +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_with_format.rs:18:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/on_move_with_format.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error[E0382]: Foo for i32 + --> $DIR/on_move_with_format.rs:30:15 + | +LL | let mytype = MyType { _x: 0 }; + | ------ Bar for i32 +LL | takes_mytype(mytype); + | ------ value moved here +LL | let baz = mytype; + | ^^^^^^ value used here after move + | +note: consider changing this parameter type in function `takes_mytype` to borrow instead if owning the value isn't necessary + --> $DIR/on_move_with_format.rs:20:23 + | +LL | fn takes_mytype(_: MyType) {} + | ------------ ^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +note: if `MyType` implemented `Clone`, you could clone the value + --> $DIR/on_move_with_format.rs:14:1 + | +LL | struct MyType { + | ^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_mytype(mytype); + | ------ you could clone this value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs new file mode 100644 index 0000000000000..1af3daf0f3152 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.rs @@ -0,0 +1,22 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "first message", + label = "first label", +)] +#[diagnostic::on_move( + message = "second message", + //~^ WARN `message` is ignored due to previous definition of `message` [malformed_diagnostic_attributes] + label = "second label", + //~^ WARN `label` is ignored due to previous definition of `label` [malformed_diagnostic_attributes] +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR first message +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr new file mode 100644 index 0000000000000..f02f970149819 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_duplicated_options.stderr @@ -0,0 +1,49 @@ +warning: `message` is ignored due to previous definition of `message` + --> $DIR/report_warning_on_duplicated_options.rs:8:5 + | +LL | message = "first message", + | ------------------------- `message` is first declared here +... +LL | message = "second message", + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `message` is later redundantly declared here + | + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +warning: `label` is ignored due to previous definition of `label` + --> $DIR/report_warning_on_duplicated_options.rs:10:5 + | +LL | label = "first label", + | --------------------- `label` is first declared here +... +LL | label = "second label", + | ^^^^^^^^^^^^^^^^^^^^^^ `label` is later redundantly declared here + +error[E0382]: first message + --> $DIR/report_warning_on_duplicated_options.rs:20:15 + | +LL | let foo = Foo; + | --- first label +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_duplicated_options.rs:15:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_duplicated_options.rs:13:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs new file mode 100644 index 0000000000000..f403ad1ff480f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo {Baz}", + //~^WARN unknown parameter `Baz` + label = "Bar", +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr new file mode 100644 index 0000000000000..efb43c3562a4b --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_formats.stderr @@ -0,0 +1,38 @@ +warning: unknown parameter `Baz` + --> $DIR/report_warning_on_invalid_formats.rs:4:21 + | +LL | message = "Foo {Baz}", + | ^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + = note: `#[warn(malformed_diagnostic_format_literals)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo {Baz} + --> $DIR/report_warning_on_invalid_formats.rs:16:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_invalid_formats.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_invalid_formats.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs new file mode 100644 index 0000000000000..2050403210d58 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.rs @@ -0,0 +1,14 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move = "foo"] +//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr new file mode 100644 index 0000000000000..39992b02e5804 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_invalid_meta_item_syntax.stderr @@ -0,0 +1,38 @@ +warning: missing options for `on_move` attribute + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:3:1 + | +LL | #[diagnostic::on_move = "foo"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:12:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_invalid_meta_item_syntax.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs new file mode 100644 index 0000000000000..b5bb103d3f27e --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( +//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes] +//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + message = "Foo" + label = "Bar", +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr new file mode 100644 index 0000000000000..00d0657bfcbd5 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_delimiters.stderr @@ -0,0 +1,44 @@ +warning: expected a literal or missing delimiter + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:3:22 + | +LL | #[diagnostic::on_move( + | ______________________^ +LL | | +LL | | +LL | | message = "Foo" +LL | | label = "Bar", +LL | | )] + | |_^ + | + = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_malformed_options_without_delimiters.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs new file mode 100644 index 0000000000000..c676b87ad8570 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.rs @@ -0,0 +1,18 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( +//~^ WARN expected a literal or missing delimiter [malformed_diagnostic_attributes] +//~| HELP only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + message = Foo, + label = "Bar", +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr new file mode 100644 index 0000000000000..6dc230b68c5fe --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_malformed_options_without_literals.stderr @@ -0,0 +1,44 @@ +warning: expected a literal or missing delimiter + --> $DIR/report_warning_on_malformed_options_without_literals.rs:3:22 + | +LL | #[diagnostic::on_move( + | ______________________^ +LL | | +LL | | +LL | | message = Foo, +LL | | label = "Bar", +LL | | )] + | |_^ + | + = help: only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_malformed_options_without_literals.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_malformed_options_without_literals.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_malformed_options_without_literals.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs new file mode 100644 index 0000000000000..e5603fd24ec98 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.rs @@ -0,0 +1,14 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move] +//~^WARN missing options for `on_move` attribute [malformed_diagnostic_attributes] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr new file mode 100644 index 0000000000000..f4e6d69faecb9 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_missing_options.stderr @@ -0,0 +1,38 @@ +warning: missing options for `on_move` attribute + --> $DIR/report_warning_on_missing_options.rs:3:1 + | +LL | #[diagnostic::on_move] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: use of moved value: `foo` + --> $DIR/report_warning_on_missing_options.rs:12:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_missing_options.rs:7:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_missing_options.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs new file mode 100644 index 0000000000000..33e78ea5fc1fe --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.rs @@ -0,0 +1,23 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", +)] +struct Foo; + +#[diagnostic::on_move( +//~^WARN `#[diagnostic::on_move]` can only be applied to enums, structs or unions + message = "Foo", + label = "Bar", +)] +trait MyTrait {} + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr new file mode 100644 index 0000000000000..29c987fba48f1 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_non_adt.stderr @@ -0,0 +1,41 @@ +warning: `#[diagnostic::on_move]` can only be applied to enums, structs or unions + --> $DIR/report_warning_on_non_adt.rs:9:1 + | +LL | / #[diagnostic::on_move( +LL | | +LL | | message = "Foo", +LL | | label = "Bar", +LL | | )] + | |__^ + | + = note: `#[warn(misplaced_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo + --> $DIR/report_warning_on_non_adt.rs:21:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_non_adt.rs:16:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_non_adt.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs new file mode 100644 index 0000000000000..651f6184cfac6 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.rs @@ -0,0 +1,19 @@ +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move( + message = "Foo", + label = "Bar", + baz="Baz" + //~^WARN unknown or malformed `on_move` attribute + //~|HELP only `message`, `note` and `label` are allowed as options. Their values must be string literals +)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR Foo +} diff --git a/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr new file mode 100644 index 0000000000000..a09b8a96d2d12 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/report_warning_on_unknown_options.stderr @@ -0,0 +1,38 @@ +warning: unknown or malformed `on_move` attribute + --> $DIR/report_warning_on_unknown_options.rs:6:5 + | +LL | baz="Baz" + | ^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options. Their values must be string literals + = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default + +error[E0382]: Foo + --> $DIR/report_warning_on_unknown_options.rs:17:15 + | +LL | let foo = Foo; + | --- Bar +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/report_warning_on_unknown_options.rs:12:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/report_warning_on_unknown_options.rs:10:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs new file mode 100644 index 0000000000000..a1f3b1fbbc860 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.rs @@ -0,0 +1,18 @@ +//! This is an unusual feature gate test, as it doesn't test the feature +//! gate, but the fact that not adding the feature gate will cause the +//! diagnostic to not emit the custom diagnostic message +//! +#[diagnostic::on_move( + message = "Foo" +)] +#[derive(Debug)] +struct Foo; + +fn takes_foo(_: Foo) {} + +fn main() { + let foo = Foo; + takes_foo(foo); + let bar = foo; + //~^ERROR use of moved value: `foo` +} diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr new file mode 100644 index 0000000000000..9ba6f272cf92b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr @@ -0,0 +1,29 @@ +error[E0382]: use of moved value: `foo` + --> $DIR/feature-gate-diagnostic-on-move.rs:16:15 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | takes_foo(foo); + | --- value moved here +LL | let bar = foo; + | ^^^ value used here after move + | +note: consider changing this parameter type in function `takes_foo` to borrow instead if owning the value isn't necessary + --> $DIR/feature-gate-diagnostic-on-move.rs:11:17 + | +LL | fn takes_foo(_: Foo) {} + | --------- ^^^ this parameter takes ownership of the value + | | + | in this function +note: if `Foo` implemented `Clone`, you could clone the value + --> $DIR/feature-gate-diagnostic-on-move.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^ consider implementing `Clone` for this type +... +LL | takes_foo(foo); + | --- you could clone this value + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.rs b/tests/ui/impl-restriction/restriction_resolution_errors.rs new file mode 100644 index 0000000000000..b36f2cf9bdfba --- /dev/null +++ b/tests/ui/impl-restriction/restriction_resolution_errors.rs @@ -0,0 +1,85 @@ +#![feature(impl_restriction)] +#![expect(incomplete_features)] + +pub mod a { + pub enum E {} + pub mod d {} + pub mod b { + pub mod c {} + + // We do not use crate-relative paths here, since we follow the + // "uniform paths" approach used for type/expression paths. + pub impl(in a::b) trait T1 {} //~ ERROR cannot find module or crate `a` in this scope [E0433] + + pub impl(in ::std) trait T2 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in self::c) trait T3 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in super::d) trait T4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in crate::c) trait T5 {} //~ ERROR cannot find module `c` in the crate root [E0433] + + pub impl(in super::E) trait T6 {} //~ ERROR expected module, found enum `super::E` [E0577] + + pub impl(in super::super::super) trait T7 {} //~ ERROR too many leading `super` keywords [E0433] + + // OK paths + pub impl(crate) trait T8 {} + pub impl(self) trait T9 {} + pub impl(super) trait T10 {} + pub impl(in crate::a) trait T11 {} + pub impl(in super::super) trait T12 {} + + // Check if we can resolve paths referring to modules declared later. + pub impl(in self::f) trait L1 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub impl(in super::G) trait L2 {} //~ ERROR expected module, found enum `super::G` [E0577] + + pub impl(in super::h) trait L3 {} //~ ERROR trait implementation can only be restricted to ancestor modules + + pub mod f {} + } + + pub enum G {} + pub mod h {} +} + +pub impl(in crate::a) trait T13 {} //~ ERROR trait implementation can only be restricted to ancestor modules + +pub impl(in crate::a::E) trait T14 {} //~ ERROR expected module, found enum `crate::a::E` [E0577] + +pub impl(crate) trait T15 {} +pub impl(self) trait T16 {} + +pub impl(super) trait T17 {} //~ ERROR too many leading `super` keywords [E0433] + +// Check if we can resolve paths referring to modules declared later. +pub impl(in crate::j) trait L4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + +pub impl(in crate::I) trait L5 {} //~ ERROR expected module, found enum `crate::I` [E0577] + +pub enum I {} +pub mod j {} + +// Check if we can resolve `use`d paths. +mod m1 { + pub impl(in crate::m2) trait U1 {} // OK +} + +use m1 as m2; + +mod m3 { + mod m4 { + pub impl(in crate::m2) trait U2 {} //~ ERROR trait implementation can only be restricted to ancestor modules + pub impl(in m6) trait U3 {} // OK + pub impl(in m6::m5) trait U4 {} //~ ERROR trait implementation can only be restricted to ancestor modules + pub impl(in m7) trait U5 {} //~ ERROR expected module, found enum `m7` [E0577] + + use crate::m3 as m6; + use crate::m3::E as m7; + } + mod m5 {} + pub enum E {} +} + +fn main() {} diff --git a/tests/ui/impl-restriction/restriction_resolution_errors.stderr b/tests/ui/impl-restriction/restriction_resolution_errors.stderr new file mode 100644 index 0000000000000..540803285c1b5 --- /dev/null +++ b/tests/ui/impl-restriction/restriction_resolution_errors.stderr @@ -0,0 +1,140 @@ +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:14:21 + | +LL | pub impl(in ::std) trait T2 {} + | ^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:16:21 + | +LL | pub impl(in self::c) trait T3 {} + | ^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:18:21 + | +LL | pub impl(in super::d) trait T4 {} + | ^^^^^^^^ + +error[E0433]: too many leading `super` keywords + --> $DIR/restriction_resolution_errors.rs:24:35 + | +LL | pub impl(in super::super::super) trait T7 {} + | ^^^^^ there are too many leading `super` keywords + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:34:21 + | +LL | pub impl(in self::f) trait L1 {} + | ^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:38:21 + | +LL | pub impl(in super::h) trait L3 {} + | ^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:47:13 + | +LL | pub impl(in crate::a) trait T13 {} + | ^^^^^^^^ + +error[E0433]: too many leading `super` keywords + --> $DIR/restriction_resolution_errors.rs:54:10 + | +LL | pub impl(super) trait T17 {} + | ^^^^^ there are too many leading `super` keywords + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:57:13 + | +LL | pub impl(in crate::j) trait L4 {} + | ^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:73:21 + | +LL | pub impl(in crate::m2) trait U2 {} + | ^^^^^^^^^ + +error: trait implementation can only be restricted to ancestor modules + --> $DIR/restriction_resolution_errors.rs:75:21 + | +LL | pub impl(in m6::m5) trait U4 {} + | ^^^^^^ + +error[E0433]: cannot find module or crate `a` in this scope + --> $DIR/restriction_resolution_errors.rs:12:21 + | +LL | pub impl(in a::b) trait T1 {} + | ^ use of unresolved module or unlinked crate `a` + | +help: there is a crate or module with a similar name + | +LL - pub impl(in a::b) trait T1 {} +LL + pub impl(in c::b) trait T1 {} + | +help: consider importing this module + | +LL + use a; + | + +error[E0433]: cannot find module `c` in the crate root + --> $DIR/restriction_resolution_errors.rs:20:28 + | +LL | pub impl(in crate::c) trait T5 {} + | ^ not found in the crate root + +error[E0577]: expected module, found enum `super::E` + --> $DIR/restriction_resolution_errors.rs:22:21 + | +LL | pub impl(in super::E) trait T6 {} + | ^^^^^^^^ not a module + +error[E0577]: expected module, found enum `super::G` + --> $DIR/restriction_resolution_errors.rs:36:21 + | +LL | pub impl(in super::G) trait L2 {} + | ^^^^^^^^ not a module + +error[E0577]: expected module, found enum `crate::a::E` + --> $DIR/restriction_resolution_errors.rs:49:13 + | +LL | pub mod b { + | --------- similarly named module `b` defined here +... +LL | pub impl(in crate::a::E) trait T14 {} + | ^^^^^^^^^^^ + | +help: a module with a similar name exists + | +LL - pub impl(in crate::a::E) trait T14 {} +LL + pub impl(in crate::a::b) trait T14 {} + | + +error[E0577]: expected module, found enum `crate::I` + --> $DIR/restriction_resolution_errors.rs:59:13 + | +LL | pub mod a { + | --------- similarly named module `a` defined here +... +LL | pub impl(in crate::I) trait L5 {} + | ^^^^^^^^ + | +help: a module with a similar name exists + | +LL - pub impl(in crate::I) trait L5 {} +LL + pub impl(in crate::a) trait L5 {} + | + +error[E0577]: expected module, found enum `m7` + --> $DIR/restriction_resolution_errors.rs:76:21 + | +LL | pub impl(in m7) trait U5 {} + | ^^ not a module + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0433, E0577. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/lint/must_not_suspend/issue-89562.rs b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs similarity index 67% rename from tests/ui/lint/must_not_suspend/issue-89562.rs rename to tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs index 99a548130720f..d1c48c3c51457 100644 --- a/tests/ui/lint/must_not_suspend/issue-89562.rs +++ b/tests/ui/lint/must_not_suspend/mutex-guard-dropped-before-await.rs @@ -1,9 +1,13 @@ +//! Regression test for + //@ edition:2018 //@ run-pass +#![feature(must_not_suspend)] +#![deny(must_not_suspend)] + use std::sync::Mutex; -// Copied from the issue. Allow-by-default for now, so run-pass pub async fn foo() { let foo = Mutex::new(1); let lock = foo.lock().unwrap();