Skip to content
Closed
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 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
}
}
}
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
18 changes: 18 additions & 0 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3538,6 +3538,24 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
Applicability::MaybeIncorrect,
);
}

if let Some(cow_did) = tcx.get_diagnostic_item(sym::Cow)
&& let ty::Adt(adt_def, _) = return_ty.kind()
&& adt_def.did() == cow_did
{
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
if let Some(pos) = snippet.rfind(".to_owned") {
let byte_pos = BytePos(pos as u32 + 1u32);
let to_owned_span = return_span.with_hi(return_span.lo() + byte_pos);
err.span_suggestion_short(
to_owned_span.shrink_to_hi(),
"try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`",
"in",
Applicability::MaybeIncorrect,
);
}
}
}
}

Err(err)
Expand Down
Loading
Loading