Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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 Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3505,6 +3505,7 @@ dependencies = [
"rand_xoshiro",
"rustc_data_structures",
"rustc_error_messages",
"rustc_errors",
"rustc_hashes",
"rustc_index",
"rustc_macros",
Expand Down Expand Up @@ -3909,7 +3910,6 @@ dependencies = [
"anstream",
"anstyle",
"derive_setters",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
"rustc_error_codes",
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ rand = { version = "0.9.0", default-features = false, optional = true }
rand_xoshiro = { version = "0.7.0", optional = true }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_error_messages = { path = "../rustc_error_messages", optional = true }
rustc_errors = { path = "../rustc_errors", optional = true }
rustc_hashes = { path = "../rustc_hashes" }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
Expand All @@ -21,11 +22,12 @@ tracing = "0.1"
[features]
# tidy-alphabetical-start
default = ["nightly", "randomize"]
# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
# without depending on rustc_data_structures, rustc_macros and rustc_serialize
# rust-analyzer depends on this crate and we therefore require it to build on a stable toolchain
# without depending on the rustc_* crates in the following list.
nightly = [
"dep:rustc_data_structures",
"dep:rustc_error_messages",
"dep:rustc_errors",
"dep:rustc_macros",
"dep:rustc_serialize",
"dep:rustc_span",
Expand Down
63 changes: 55 additions & 8 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ use std::str::FromStr;
use bitflags::bitflags;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::StableOrd;
#[cfg(feature = "nightly")]
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
use rustc_hashes::Hash64;
use rustc_index::{Idx, IndexSlice, IndexVec};
#[cfg(feature = "nightly")]
Expand Down Expand Up @@ -332,7 +334,7 @@ impl Default for TargetDataLayout {
}
}

pub enum TargetDataLayoutErrors<'a> {
pub enum TargetDataLayoutError<'a> {
InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
MissingAlignment { cause: &'a str },
Expand All @@ -343,6 +345,51 @@ pub enum TargetDataLayoutErrors<'a> {
UnknownPointerSpecification { err: String },
}

#[cfg(feature = "nightly")]
impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetDataLayoutError<'_> {
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
match self {
TargetDataLayoutError::InvalidAddressSpace { addr_space, err, cause } => {
Diag::new(dcx, level, msg!("invalid address space `{$addr_space}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("addr_space", addr_space)
.with_arg("cause", cause)
.with_arg("err", err)
}
TargetDataLayoutError::InvalidBits { kind, bit, cause, err } => {
Diag::new(dcx, level, msg!("invalid {$kind} `{$bit}` for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("kind", kind)
.with_arg("bit", bit)
.with_arg("cause", cause)
.with_arg("err", err)
}
TargetDataLayoutError::MissingAlignment { cause } => {
Diag::new(dcx, level, msg!("missing alignment for `{$cause}` in \"data-layout\""))
.with_arg("cause", cause)
}
TargetDataLayoutError::InvalidAlignment { cause, err } => {
Diag::new(dcx, level, msg!("invalid alignment for `{$cause}` in \"data-layout\": {$err}"))
.with_arg("cause", cause)
.with_arg("err", err.to_string())
}
TargetDataLayoutError::InconsistentTargetArchitecture { dl, target } => {
Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims architecture is {$dl}-endian, while \"target-endian\" is `{$target}`"))
.with_arg("dl", dl).with_arg("target", target)
}
TargetDataLayoutError::InconsistentTargetPointerWidth { pointer_size, target } => {
Diag::new(dcx, level, msg!("inconsistent target specification: \"data-layout\" claims pointers are {$pointer_size}-bit, while \"target-pointer-width\" is `{$target}`"))
.with_arg("pointer_size", pointer_size).with_arg("target", target)
}
TargetDataLayoutError::InvalidBitsSize { err } => {
Diag::new(dcx, level, msg!("{$err}")).with_arg("err", err)
}
TargetDataLayoutError::UnknownPointerSpecification { err } => {
Diag::new(dcx, level, msg!("unknown pointer specification `{$err}` in datalayout string"))
.with_arg("err", err)
}
}
}
}

impl TargetDataLayout {
/// Parse data layout from an
/// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
Expand All @@ -352,17 +399,17 @@ impl TargetDataLayout {
pub fn parse_from_llvm_datalayout_string<'a>(
input: &'a str,
default_address_space: AddressSpace,
) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
) -> Result<TargetDataLayout, TargetDataLayoutError<'a>> {
// Parse an address space index from a string.
let parse_address_space = |s: &'a str, cause: &'a str| {
s.parse::<u32>().map(AddressSpace).map_err(|err| {
TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
TargetDataLayoutError::InvalidAddressSpace { addr_space: s, cause, err }
})
};

// Parse a bit count from a string.
let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
s.parse::<u64>().map_err(|err| TargetDataLayoutError::InvalidBits {
kind,
bit: s,
cause,
Expand All @@ -378,7 +425,7 @@ impl TargetDataLayout {
let parse_align_str = |s: &'a str, cause: &'a str| {
let align_from_bits = |bits| {
Align::from_bits(bits)
.map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
.map_err(|err| TargetDataLayoutError::InvalidAlignment { cause, err })
};
let abi = parse_bits(s, "alignment", cause)?;
Ok(align_from_bits(abi)?)
Expand All @@ -388,7 +435,7 @@ impl TargetDataLayout {
// ignoring the secondary alignment specifications.
let parse_align_seq = |s: &[&'a str], cause: &'a str| {
if s.is_empty() {
return Err(TargetDataLayoutErrors::MissingAlignment { cause });
return Err(TargetDataLayoutError::MissingAlignment { cause });
}
parse_align_str(s[0], cause)
};
Expand Down Expand Up @@ -426,7 +473,7 @@ impl TargetDataLayout {
// However, we currently don't take into account further specifications:
// an error is emitted instead.
if p.starts_with(char::is_alphabetic) {
return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
return Err(TargetDataLayoutError::UnknownPointerSpecification {
err: p.to_string(),
});
}
Expand Down Expand Up @@ -471,7 +518,7 @@ impl TargetDataLayout {
// However, we currently don't take into account further specifications:
// an error is emitted instead.
if p.starts_with(char::is_alphabetic) {
return Err(TargetDataLayoutErrors::UnknownPointerSpecification {
return Err(TargetDataLayoutError::UnknownPointerSpecification {
err: p.to_string(),
});
}
Expand Down
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
}
}
}
15 changes: 11 additions & 4 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::sync::LazyLock;

use private::Sealed;
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_errors::{Diag, Diagnostic, Level, MultiSpan};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
Expand All @@ -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 Expand Up @@ -455,14 +457,19 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
pub(crate) fn emit_lint<M: Into<MultiSpan>>(
&mut self,
lint: &'static Lint,
kind: AttributeLintKind,
span: M,
) {
if !matches!(
self.stage.should_emit(),
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
}
(self.emit_lint)(LintId::of(lint), span, kind);
(self.emit_lint)(LintId::of(lint), span.into(), kind);
}

pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
Expand Down Expand Up @@ -528,7 +535,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {

/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind),
}

/// Context given to every attribute parser during finalization.
Expand Down
Loading
Loading