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
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
AttributeParser::parse_limited(
sess,
&krate.attrs,
sym::feature,
&[sym::feature],
DUMMY_SP,
krate.id,
Some(&features),
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub(crate) mod do_not_recommend;
pub(crate) mod on_const;
pub(crate) mod on_move;
pub(crate) mod on_unimplemented;
pub(crate) mod on_unknown_item;

#[derive(Copy, Clone)]
pub(crate) enum Mode {
Expand All @@ -35,6 +36,8 @@ pub(crate) enum Mode {
DiagnosticOnConst,
/// `#[diagnostic::on_move]`
DiagnosticOnMove,
/// `#[diagnostic::on_unknown_item]`
DiagnosticOnUnknownItem,
}

fn merge_directives<S: Stage>(
Expand Down Expand Up @@ -123,6 +126,13 @@ fn parse_directive_items<'p, S: Stage>(
span,
);
}
Mode::DiagnosticOnUnknownItem => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::MalformedOnUnknownItemdAttr { span },
span,
);
}
}
continue;
}}
Expand All @@ -142,7 +152,7 @@ fn parse_directive_items<'p, S: Stage>(
Mode::RustcOnUnimplemented => {
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
}
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnknownItem => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::IgnoredDiagnosticOption {
Expand Down Expand Up @@ -173,7 +183,8 @@ fn parse_directive_items<'p, S: Stage>(
Ok((f, warnings)) => {
for warning in warnings {
let (FormatWarning::InvalidSpecifier { span, .. }
| FormatWarning::PositionalArgument { span, .. }) = warning;
| FormatWarning::PositionalArgument { span, .. }
| FormatWarning::DisallowedPlaceholder { span }) = warning;
cx.emit_lint(
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
AttributeLintKind::MalformedDiagnosticFormat { warning },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use rustc_hir::attrs::diagnostic::Directive;
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;

use crate::attributes::diagnostic::*;
use crate::attributes::prelude::*;

#[derive(Default)]
pub(crate) struct OnUnknownItemParser {
span: Option<Span>,
directive: Option<(Span, Directive)>,
}

impl OnUnknownItemParser {
fn parse<'sess, S: Stage>(
&mut self,
cx: &mut AcceptContext<'_, 'sess, S>,
args: &ArgParser,
mode: Mode,
) {
if !cx.features().diagnostic_on_unknown_item() {
return;
}
let span = cx.attr_span;
self.span = Some(span);

let items = match args {
ArgParser::List(items) if !items.is_empty() => items,
ArgParser::NoArgs | ArgParser::List(_) => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::MissingOptionsForOnUnknownItem,
span,
);
return;
}
ArgParser::NameValue(_) => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::MalformedOnUnknownItemdAttr { span },
span,
);
return;
}
};

if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
merge_directives(cx, &mut self.directive, (span, directive));
};
}
}

impl<S: Stage> AttributeParser<S> for OnUnknownItemParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::diagnostic, sym::on_unknown_item],
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|this, cx, args| {
this.parse(cx, args, Mode::DiagnosticOnUnknownItem);
},
)];
//FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(span) = self.span {
Some(AttributeKind::OnUnknownItem {
span,
directive: self.directive.map(|d| Box::new(d.1)),
})
} else {
None
}
}
}
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 @@ -31,6 +31,7 @@ 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::diagnostic::on_unknown_item::*;
use crate::attributes::doc::*;
use crate::attributes::dummy::*;
use crate::attributes::inline::*;
Expand Down Expand Up @@ -152,6 +153,7 @@ attribute_parsers!(
OnConstParser,
OnMoveParser,
OnUnimplementedParser,
OnUnknownItemParser,
RustcAlignParser,
RustcAlignStaticParser,
RustcCguTestAttributeParser,
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
/// *Only* parse attributes with this symbol.
///
/// Used in cases where we want the lowering infrastructure for parse just a single attribute.
parse_only: Option<Symbol>,
parse_only: Option<&'static [Symbol]>,
}

