@@ -6,12 +6,16 @@ use std::ops::ControlFlow;
66use either:: Either ;
77use hir:: { ClosureKind , Path } ;
88use rustc_data_structures:: fx:: FxIndexSet ;
9+ use rustc_data_structures:: thin_vec:: ThinVec ;
910use rustc_errors:: codes:: * ;
1011use rustc_errors:: { Applicability , Diag , MultiSpan , struct_span_code_err} ;
1112use rustc_hir as hir;
13+ use rustc_hir:: attrs:: diagnostic:: FormatArgs ;
1214use rustc_hir:: def:: { DefKind , Res } ;
1315use rustc_hir:: intravisit:: { Visitor , walk_block, walk_expr} ;
14- use rustc_hir:: { CoroutineDesugaring , CoroutineKind , CoroutineSource , LangItem , PatField } ;
16+ use rustc_hir:: {
17+ CoroutineDesugaring , CoroutineKind , CoroutineSource , LangItem , PatField , find_attr,
18+ } ;
1519use rustc_middle:: bug;
1620use rustc_middle:: hir:: nested_filter:: OnlyBodies ;
1721use rustc_middle:: mir:: {
@@ -138,6 +142,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
138142 let partial_str = if is_partial_move { "partial " } else { "" } ;
139143 let partially_str = if is_partial_move { "partially " } else { "" } ;
140144
145+ let ( on_move_message, on_move_label, on_move_notes) = if let ty:: Adt ( item_def, args) =
146+ self . body . local_decls [ moved_place. local ] . ty . kind ( )
147+ && let Some ( Some ( directive) ) = find_attr ! ( self . infcx. tcx, item_def. did( ) , OnMove { directive, .. } => directive)
148+ {
149+ let item_name = self . infcx . tcx . item_name ( item_def. did ( ) ) . to_string ( ) ;
150+ let mut generic_args: Vec < _ > = self
151+ . infcx
152+ . tcx
153+ . generics_of ( item_def. did ( ) )
154+ . own_params
155+ . iter ( )
156+ . filter_map ( |param| Some ( ( param. name , args[ param. index as usize ] . to_string ( ) ) ) )
157+ . collect ( ) ;
158+ generic_args. push ( ( kw:: SelfUpper , item_name) ) ;
159+
160+ let args = FormatArgs {
161+ this : String :: new ( ) ,
162+ trait_sugared : String :: new ( ) ,
163+ item_context : "" ,
164+ generic_args,
165+ } ;
166+ (
167+ directive. message . as_ref ( ) . map ( |e| e. 1 . format ( & args) ) ,
168+ directive. label . as_ref ( ) . map ( |e| e. 1 . format ( & args) ) ,
169+ directive. notes . iter ( ) . map ( |e| e. format ( & args) ) . collect ( ) ,
170+ )
171+ } else {
172+ ( None , None , ThinVec :: new ( ) )
173+ } ;
174+
141175 let mut err = self . cannot_act_on_moved_value (
142176 span,
143177 desired_action. as_noun ( ) ,
@@ -146,8 +180,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
146180 moved_place,
147181 DescribePlaceOpt { including_downcast : true , including_tuple_field : true } ,
148182 ) ,
183+ on_move_message,
149184 ) ;
150185
186+ for note in on_move_notes {
187+ err. note ( note) ;
188+ }
189+
151190 let reinit_spans = maybe_reinitialized_locations
152191 . iter ( )
153192 . take ( 3 )
@@ -275,12 +314,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
275314 if needs_note {
276315 if let Some ( local) = place. as_local ( ) {
277316 let span = self . body . local_decls [ local] . source_info . span ;
278- err. subdiagnostic ( crate :: session_diagnostics:: TypeNoCopy :: Label {
279- is_partial_move,
280- ty,
281- place : & note_msg,
282- span,
283- } ) ;
317+ if let Some ( on_move_label) = on_move_label {
318+ err. span_label ( span, on_move_label) ;
319+ } else {
320+ err. subdiagnostic ( crate :: session_diagnostics:: TypeNoCopy :: Label {
321+ is_partial_move,
322+ ty,
323+ place : & note_msg,
324+ span,
325+ } ) ;
326+ }
284327 } else {
285328 err. subdiagnostic ( crate :: session_diagnostics:: TypeNoCopy :: Note {
286329 is_partial_move,
0 commit comments