Skip to content
Merged
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 @@ -649,7 +649,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
19 changes: 17 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;

#[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]`
DiagnosticOnUnknown,
}

fn merge_directives<S: Stage>(
Expand Down Expand Up @@ -122,6 +125,13 @@ fn parse_directive_items<'p, S: Stage>(
span,
);
}
Mode::DiagnosticOnUnknown => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::MalformedOnUnknownAttr { span },
span,
);
}
}
continue;
}}
Expand All @@ -140,7 +150,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::DiagnosticOnUnknown => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::IgnoredDiagnosticOption {
Expand Down Expand Up @@ -176,7 +186,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 Expand Up @@ -326,6 +337,10 @@ fn parse_arg(
is_source_literal: bool,
) -> FormatArg {
let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
if matches!(mode, Mode::DiagnosticOnUnknown) {
warnings.push(FormatWarning::DisallowedPlaceholder { span });
return FormatArg::AsIs(sym::empty_braces);
}

match arg.position {
// Something like "hello {name}"
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 OnUnknownParser {
span: Option<Span>,
directive: Option<(Span, Directive)>,
}

impl OnUnknownParser {
fn parse<'sess, S: Stage>(
&mut self,
cx: &mut AcceptContext<'_, 'sess, S>,
args: &ArgParser,
mode: Mode,
) {
if !cx.features().diagnostic_on_unknown() {
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::MissingOptionsForOnUnknown,
span,
);
return;
}
ArgParser::NameValue(_) => {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::MalformedOnUnknownAttr { 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 OnUnknownParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
&[sym::diagnostic, sym::on_unknown],
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|this, cx, args| {
this.parse(cx, args, Mode::DiagnosticOnUnknown);
},
)];
//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::OnUnknown {
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 @@ -32,6 +32,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::*;
use crate::attributes::doc::*;
use crate::attributes::dummy::*;
use crate::attributes::inline::*;
Expand Down Expand Up @@ -154,6 +155,7 @@ attribute_parsers!(
OnConstParser,
OnMoveParser,
OnUnimplementedParser,
OnUnknownParser,
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 @@ -72,7 +72,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,
target: Target,
Expand Down Expand Up @@ -103,7 +103,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 @@ -272,7 +272,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
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 @@ -54,7 +54,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 => features.diagnostic_on_unknown(),
_ => 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(154181)),
/// Allows giving unresolved imports a custom diagnostic message
(unstable, diagnostic_on_unknown, "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]`
OnUnknown {
span: Span,
/// None if the directive was malformed in some way.
directive: Option<Box<Directive>>,
},

/// 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 @@ -79,6 +79,7 @@ impl AttributeKind {
OnConst { .. } => Yes,
OnMove { .. } => Yes,
OnUnimplemented { .. } => Yes,
OnUnknown { .. } => 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 @@ -1369,7 +1369,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,
Target::Crate,
Expand Down Expand Up @@ -1419,7 +1419,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,
Target::Crate,
Expand Down Expand Up @@ -1476,7 +1476,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,
Target::Crate,
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
9 changes: 9 additions & 0 deletions compiler/rustc_lint/src/early/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
&AttributeLintKind::MalformedOnUnimplementedAttr { span } => {
lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level)
}
&AttributeLintKind::MalformedOnUnknownAttr { span } => {
lints::MalformedOnUnknownAttrLint { span }.into_diag(dcx, level)
}
&AttributeLintKind::MalformedOnConstAttr { span } => {
lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level)
}
Expand All @@ -189,6 +192,9 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
FormatWarning::InvalidSpecifier { .. } => {
lints::InvalidFormatSpecifier.into_diag(dcx, level)
}
FormatWarning::DisallowedPlaceholder { .. } => {
lints::DisallowedPlaceholder.into_diag(dcx, level)
}
},
AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => {
lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level)
Expand All @@ -215,6 +221,9 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
&AttributeLintKind::MissingOptionsForOnMove => {
lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
}
&AttributeLintKind::MissingOptionsForOnUnknown => {
lints::MissingOptionsForOnUnknownAttr.into_diag(dcx, level)
}
}
}
}
18 changes: 18 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3542,6 +3542,11 @@ pub(crate) struct UnknownCrateTypesSuggestion {
)]
pub(crate) struct DisallowedPositionalArgument;

#[derive(Diagnostic)]
#[diag("format arguments are not allowed here")]
#[help("consider removing this format argument")]
pub(crate) struct DisallowedPlaceholder;

#[derive(Diagnostic)]
#[diag("invalid format specifier")]
#[help("no format specifier are supported in this position")]
Expand Down Expand Up @@ -3571,6 +3576,11 @@ pub(crate) struct IgnoredDiagnosticOption {
#[help("at least one of the `message`, `note` and `label` options are expected")]
pub(crate) struct MissingOptionsForOnUnimplementedAttr;

#[derive(Diagnostic)]
#[diag("missing options for `on_unknown` attribute")]
#[help("at least one of the `message`, `note` and `label` options are expected")]
pub(crate) struct MissingOptionsForOnUnknownAttr;

#[derive(Diagnostic)]
#[diag("missing options for `on_const` attribute")]
#[help("at least one of the `message`, `note` and `label` options are expected")]
Expand All @@ -3589,6 +3599,14 @@ pub(crate) struct MalformedOnUnimplementedAttrLint {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("malformed `on_unknown` attribute")]
#[help("only `message`, `note` and `label` are allowed as options")]
pub(crate) struct MalformedOnUnknownAttrLint {
#[label("invalid option found here")]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("malformed `on_const` attribute")]
#[help("only `message`, `note` and `label` are allowed as options")]
Expand Down
Loading
Loading