Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3548,6 +3548,7 @@ dependencies = [
"rustc_lexer",
"rustc_macros",
"rustc_parse",
"rustc_parse_format",
"rustc_session",
"rustc_span",
"rustc_target",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_parse = { path = "../rustc_parse" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude;
pub(crate) mod no_link;
pub(crate) mod non_exhaustive;
pub(crate) mod on_move;
pub(crate) mod path;
pub(crate) mod pin_v2;
pub(crate) mod proc_macro_attrs;
Expand Down
106 changes: 106 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/on_move.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::{AttributeKind, OnMoveAttrArg, OnMoveAttribute};
use rustc_hir::lints::AttributeLintKind;
use rustc_parse_format::{ParseMode, Parser, Piece, Position};
use rustc_session::lint::builtin::{
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
};
use rustc_span::{InnerSpan, Span, Symbol, kw, sym};
use thin_vec::ThinVec;

use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};

pub(crate) struct OnMoveParser;

impl<S: Stage> SingleAttributeParser<S> for OnMoveParser {
const PATH: &[Symbol] = &[sym::diagnostic, sym::on_move];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Check in check_attr.
const TEMPLATE: AttributeTemplate = template!(List: &["message", "label"]);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let get_format_ranges = |cx: &mut AcceptContext<'_, '_, S>,
symbol: &Symbol,
span: Span|
-> ThinVec<(usize, usize)> {
let mut parser = Parser::new(symbol.as_str(), None, None, false, ParseMode::Diagnostic);
let pieces: Vec<_> = parser.by_ref().collect();
let mut spans = ThinVec::new();

for piece in pieces {
match piece {
Piece::NextArgument(arg) => match arg.position {
Position::ArgumentNamed(name) if name == kw::SelfUpper.as_str() => {
spans.push((arg.position_span.start - 2, arg.position_span.end));
}
Position::ArgumentNamed(name) => {
let span = span.from_inner(InnerSpan {
start: arg.position_span.start,
end: arg.position_span.end,
});
cx.emit_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
AttributeLintKind::OnMoveMalformedFormatLiterals {
name: Symbol::intern(name),
},
span,
)
}
_ => {}
},
_ => continue,
}
}
spans
};
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span, args);
return None;
};
let mut message = None;
let mut label = None;

for item in list.mixed() {
let Some(item) = item.meta_item() else {
cx.expected_specific_argument(item.span(), &[sym::message, sym::label]);
return None;
};

let Some(name_value) = item.args().name_value() else {
cx.expected_name_value(cx.attr_span, item.path().word_sym());
return None;
};

let Some(value) = name_value.value_as_str() else {
cx.expected_string_literal(name_value.value_span, None);
return None;
};

let value_span = name_value.value_span;
if item.path().word_is(sym::message) && message.is_none() {
let spans = get_format_ranges(cx, &value, value_span);
message = Some(OnMoveAttrArg::new(value, spans));
continue;
} else if item.path().word_is(sym::label) && label.is_none() {
let spans = get_format_ranges(cx, &value, value_span);
label = Some(OnMoveAttrArg::new(value, spans));
continue;
}

cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::OnMoveMalformedAttr,
item.span(),
)
}
Some(AttributeKind::OnMove(Box::new(OnMoveAttribute {
span: cx.attr_span,
message,
label,
})))
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::no_link::NoLinkParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
use crate::attributes::on_move::OnMoveParser;
use crate::attributes::path::PathParser as PathAttributeParser;
use crate::attributes::pin_v2::PinV2Parser;
use crate::attributes::proc_macro_attrs::{
Expand Down Expand Up @@ -225,6 +226,7 @@ attribute_parsers!(
Single<MustUseParser>,
Single<ObjcClassParser>,
Single<ObjcSelectorParser>,
Single<OnMoveParser>,
Single<OptimizeParser>,
Single<PatchableFunctionEntryParser>,
Single<PathAttributeParser>,
Expand Down
25 changes: 15 additions & 10 deletions compiler/rustc_borrowck/src/borrowck_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,18 +324,23 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> {
verb: &str,
optional_adverb_for_moved: &str,
moved_path: Option<String>,
primary_message: Option<String>,
) -> 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(
Expand Down
35 changes: 28 additions & 7 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
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::{
Expand Down Expand Up @@ -138,6 +141,19 @@ 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) = if let ty::Adt(item_def, _) =
self.body.local_decls[moved_place.local].ty.kind()
&& let Some(attr) = find_attr!(self.infcx.tcx.get_all_attrs(item_def.did()), AttributeKind::OnMove(attr) => attr)
{
let item_name = self.infcx.tcx.item_name(item_def.did());
(
attr.message.as_ref().map(|e| e.format_args_with(item_name.as_str())),
attr.label.as_ref().map(|e| e.format_args_with(item_name.as_str())),
)
} else {
(None, None)
};

let mut err = self.cannot_act_on_moved_value(
span,
desired_action.as_noun(),
Expand All @@ -146,6 +162,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
moved_place,
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
),
on_move_message,
);

let reinit_spans = maybe_reinitialized_locations
Expand Down Expand Up @@ -275,12 +292,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: &note_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: &note_msg,
span,
});
}
} else {
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
is_partial_move,
Expand Down
31 changes: 31 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::ops::Range;
use std::path::PathBuf;

pub use ReprAttr::*;
Expand Down Expand Up @@ -568,6 +569,33 @@ impl<E: rustc_span::SpanEncoder> rustc_serialize::Encodable<E> for DocAttribute
}
}