impl<'sess> AttributeParser<'sess, Early> {
Expand All @@ -50,7 +50,7 @@ impl<'sess> AttributeParser<'sess, Early> {
pub fn parse_limited(
sess: &'sess Session,
attrs: &[ast::Attribute],
sym: Symbol,
sym: &'static [Symbol],
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
Expand All @@ -71,7 +71,7 @@ impl<'sess> AttributeParser<'sess, Early> {
pub fn parse_limited_should_emit(
sess: &'sess Session,
attrs: &[ast::Attribute],
sym: Symbol,
sym: &'static [Symbol],
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
Expand Down Expand Up @@ -101,7 +101,7 @@ impl<'sess> AttributeParser<'sess, Early> {
pub fn parse_limited_all(
sess: &'sess Session,
attrs: &[ast::Attribute],
parse_only: Option<Symbol>,
parse_only: Option<&'static [Symbol]>,
target: Target,
target_span: Span,
target_node_id: NodeId,
Expand Down Expand Up @@ -275,7 +275,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
for attr in attrs {
// If we're only looking for a single attribute, skip all the ones we don't care about.
if let Some(expected) = self.parse_only {
if !attr.has_name(expected) {
if !attr.path_matches(expected) {
continue;
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
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(),
directive.message.as_ref().map(|e| e.1.format(Some(&args))),
directive.label.as_ref().map(|e| e.1.format(Some(&args))),
directive.notes.iter().map(|e| e.format(Some(&args))).collect(),
)
} else {
(None, None, ThinVec::new())
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ impl<'a> TraitDef<'a> {
match item {
Annotatable::Item(item) => {
let is_packed = matches!(
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr], item.span, item.id, None),
Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/proc_macro_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl<'a> CollectProcMacros<'a> {
})) = AttributeParser::parse_limited(
self.session,
slice::from_ref(attr),
sym::proc_macro_derive,
&[sym::proc_macro_derive],
item.span,
item.node_id(),
None,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
AttributeParser::parse_limited(
cx.sess,
&i.attrs,
sym::should_panic,
&[sym::should_panic],
i.span,
i.node_id(),
None,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> O
match AttributeParser::parse_limited(
sess,
&krate.attrs,
sym::test_runner,
&[sym::test_runner],
krate.spans.inner_span,
krate.id,
Some(features),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
AttributeParser::parse_limited(
sess,
krate_attrs,
sym::feature,
&[sym::feature],
DUMMY_SP,
DUMMY_NODE_ID,
Some(&features),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool
sym::on_unimplemented | sym::do_not_recommend => true,
sym::on_const => features.diagnostic_on_const(),
sym::on_move => features.diagnostic_on_move(),
sym::on_unknown_item => features.diagnostic_on_unknown_item(),
_ => false,
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ declare_features! (
(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 giving unresolved imports a custom diagnostic message
(unstable, diagnostic_on_unknown_item, "CURRENT_RUSTC_VERSION", Some(152900)),
/// Allows `#[doc(cfg(...))]`.
(unstable, doc_cfg, "1.21.0", Some(43781)),
/// Allows `#[doc(masked)]`.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,14 @@ pub enum AttributeKind {
/// None if the directive was malformed in some way.
directive: Option<Box<Directive>>,
},

/// Represents `#[diagnostic::on_unknown_item]`
OnUnknownItem {
span: Span,
/// None if the directive was malformed in some way.
directive: Option<Box<Directive>>,
},

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

Expand Down
34 changes: 24 additions & 10 deletions compiler/rustc_hir/src/attrs/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ impl Directive {
}

OnUnimplementedNote {
label: label.map(|l| l.1.format(args)),
message: message.map(|m| m.1.format(args)),
notes: notes.into_iter().map(|n| n.format(args)).collect(),
parent_label: parent_label.map(|e_s| e_s.format(args)),
label: label.map(|l| l.1.format(Some(args))),
message: message.map(|m| m.1.format(Some(args))),
notes: notes.into_iter().map(|n| n.format(Some(args))).collect(),
parent_label: parent_label.map(|e_s| e_s.format(Some(args))),
append_const_msg,
}
}
Expand Down Expand Up @@ -133,15 +133,17 @@ pub struct FormatString {
pub pieces: ThinVec<Piece>,
}
impl FormatString {
pub fn format(&self, args: &FormatArgs) -> String {
pub fn format(&self, args: Option<&FormatArgs>) -> String {
let mut ret = String::new();
for piece in &self.pieces {
match piece {
Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(s.as_str()),

// `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"`
Piece::Arg(FormatArg::GenericParam { generic_param, .. }) => {
match args.generic_args.iter().find(|(p, _)| p == generic_param) {
match args
.and_then(|args| args.generic_args.iter().find(|(p, _)| p == generic_param))
{
Some((_, val)) => ret.push_str(val.as_str()),

None => {
Expand All @@ -153,19 +155,31 @@ impl FormatString {
}
// `{Self}`
Piece::Arg(FormatArg::SelfUpper) => {
let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) {
let slf = match args.and_then(|args| {
args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper)
}) {
Some((_, val)) => val.to_string(),
None => "Self".to_string(),
};
ret.push_str(&slf);
}

// It's only `rustc_onunimplemented` from here
Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
Piece::Arg(FormatArg::This) => {
ret.push_str(&args.map(|args| args.this.as_str()).unwrap_or_default())
}
Piece::Arg(FormatArg::Trait) => {
let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared));
let _ = fmt::write(
&mut ret,
format_args!(
"{}",
&args.map(|args| args.trait_sugared.as_str()).unwrap_or_default()
),
);
}
Piece::Arg(FormatArg::ItemContext) => {
ret.push_str(args.map(|args| args.item_context).unwrap_or_default())
}
Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context),
}
}
ret
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 @@ -79,6 +79,7 @@ impl AttributeKind {
OnConst { .. } => Yes,
OnMove { .. } => Yes,
OnUnimplemented { .. } => Yes,
OnUnknownItem { .. } => Yes,
Optimize(..) => No,
PanicRuntime => No,
PatchableFunctionEntry { .. } => Yes,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ pub(crate) fn parse_crate_name(
AttributeParser::parse_limited_should_emit(
sess,
attrs,
sym::crate_name,
&[sym::crate_name],
DUMMY_SP,
rustc_ast::node_id::CRATE_NODE_ID,
None,
Expand Down Expand Up @@ -1367,7 +1367,7 @@ pub fn collect_crate_types(
AttributeParser::<Early>::parse_limited_should_emit(
session,
attrs,
sym::crate_type,
&[sym::crate_type],
crate_span,
CRATE_NODE_ID,
None,
Expand Down Expand Up @@ -1423,7 +1423,7 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit
let attr = AttributeParser::parse_limited_should_emit(
sess,
&krate_attrs,
sym::recursion_limit,
&[sym::recursion_limit],
DUMMY_SP,
rustc_ast::node_id::CRATE_NODE_ID,
None,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ impl EarlyLintPass for UnsafeCode {
AttributeParser::parse_limited(
cx.builder.sess(),
&it.attrs,
sym::allow_internal_unsafe,
&[sym::allow_internal_unsafe],
it.span,
DUMMY_NODE_ID,
Some(cx.builder.features()),
Expand Down
Loading
Loading