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_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 39e886227d946..18e03d94a997f 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -470,6 +470,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 e8476c3d8c73b..deb22fcaa269a 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_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_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 7c7698ac3bb8e..de3b2e96f6ddd 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1434,3 +1434,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_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 551d89ee6022a..54bca9be57650 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_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 257ac3f51c2c1..1e59ff33f8dc8 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, @@ -1406,6 +1407,7 @@ symbols! { omit_gdb_pretty_printer_section, on, on_const, + on_move, on_unimplemented, opaque, opaque_generic_const_args, 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`.