#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
pub struct OnMoveAttrArg {
pub symbol: Symbol,
pub format_ranges: ThinVec<(usize, usize)>,
}
Comment on lines +572 to +576
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan on moving a fair bit of the format and string stuff that on_unimplemented uses into rustc_hir; you should be able to reuse some of that in this PR :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will do


impl OnMoveAttrArg {
pub fn new(symbol: Symbol, format_ranges: ThinVec<(usize, usize)>) -> Self {
Self { symbol, format_ranges }
}

pub fn format_args_with(&self, item_name: &str) -> String {
let mut arg = self.symbol.to_string();
for fmt_idx in &self.format_ranges {
arg.replace_range(Range { start: fmt_idx.0, end: fmt_idx.1 }, item_name);
}
arg
}
}

#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
pub struct OnMoveAttribute {
pub span: Span,
pub message: Option<OnMoveAttrArg>,
pub label: Option<OnMoveAttrArg>,
}

/// How to perform collapse macros debug info
/// if-ext - if macro from different crate (related to callsite code)
/// | cmd \ attr | no | (unspecified) | external | yes |
Expand Down Expand Up @@ -984,6 +1012,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_objc_selector]`
ObjcSelector { methname: Symbol, span: Span },

/// Represents `#[diagnostic::on_move]`
OnMove(Box<OnMoveAttribute>),

/// Represents `#[optimize(size|speed)]`
Optimize(OptimizeAttr, Span),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ impl AttributeKind {
NonExhaustive(..) => Yes, // Needed for rustdoc
ObjcClass { .. } => No,
ObjcSelector { .. } => No,
OnMove { .. } => Yes,
Optimize(..) => No,
PanicRuntime => No,
ParenSugar(..) => No,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,12 @@ lint_macro_expr_fragment_specifier_2024_migration =
lint_malformed_attribute = malformed lint attribute input
lint_malformed_on_move_attr = unknown or malformed `on_move` attribute
.help = only `message` and `label` are allowed as options
.label = invalid option found here
lint_malformed_on_move_format_literals = unknown parameter `{$name}`
.help = expect {"`{Self}`"} as format argument
lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
.note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
.function_label = this function returns `()`, which is likely not what you wanted
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_lint/src/early/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,5 +428,11 @@ pub fn decorate_attribute_lint(
sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }),
}
.decorate_lint(diag),

&AttributeLintKind::OnMoveMalformedAttr => lints::OnMoveMalformedAttr.decorate_lint(diag),

&AttributeLintKind::OnMoveMalformedFormatLiterals { name } => {
lints::OnMoveMalformedFormatLiterals { name }.decorate_lint(diag)
}
}
}
12 changes: 12 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3325,3 +3325,15 @@ pub(crate) struct UnknownCrateTypesSuggestion {
pub span: Span,
pub snippet: Symbol,
}

#[derive(LintDiagnostic)]
#[diag(lint_malformed_on_move_attr)]
#[help]
pub(crate) struct OnMoveMalformedAttr;

#[derive(LintDiagnostic)]
#[diag(lint_malformed_on_move_format_literals)]
#[help]
pub(crate) struct OnMoveMalformedFormatLiterals {
pub name: Symbol,
}
4 changes: 4 additions & 0 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,10 @@ pub enum AttributeLintKind {
span: Span,
suggested: Option<Symbol>,
},
OnMoveMalformedAttr,
OnMoveMalformedFormatLiterals {
name: Symbol,
},
}

pub type RegisteredTools = FxIndexSet<Ident>;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ passes_diagnostic_diagnostic_on_const_only_for_trait_impls =
`#[diagnostic::on_const]` can only be applied to trait impls
.label = not a trait impl
passes_diagnostic_diagnostic_on_move_only_for_adt =
`#[diagnostic::on_move]` can only be applied to enums, structs or unions
passes_diagnostic_diagnostic_on_unimplemented_only_for_traits =
`#[diagnostic::on_unimplemented]` can only be applied to trait definitions
Expand Down
Loading
Loading