mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-02 18:12:51 +00:00
Rollup merge of #99213 - davidtwco:translation-migrate-passes, r=compiler-errors
migrate some of `rustc_passes::check_attr`'s diagnostics and derive improvements - Implements `IntoDiagnosticArg` for `char` using its `Debug` implementation and introduces a macro for those types which just delegate the implementation to `ToString`. - Apply the `#[rustc_lint_diagnostics]` attribute to `LintDiagnosticBuilder::build` so that diagnostic migration lints will trigger for it - some diagnostics in `rustc_privacy` need updated after this since the lints apply to that crate. - Add support for `MultiSpan` with any of the attributes that work on a `Span` in the diagnostic derive (`SessionDiagnostic` + `LintDiagnostic`). Requires that diagnostic logic generated for these attributes are emitted in the by-move block rather than the by-ref block that they would normally have been generated in. - Both diagnostic and subdiagnostic derives were missing the ability to add warnings to diagnostics - this is made more difficult by the `warn` attribute already existing, so this name being unavailable for the derives to use. `#[warn_]` is used instead, which requires special-casing so that `{span_,}warn` is called instead of `{span_,}warn_`. - Migrate half of the `rustc_passes::check_attr` diagnostics to using diagnostic derives and being translatable. I got tired after a while. I modified some diagnostic output for consistency while doing this, nothing too crazy. r? `@compiler-errors`
This commit is contained in:
commit
79857a740e
@ -4239,6 +4239,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
|
151
compiler/rustc_error_messages/locales/en-US/passes.ftl
Normal file
151
compiler/rustc_error_messages/locales/en-US/passes.ftl
Normal file
@ -0,0 +1,151 @@
|
||||
-passes-previously-accepted =
|
||||
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
-passes-see-issue =
|
||||
see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
|
||||
|
||||
passes-outer-crate-level-attr =
|
||||
crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
|
||||
|
||||
passes-inner-crate-level-attr =
|
||||
crate-level attribute should be in the root module
|
||||
|
||||
passes-ignored-attr-with-macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs
|
||||
.warn = {-passes-previously-accepted}
|
||||
.note = {-passes-see-issue(issue: "80564")}
|
||||
|
||||
passes-ignored-attr = `#[{$sym}]` is ignored on struct fields and match arms
|
||||
.warn = {-passes-previously-accepted}
|
||||
.note = {-passes-see-issue(issue: "80564")}
|
||||
|
||||
passes-inline-ignored-function-prototype = `#[inline]` is ignored on function prototypes
|
||||
|
||||
passes-inline-ignored-constants = `#[inline]` is ignored on constants
|
||||
.warn = {-passes-previously-accepted}
|
||||
.note = {-passes-see-issue(issue: "65833")}
|
||||
|
||||
passes-inline-not-fn-or-closure = attribute should be applied to function or closure
|
||||
.label = not a function or closure
|
||||
|
||||
passes-no-coverage-ignored-function-prototype = `#[no_coverage]` is ignored on function prototypes
|
||||
|
||||
passes-no-coverage-propagate =
|
||||
`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
|
||||
passes-no-coverage-fn-defn = `#[no_coverage]` may only be applied to function definitions
|
||||
|
||||
passes-no-coverage-not-coverable = `#[no_coverage]` must be applied to coverable code
|
||||
.label = not coverable code
|
||||
|
||||
passes-should-be-applied-to-fn = attribute should be applied to a function definition
|
||||
.label = not a function definition
|
||||
|
||||
passes-naked-tracked-caller = cannot use `#[track_caller]` with `#[naked]`
|
||||
|
||||
passes-should-be-applied-to-struct-enum = attribute should be applied to a struct or enum
|
||||
.label = not a struct or enum
|
||||
|
||||
passes-should-be-applied-to-trait = attribute should be applied to a trait
|
||||
.label = not a trait
|
||||
|
||||
passes-target-feature-on-statement = {passes-should-be-applied-to-fn}
|
||||
.warn = {-passes-previously-accepted}
|
||||
.label = {passes-should-be-applied-to-fn.label}
|
||||
|
||||
passes-should-be-applied-to-static = attribute should be applied to a static
|
||||
.label = not a static
|
||||
|
||||
passes-doc-expect-str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
|
||||
|
||||
passes-doc-alias-empty = {$attr_str} attribute cannot have empty value
|
||||
|
||||
passes-doc-alias-bad-char = {$char_} character isn't allowed in {$attr_str}
|
||||
|
||||
passes-doc-alias-start-end = {$attr_str} cannot start or end with ' '
|
||||
|
||||
passes-doc-alias-bad-location = {$attr_str} isn't allowed on {$location}
|
||||
|
||||
passes-doc-alias-not-an-alias = {$attr_str} is the same as the item's name
|
||||
|
||||
passes-doc-alias-duplicated = doc alias is duplicated
|
||||
.label = first defined here
|
||||
|
||||
passes-doc-alias-not-string-literal = `#[doc(alias("a"))]` expects string literals
|
||||
|
||||
passes-doc-alias-malformed =
|
||||
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
|
||||
|
||||
passes-doc-keyword-empty-mod = `#[doc(keyword = "...")]` should be used on empty modules
|
||||
|
||||
passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules
|
||||
|
||||
passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier
|
||||
|
||||
passes-doc-tuple-variadic-not-first =
|
||||
`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity
|
||||
|
||||
passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks
|
||||
|
||||
passes-doc-inline-conflict-first = this attribute...
|
||||
passes-doc-inline-conflict-second = ...conflicts with this attribute
|
||||
passes-doc-inline-conflict = conflicting doc inlining attributes
|
||||
.help = remove one of the conflicting attributes
|
||||
|
||||
passes-doc-inline-only-use = this attribute can only be applied to a `use` item
|
||||
.label = only applicable on `use` items
|
||||
.not-a-use-item-label = not a `use` item
|
||||
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
passes-doc-attr-not-crate-level =
|
||||
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
|
||||
|
||||
passes-attr-crate-level = this attribute can only be applied at the crate level
|
||||
.suggestion = to apply to the crate, use an inner attribute
|
||||
.help = to apply to the crate, use an inner attribute
|
||||
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
passes-doc-test-unknown = unknown `doc(test)` attribute `{$path}`
|
||||
|
||||
passes-doc-test-takes-list = `#[doc(test(...)]` takes a list of attributes
|
||||
|
||||
passes-doc-primitive = `doc(primitive)` should never have been stable
|
||||
|
||||
passes-doc-test-unknown-any = unknown `doc` attribute `{$path}`
|
||||
|
||||
passes-doc-test-unknown-spotlight = unknown `doc` attribute `{$path}`
|
||||
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
|
||||
.suggestion = use `notable_trait` instead
|
||||
.no-op-note = `doc(spotlight)` is now a no-op
|
||||
|
||||
passes-doc-test-unknown-include = unknown `doc` attribute `{$path}`
|
||||
.suggestion = use `doc = include_str!` instead
|
||||
|
||||
passes-doc-invalid = invalid `doc` attribute
|
||||
|
||||
passes-pass-by-value = `pass_by_value` attribute should be applied to a struct, enum or type alias
|
||||
.label = is not a struct, enum or type alias
|
||||
|
||||
passes-allow-incoherent-impl =
|
||||
`rustc_allow_incoherent_impl` attribute should be applied to impl items.
|
||||
.label = the only currently supported targets are inherent methods
|
||||
|
||||
passes-has-incoherent-inherent-impl =
|
||||
`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
|
||||
.label = only adts, extern types and traits are supported
|
||||
|
||||
passes-must-use-async =
|
||||
`must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
|
||||
.label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
|
||||
|
||||
passes-must-use-no-effect = `#[must_use]` has no effect when applied to {$article} {$target}
|
||||
|
||||
passes-must-not-suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait
|
||||
.label = is not a struct, enum, or trait
|
||||
|
||||
passes-cold = {passes-should-be-applied-to-fn}
|
||||
.warn = {-passes-previously-accepted}
|
||||
.label = {passes-should-be-applied-to-fn.label}
|
||||
|
||||
passes-link = attribute should be applied to an `extern` block with non-Rust ABI
|
||||
.warn = {-passes-previously-accepted}
|
||||
.label = not an `extern` block
|
@ -10,3 +10,12 @@ privacy-unnamed-item-is-private = {$kind} is private
|
||||
privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface
|
||||
.label = can't leak {$vis_descr} {$kind}
|
||||
.visibility-label = `{$descr}` declared as {$vis_descr}
|
||||
|
||||
privacy-from-private-dep-in-public-interface =
|
||||
{$kind} `{$descr}` from private dependency '{$krate}' in public interface
|
||||
|
||||
private-in-public-lint =
|
||||
{$vis_descr} {$kind} `{$descr}` in public interface (error {$kind ->
|
||||
[trait] E0445
|
||||
*[other] E0446
|
||||
})
|
||||
|
@ -37,6 +37,7 @@ fluent_messages! {
|
||||
expand => "../locales/en-US/expand.ftl",
|
||||
lint => "../locales/en-US/lint.ftl",
|
||||
parser => "../locales/en-US/parser.ftl",
|
||||
passes => "../locales/en-US/passes.ftl",
|
||||
privacy => "../locales/en-US/privacy.ftl",
|
||||
typeck => "../locales/en-US/typeck.ftl",
|
||||
}
|
||||
|
@ -40,6 +40,35 @@ pub trait IntoDiagnosticArg {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
|
||||
}
|
||||
|
||||
macro_rules! into_diagnostic_arg_using_display {
|
||||
($( $ty:ty ),+ $(,)?) => {
|
||||
$(
|
||||
impl IntoDiagnosticArg for $ty {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
into_diagnostic_arg_using_display!(
|
||||
i8,
|
||||
u8,
|
||||
i16,
|
||||
u16,
|
||||
i32,
|
||||
u32,
|
||||
i64,
|
||||
u64,
|
||||
i128,
|
||||
u128,
|
||||
std::num::NonZeroU32,
|
||||
hir::Target,
|
||||
Edition,
|
||||
Ident,
|
||||
);
|
||||
|
||||
impl IntoDiagnosticArg for bool {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
if self {
|
||||
@ -50,81 +79,9 @@ impl IntoDiagnosticArg for bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for i8 {
|
||||
impl IntoDiagnosticArg for char {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for u8 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for i16 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for u16 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for i32 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for u32 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for i64 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for u64 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for i128 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for u128 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for String {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for std::num::NonZeroU32 {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for Edition {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
|
||||
DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,15 +91,15 @@ impl IntoDiagnosticArg for Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for Ident {
|
||||
impl<'a> IntoDiagnosticArg for &'a str {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoDiagnosticArg for &'a str {
|
||||
impl IntoDiagnosticArg for String {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
self.to_string().into_diagnostic_arg()
|
||||
DiagnosticArgValue::Str(Cow::Owned(self))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,6 +595,7 @@ macro_rules! error_code {
|
||||
pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
|
||||
|
||||
impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
|
||||
#[rustc_lint_diagnostics]
|
||||
/// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
|
||||
pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
|
||||
self.0.set_primary_message(msg);
|
||||
|
@ -59,7 +59,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
}
|
||||
(Some(DiagnosticDeriveKind::Lint), _) => {
|
||||
span_err(span, "only `#[error(..)]` and `#[warn(..)]` are supported")
|
||||
span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported")
|
||||
.help("use the `#[error(...)]` attribute to create a error")
|
||||
.emit();
|
||||
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
|
||||
|
@ -8,12 +8,13 @@ use crate::diagnostics::utils::{
|
||||
report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
|
||||
Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
|
||||
};
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use syn::{
|
||||
parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
|
||||
parse_quote, spanned::Spanned, Attribute, Field, Meta, MetaList, MetaNameValue, NestedMeta,
|
||||
Path, Type,
|
||||
};
|
||||
use synstructure::{BindingInfo, Structure};
|
||||
|
||||
@ -80,8 +81,8 @@ impl DiagnosticDeriveBuilder {
|
||||
}
|
||||
|
||||
pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) {
|
||||
// Keep track of which fields are subdiagnostics or have no attributes.
|
||||
let mut subdiagnostics_or_empty = std::collections::HashSet::new();
|
||||
// Keep track of which fields need to be handled with a by-move binding.
|
||||
let mut needs_moved = std::collections::HashSet::new();
|
||||
|
||||
// Generates calls to `span_label` and similar functions based on the attributes
|
||||
// on fields. Code for suggestions uses formatting machinery and the value of
|
||||
@ -92,16 +93,11 @@ impl DiagnosticDeriveBuilder {
|
||||
let attrs = structure
|
||||
.clone()
|
||||
.filter(|field_binding| {
|
||||
let attrs = &field_binding.ast().attrs;
|
||||
|
||||
(!attrs.is_empty()
|
||||
&& attrs.iter().all(|attr| {
|
||||
"subdiagnostic" != attr.path.segments.last().unwrap().ident.to_string()
|
||||
}))
|
||||
|| {
|
||||
subdiagnostics_or_empty.insert(field_binding.binding.clone());
|
||||
false
|
||||
}
|
||||
let ast = &field_binding.ast();
|
||||
!self.needs_move(ast) || {
|
||||
needs_moved.insert(field_binding.binding.clone());
|
||||
false
|
||||
}
|
||||
})
|
||||
.each(|field_binding| self.generate_field_attrs_code(field_binding));
|
||||
|
||||
@ -111,12 +107,41 @@ impl DiagnosticDeriveBuilder {
|
||||
// attributes or a `#[subdiagnostic]` attribute then it must be passed as an
|
||||
// argument to the diagnostic so that it can be referred to by Fluent messages.
|
||||
let args = structure
|
||||
.filter(|field_binding| subdiagnostics_or_empty.contains(&field_binding.binding))
|
||||
.filter(|field_binding| needs_moved.contains(&field_binding.binding))
|
||||
.each(|field_binding| self.generate_field_attrs_code(field_binding));
|
||||
|
||||
(attrs, args)
|
||||
}
|
||||
|
||||
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
|
||||
/// call (like `span_label`).
|
||||
fn should_generate_set_arg(&self, field: &Field) -> bool {
|
||||
field.attrs.is_empty()
|
||||
}
|
||||
|
||||
/// Returns `true` if `field` needs to have code generated in the by-move branch of the
|
||||
/// generated derive rather than the by-ref branch.
|
||||
fn needs_move(&self, field: &Field) -> bool {
|
||||
let generates_set_arg = self.should_generate_set_arg(field);
|
||||
let is_multispan = type_matches_path(&field.ty, &["rustc_errors", "MultiSpan"]);
|
||||
// FIXME(davidtwco): better support for one field needing to be in the by-move and
|
||||
// by-ref branches.
|
||||
let is_subdiagnostic = field
|
||||
.attrs
|
||||
.iter()
|
||||
.map(|attr| attr.path.segments.last().unwrap().ident.to_string())
|
||||
.any(|attr| attr == "subdiagnostic");
|
||||
|
||||
// `set_arg` calls take their argument by-move..
|
||||
generates_set_arg
|
||||
// If this is a `MultiSpan` field then it needs to be moved to be used by any
|
||||
// attribute..
|
||||
|| is_multispan
|
||||
// If this a `#[subdiagnostic]` then it needs to be moved as the other diagnostic is
|
||||
// unlikely to be `Copy`..
|
||||
|| is_subdiagnostic
|
||||
}
|
||||
|
||||
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
||||
/// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
|
||||
/// diagnostic builder calls for setting error code and creating note/help messages.
|
||||
@ -131,7 +156,7 @@ impl DiagnosticDeriveBuilder {
|
||||
let name = name.as_str();
|
||||
let meta = attr.parse_meta()?;
|
||||
|
||||
let is_help_or_note = matches!(name, "help" | "note");
|
||||
let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_");
|
||||
|
||||
let nested = match meta {
|
||||
// Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
|
||||
@ -139,8 +164,12 @@ impl DiagnosticDeriveBuilder {
|
||||
Meta::List(MetaList { ref nested, .. }) => nested,
|
||||
// Subdiagnostics without spans can be applied to the type too, and these are just
|
||||
// paths: `#[help]` and `#[note]`
|
||||
Meta::Path(_) if is_help_or_note => {
|
||||
let fn_name = proc_macro2::Ident::new(name, attr.span());
|
||||
Meta::Path(_) if is_help_note_or_warn => {
|
||||
let fn_name = if name == "warn_" {
|
||||
Ident::new("warn", attr.span())
|
||||
} else {
|
||||
Ident::new(name, attr.span())
|
||||
};
|
||||
return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
|
||||
}
|
||||
_ => throw_invalid_attr!(attr, &meta),
|
||||
@ -152,9 +181,11 @@ impl DiagnosticDeriveBuilder {
|
||||
"error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)),
|
||||
"warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)),
|
||||
"lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)),
|
||||
"help" | "note" => (),
|
||||
"help" | "note" | "warn_" => (),
|
||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help("only `error`, `warning`, `help` and `note` are valid attributes")
|
||||
diag.help(
|
||||
"only `error`, `warning`, `help`, `note` and `warn_` are valid attributes",
|
||||
)
|
||||
}),
|
||||
}
|
||||
|
||||
@ -163,14 +194,16 @@ impl DiagnosticDeriveBuilder {
|
||||
let mut nested_iter = nested.into_iter();
|
||||
if let Some(nested_attr) = nested_iter.next() {
|
||||
// Report an error if there are any other list items after the path.
|
||||
if is_help_or_note && nested_iter.next().is_some() {
|
||||
if is_help_note_or_warn && nested_iter.next().is_some() {
|
||||
throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
|
||||
diag.help("`help` and `note` struct attributes can only have one argument")
|
||||
diag.help(
|
||||
"`help`, `note` and `warn_` struct attributes can only have one argument",
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
match nested_attr {
|
||||
NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => {
|
||||
NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => {
|
||||
let fn_name = proc_macro2::Ident::new(name, attr.span());
|
||||
return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
|
||||
}
|
||||
@ -178,7 +211,7 @@ impl DiagnosticDeriveBuilder {
|
||||
self.slug.set_once((path.clone(), span));
|
||||
}
|
||||
NestedMeta::Meta(meta @ Meta::NameValue(_))
|
||||
if !is_help_or_note
|
||||
if !is_help_note_or_warn
|
||||
&& meta.path().segments.last().unwrap().ident.to_string() == "code" =>
|
||||
{
|
||||
// don't error for valid follow-up attributes
|
||||
@ -227,57 +260,55 @@ impl DiagnosticDeriveBuilder {
|
||||
let field = binding_info.ast();
|
||||
let field_binding = &binding_info.binding;
|
||||
|
||||
let inner_ty = FieldInnerTy::from_type(&field.ty);
|
||||
|
||||
// When generating `set_arg` or `add_subdiagnostic` calls, move data rather than
|
||||
// borrow it to avoid requiring clones - this must therefore be the last use of
|
||||
// each field (for example, any formatting machinery that might refer to a field
|
||||
// should be generated already).
|
||||
if field.attrs.is_empty() {
|
||||
if self.should_generate_set_arg(&field) {
|
||||
let diag = &self.diag;
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
quote! {
|
||||
return quote! {
|
||||
#diag.set_arg(
|
||||
stringify!(#ident),
|
||||
#field_binding
|
||||
);
|
||||
}
|
||||
} else {
|
||||
field
|
||||
.attrs
|
||||
.iter()
|
||||
.map(move |attr| {
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
|
||||
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
||||
("primary_span", FieldInnerTy::Vec(_)) => {
|
||||
(quote! { #field_binding.clone() }, false)
|
||||
}
|
||||
// `subdiagnostics` are not derefed because they are bound by value.
|
||||
("subdiagnostic", _) => (quote! { #field_binding }, true),
|
||||
_ => (quote! { *#field_binding }, true),
|
||||
};
|
||||
|
||||
let generated_code = self
|
||||
.generate_inner_field_code(
|
||||
attr,
|
||||
FieldInfo {
|
||||
binding: binding_info,
|
||||
ty: inner_ty.inner_type().unwrap_or(&field.ty),
|
||||
span: &field.span(),
|
||||
},
|
||||
binding,
|
||||
)
|
||||
.unwrap_or_else(|v| v.to_compile_error());
|
||||
|
||||
if needs_destructure {
|
||||
inner_ty.with(field_binding, generated_code)
|
||||
} else {
|
||||
generated_code
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
}
|
||||
|
||||
let needs_move = self.needs_move(&field);
|
||||
let inner_ty = FieldInnerTy::from_type(&field.ty);
|
||||
|
||||
field
|
||||
.attrs
|
||||
.iter()
|
||||
.map(move |attr| {
|
||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||
let needs_clone =
|
||||
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
|
||||
let (binding, needs_destructure) = if needs_clone {
|
||||
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
|
||||
(quote! { #field_binding.clone() }, false)
|
||||
} else if needs_move {
|
||||
(quote! { #field_binding }, true)
|
||||
} else {
|
||||
(quote! { *#field_binding }, true)
|
||||
};
|
||||
|
||||
let generated_code = self
|
||||
.generate_inner_field_code(
|
||||
attr,
|
||||
FieldInfo {
|
||||
binding: binding_info,
|
||||
ty: inner_ty.inner_type().unwrap_or(&field.ty),
|
||||
span: &field.span(),
|
||||
},
|
||||
binding,
|
||||
)
|
||||
.unwrap_or_else(|v| v.to_compile_error());
|
||||
|
||||
if needs_destructure {
|
||||
inner_ty.with(field_binding, generated_code)
|
||||
} else {
|
||||
generated_code
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn generate_inner_field_code(
|
||||
@ -324,10 +355,12 @@ impl DiagnosticDeriveBuilder {
|
||||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
|
||||
}
|
||||
"note" | "help" => {
|
||||
let path = match name {
|
||||
"note" => parse_quote! { _subdiag::note },
|
||||
"help" => parse_quote! { _subdiag::help },
|
||||
"note" | "help" | "warn_" => {
|
||||
let warn_ident = Ident::new("warn", Span::call_site());
|
||||
let (ident, path) = match name {
|
||||
"note" => (ident, parse_quote! { _subdiag::note }),
|
||||
"help" => (ident, parse_quote! { _subdiag::help }),
|
||||
"warn_" => (&warn_ident, parse_quote! { _subdiag::warn }),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
|
||||
@ -364,10 +397,10 @@ impl DiagnosticDeriveBuilder {
|
||||
"suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
|
||||
return self.generate_inner_field_code_suggestion(attr, info);
|
||||
}
|
||||
"label" | "help" | "note" => (),
|
||||
"label" | "help" | "note" | "warn_" => (),
|
||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||
diag.help(
|
||||
"only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \
|
||||
"only `label`, `help`, `note`, `warn` or `suggestion{,_short,_hidden,_verbose}` are \
|
||||
valid field attributes",
|
||||
)
|
||||
}),
|
||||
@ -396,7 +429,14 @@ impl DiagnosticDeriveBuilder {
|
||||
Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
|
||||
}
|
||||
"note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
|
||||
"note" | "help" => report_type_error(attr, "`Span` or `()`")?,
|
||||
// `warn_` must be special-cased because the attribute `warn` already has meaning and
|
||||
// so isn't used, despite the diagnostic API being named `warn`.
|
||||
"warn_" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => Ok(self
|
||||
.add_spanned_subdiagnostic(binding, &Ident::new("warn", Span::call_site()), msg)),
|
||||
"warn_" if type_is_unit(&info.ty) => {
|
||||
Ok(self.add_subdiagnostic(&Ident::new("warn", Span::call_site()), msg))
|
||||
}
|
||||
"note" | "help" | "warn_" => report_type_error(attr, "`Span` or `()`")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -260,10 +260,12 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
||||
#generated
|
||||
|
||||
pub mod _subdiag {
|
||||
pub const note: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
|
||||
pub const help: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
|
||||
pub const note: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
|
||||
pub const warn: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
|
||||
pub const label: crate::SubdiagnosticMessage =
|
||||
crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
|
||||
pub const suggestion: crate::SubdiagnosticMessage =
|
||||
|
@ -37,6 +37,8 @@ enum SubdiagnosticKind {
|
||||
Note,
|
||||
/// `#[help(...)]`
|
||||
Help,
|
||||
/// `#[warn_(...)]`
|
||||
Warn,
|
||||
/// `#[suggestion{,_short,_hidden,_verbose}]`
|
||||
Suggestion(SubdiagnosticSuggestionKind),
|
||||
}
|
||||
@ -49,6 +51,7 @@ impl FromStr for SubdiagnosticKind {
|
||||
"label" => Ok(SubdiagnosticKind::Label),
|
||||
"note" => Ok(SubdiagnosticKind::Note),
|
||||
"help" => Ok(SubdiagnosticKind::Help),
|
||||
"warn_" => Ok(SubdiagnosticKind::Warn),
|
||||
"suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
|
||||
"suggestion_short" => {
|
||||
Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
|
||||
@ -70,6 +73,7 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
||||
SubdiagnosticKind::Label => write!(f, "label"),
|
||||
SubdiagnosticKind::Note => write!(f, "note"),
|
||||
SubdiagnosticKind::Help => write!(f, "help"),
|
||||
SubdiagnosticKind::Warn => write!(f, "warn"),
|
||||
SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => {
|
||||
write!(f, "suggestion")
|
||||
}
|
||||
|
@ -85,7 +85,13 @@ pub(crate) fn report_error_if_not_applied_to_span(
|
||||
attr: &Attribute,
|
||||
info: &FieldInfo<'_>,
|
||||
) -> Result<(), DiagnosticDeriveError> {
|
||||
report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`")
|
||||
if !type_matches_path(&info.ty, &["rustc_span", "Span"])
|
||||
&& !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"])
|
||||
{
|
||||
report_type_error(attr, "`Span` or `MultiSpan`")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inner type of a field and type of wrapper.
|
||||
|
@ -130,8 +130,9 @@ decl_derive!(
|
||||
warning,
|
||||
error,
|
||||
lint,
|
||||
note,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
primary_span,
|
||||
@ -148,8 +149,9 @@ decl_derive!(
|
||||
warning,
|
||||
error,
|
||||
lint,
|
||||
note,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
primary_span,
|
||||
@ -166,6 +168,7 @@ decl_derive!(
|
||||
label,
|
||||
help,
|
||||
note,
|
||||
warn_,
|
||||
suggestion,
|
||||
suggestion_short,
|
||||
suggestion_hidden,
|
||||
|
@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -4,9 +4,10 @@
|
||||
//! conflicts between multiple such attributes attached to the same
|
||||
//! item.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
||||
use rustc_errors::{fluent, pluralize, struct_span_err, Applicability, MultiSpan};
|
||||
use rustc_expand::base::resolve_path;
|
||||
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir as hir;
|
||||
@ -175,16 +176,20 @@ impl CheckAttrVisitor<'_> {
|
||||
if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
|
||||
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
|
||||
{
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
let msg = match attr.style {
|
||||
ast::AttrStyle::Outer => {
|
||||
"crate-level attribute should be an inner attribute: add an exclamation \
|
||||
mark: `#![foo]`"
|
||||
}
|
||||
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
|
||||
};
|
||||
lint.build(msg).emit();
|
||||
});
|
||||
match attr.style {
|
||||
ast::AttrStyle::Outer => self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::OuterCrateLevelAttr,
|
||||
),
|
||||
ast::AttrStyle::Inner => self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::InnerCrateLevelAttr,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,37 +214,21 @@ impl CheckAttrVisitor<'_> {
|
||||
}
|
||||
|
||||
fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build(&format!(
|
||||
"`#[{sym}]` is ignored on struct fields, match arms and macro defs",
|
||||
))
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
)
|
||||
.note(
|
||||
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
|
||||
for more information",
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredAttrWithMacro { sym },
|
||||
);
|
||||
}
|
||||
|
||||
fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build(&format!("`#[{sym}]` is ignored on struct fields and match arms"))
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
)
|
||||
.note(
|
||||
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
|
||||
for more information",
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredAttr { sym },
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
||||
@ -249,9 +238,12 @@ impl CheckAttrVisitor<'_> {
|
||||
| Target::Closure
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[inline]` is ignored on function prototypes").emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredInlineAttrFnProto,
|
||||
);
|
||||
true
|
||||
}
|
||||
// FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
|
||||
@ -259,19 +251,12 @@ impl CheckAttrVisitor<'_> {
|
||||
// accidentally, to to be compatible with crates depending on them, we can't throw an
|
||||
// error here.
|
||||
Target::AssocConst => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[inline]` is ignored on constants")
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
)
|
||||
.note(
|
||||
"see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \
|
||||
for more information",
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredInlineAttrConstants,
|
||||
);
|
||||
true
|
||||
}
|
||||
// FIXME(#80564): Same for fields, arms, and macro defs
|
||||
@ -280,14 +265,10 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0518,
|
||||
"attribute should be applied to function or closure",
|
||||
)
|
||||
.span_label(span, "not a function or closure")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::InlineNotFnOrClosure {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -309,36 +290,40 @@ impl CheckAttrVisitor<'_> {
|
||||
|
||||
// function prototypes can't be covered
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredNoCoverageFnProto,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredNoCoveragePropagate,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
Target::Expression | Target::Statement | Target::Arm => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` may only be applied to function definitions")
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::IgnoredNoCoverageFnDefn,
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0788,
|
||||
"`#[no_coverage]` must be applied to coverable code",
|
||||
)
|
||||
.span_label(span, "not coverable code")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::IgnoredNoCoverageNotCoverable {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -389,14 +374,10 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"attribute should be applied to a function definition",
|
||||
)
|
||||
.span_label(span, "not a function definition")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -408,14 +389,10 @@ impl CheckAttrVisitor<'_> {
|
||||
Target::Fn
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"attribute should be applied to a function definition",
|
||||
)
|
||||
.span_label(span, "not a function definition")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -432,13 +409,7 @@ impl CheckAttrVisitor<'_> {
|
||||
) -> bool {
|
||||
match target {
|
||||
_ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr_span,
|
||||
E0736,
|
||||
"cannot use `#[track_caller]` with `#[naked]`",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::NakedTrackedCaller { attr_span });
|
||||
false
|
||||
}
|
||||
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
|
||||
@ -453,14 +424,9 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr_span,
|
||||
E0739,
|
||||
"attribute should be applied to function"
|
||||
)
|
||||
.span_label(span, "not a function")
|
||||
.emit();
|
||||
self.tcx
|
||||
.sess
|
||||
.emit_err(errors::TrackedCallerWrongLocation { attr_span, defn_span: span });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -485,14 +451,10 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0701,
|
||||
"attribute can only be applied to a struct or enum"
|
||||
)
|
||||
.span_label(span, "not a struct or enum")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::NonExhaustiveWrongLocation {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -511,11 +473,10 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "attribute can only be applied to a trait")
|
||||
.span_label(span, "not a trait")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -531,11 +492,10 @@ impl CheckAttrVisitor<'_> {
|
||||
match target {
|
||||
Target::Trait => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "attribute can only be applied to a trait")
|
||||
.span_label(span, "not a trait")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -555,16 +515,12 @@ impl CheckAttrVisitor<'_> {
|
||||
// FIXME: #[target_feature] was previously erroneously allowed on statements and some
|
||||
// crates used this, so only emit a warning.
|
||||
Target::Statement => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("attribute should be applied to a function")
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
)
|
||||
.span_label(span, "not a function")
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::TargetFeatureOnStatement,
|
||||
);
|
||||
true
|
||||
}
|
||||
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||
@ -576,11 +532,10 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "attribute should be applied to a function")
|
||||
.span_label(span, "not a function")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -591,24 +546,17 @@ impl CheckAttrVisitor<'_> {
|
||||
match target {
|
||||
Target::ForeignStatic | Target::Static => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "attribute should be applied to a static")
|
||||
.span_label(span, "not a static")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToStatic {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
&format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name),
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
|
||||
}
|
||||
|
||||
fn check_doc_alias_value(
|
||||
@ -621,22 +569,12 @@ impl CheckAttrVisitor<'_> {
|
||||
aliases: &mut FxHashMap<String, Span>,
|
||||
) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let err_fn = move |span: Span, msg: &str| {
|
||||
tcx.sess.span_err(
|
||||
span,
|
||||
&format!(
|
||||
"`#[doc(alias{})]` {}",
|
||||
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||
msg,
|
||||
),
|
||||
);
|
||||
false
|
||||
};
|
||||
let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
|
||||
let attr_str =
|
||||
&format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
|
||||
if doc_alias == kw::Empty {
|
||||
return err_fn(
|
||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
"attribute cannot have empty value",
|
||||
);
|
||||
tcx.sess.emit_err(errors::DocAliasEmpty { span, attr_str });
|
||||
return false;
|
||||
}
|
||||
|
||||
let doc_alias_str = doc_alias.as_str();
|
||||
@ -644,23 +582,16 @@ impl CheckAttrVisitor<'_> {
|
||||
.chars()
|
||||
.find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
|
||||
{
|
||||
self.tcx.sess.span_err(
|
||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
&format!(
|
||||
"{:?} character isn't allowed in `#[doc(alias{})]`",
|
||||
c,
|
||||
if is_list { "(\"...\")" } else { " = \"...\"" },
|
||||
),
|
||||
);
|
||||
tcx.sess.emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
|
||||
return false;
|
||||
}
|
||||
if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
|
||||
return err_fn(
|
||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
"cannot start or end with ' '",
|
||||
);
|
||||
tcx.sess.emit_err(errors::DocAliasStartEnd { span, attr_str });
|
||||
return false;
|
||||
}
|
||||
if let Some(err) = match target {
|
||||
|
||||
let span = meta.span();
|
||||
if let Some(location) = match target {
|
||||
Target::Impl => Some("implementation block"),
|
||||
Target::ForeignMod => Some("extern block"),
|
||||
Target::AssocTy => {
|
||||
@ -686,19 +617,21 @@ impl CheckAttrVisitor<'_> {
|
||||
Target::Param => return false,
|
||||
_ => None,
|
||||
} {
|
||||
return err_fn(meta.span(), &format!("isn't allowed on {}", err));
|
||||
tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
|
||||
return false;
|
||||
}
|
||||
let item_name = self.tcx.hir().name(hir_id);
|
||||
if item_name == doc_alias {
|
||||
return err_fn(meta.span(), "is the same as the item's name");
|
||||
tcx.sess.emit_err(errors::DocAliasNotAnAlias { span, attr_str });
|
||||
return false;
|
||||
}
|
||||
let span = meta.span();
|
||||
if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
|
||||
lint.build("doc alias is duplicated")
|
||||
.span_label(*entry.entry.get(), "first defined here")
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
span,
|
||||
errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
|
||||
);
|
||||
}
|
||||
true
|
||||
}
|
||||
@ -723,22 +656,12 @@ impl CheckAttrVisitor<'_> {
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
v.span(),
|
||||
"`#[doc(alias(\"a\"))]` expects string literals",
|
||||
)
|
||||
.emit();
|
||||
.emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
|
||||
errors += 1;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
v.span(),
|
||||
"`#[doc(alias(\"a\"))]` expects string literals",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
|
||||
errors += 1;
|
||||
}
|
||||
}
|
||||
@ -747,14 +670,7 @@ impl CheckAttrVisitor<'_> {
|
||||
} else if let Some(doc_alias) = meta.value_str() {
|
||||
self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \
|
||||
strings `#[doc(alias(\"a\", \"b\"))]`",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocAliasMalformed { span: meta.span() });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -771,35 +687,20 @@ impl CheckAttrVisitor<'_> {
|
||||
}) {
|
||||
Some(ItemKind::Mod(ref module)) => {
|
||||
if !module.item_ids.is_empty() {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"`#[doc(keyword = \"...\")]` can only be used on empty modules",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"`#[doc(keyword = \"...\")]` can only be used on modules",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocKeywordNotMod { span: meta.span() });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if !rustc_lexer::is_ident(doc_keyword.as_str()) {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
&format!("`{doc_keyword}` is not a valid identifier"),
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocKeywordInvalidIdent {
|
||||
span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
|
||||
doc_keyword,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
true
|
||||
@ -812,24 +713,12 @@ impl CheckAttrVisitor<'_> {
|
||||
}) {
|
||||
Some(ItemKind::Impl(ref i)) => {
|
||||
if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"`#[doc(keyword = \"...\")]` can only be used on impl blocks",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -858,13 +747,9 @@ impl CheckAttrVisitor<'_> {
|
||||
if let Some((prev_inline, prev_span)) = *specified_inline {
|
||||
if do_inline != prev_inline {
|
||||
let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
|
||||
spans.push_span_label(prev_span, "this attribute...");
|
||||
spans.push_span_label(meta.span(), "...conflicts with this attribute");
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(spans, "conflicting doc inlining attributes")
|
||||
.help("remove one of the conflicting attributes")
|
||||
.emit();
|
||||
spans.push_span_label(prev_span, fluent::passes::doc_inline_conflict_first);
|
||||
spans.push_span_label(meta.span(), fluent::passes::doc_inline_conflict_second);
|
||||
self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
|
||||
return false;
|
||||
}
|
||||
true
|
||||
@ -873,23 +758,14 @@ impl CheckAttrVisitor<'_> {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
|lint| {
|
||||
let mut err = lint.build(
|
||||
"this attribute can only be applied to a `use` item",
|
||||
);
|
||||
err.span_label(meta.span(), "only applicable on `use` items");
|
||||
if attr.style == AttrStyle::Outer {
|
||||
err.span_label(
|
||||
self.tcx.hir().span(hir_id),
|
||||
"not a `use` item",
|
||||
);
|
||||
}
|
||||
err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
|
||||
.emit();
|
||||
errors::DocInlineOnlyUse {
|
||||
attr_span: meta.span(),
|
||||
item_span: (attr.style == AttrStyle::Outer)
|
||||
.then(|| self.tcx.hir().span(hir_id)),
|
||||
},
|
||||
);
|
||||
false
|
||||
@ -904,15 +780,7 @@ impl CheckAttrVisitor<'_> {
|
||||
attr_name: &str,
|
||||
) -> bool {
|
||||
if CRATE_HIR_ID == hir_id {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
&format!(
|
||||
"`#![doc({attr_name} = \"...\")]` isn't allowed as a crate-level attribute",
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
|
||||
return false;
|
||||
}
|
||||
true
|
||||
@ -926,36 +794,25 @@ impl CheckAttrVisitor<'_> {
|
||||
hir_id: HirId,
|
||||
) -> bool {
|
||||
if hir_id != CRATE_HIR_ID {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
|lint| {
|
||||
let mut err = lint.build(
|
||||
"this attribute can only be applied at the crate level",
|
||||
);
|
||||
if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID {
|
||||
if let Ok(mut src) =
|
||||
self.tcx.sess.source_map().span_to_snippet(attr.span)
|
||||
{
|
||||
src.insert(1, '!');
|
||||
err.span_suggestion_verbose(
|
||||
attr.span,
|
||||
"to apply to the crate, use an inner attribute",
|
||||
src,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_help(
|
||||
attr.span,
|
||||
"to apply to the crate, use an inner attribute",
|
||||
);
|
||||
}
|
||||
self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
|
||||
let mut err = lint.build(fluent::passes::attr_crate_level);
|
||||
if attr.style == AttrStyle::Outer
|
||||
&& self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID
|
||||
{
|
||||
if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
|
||||
src.insert(1, '!');
|
||||
err.span_suggestion_verbose(
|
||||
attr.span,
|
||||
fluent::passes::suggestion,
|
||||
src,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_help(attr.span, fluent::passes::help);
|
||||
}
|
||||
err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information")
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
err.note(fluent::passes::note).emit();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
true
|
||||
@ -970,18 +827,14 @@ impl CheckAttrVisitor<'_> {
|
||||
match i_meta.name_or_empty() {
|
||||
sym::attr | sym::no_crate_inject => {}
|
||||
_ => {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span(),
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"unknown `doc(test)` attribute `{}`",
|
||||
rustc_ast_pretty::pprust::path_to_string(
|
||||
&i_meta.meta_item().unwrap().path
|
||||
),
|
||||
))
|
||||
.emit();
|
||||
errors::DocTestUnknown {
|
||||
path: rustc_ast_pretty::pprust::path_to_string(
|
||||
&i_meta.meta_item().unwrap().path,
|
||||
),
|
||||
},
|
||||
);
|
||||
is_valid = false;
|
||||
@ -989,9 +842,12 @@ impl CheckAttrVisitor<'_> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
|
||||
lint.build("`#[doc(test(...)]` takes a list of attributes").emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
errors::DocTestTakesList,
|
||||
);
|
||||
is_valid = false;
|
||||
}
|
||||
is_valid
|
||||
@ -1093,79 +949,66 @@ impl CheckAttrVisitor<'_> {
|
||||
|
||||
sym::primitive => {
|
||||
if !self.tcx.features().rustdoc_internals {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
|lint| {
|
||||
let mut diag = lint.build(
|
||||
"`doc(primitive)` should never have been stable",
|
||||
);
|
||||
diag.emit();
|
||||
},
|
||||
errors::DocPrimitive,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
|lint| {
|
||||
let mut diag = lint.build(&format!(
|
||||
"unknown `doc` attribute `{}`",
|
||||
rustc_ast_pretty::pprust::path_to_string(&i_meta.path),
|
||||
));
|
||||
if i_meta.has_name(sym::spotlight) {
|
||||
diag.note(
|
||||
"`doc(spotlight)` was renamed to `doc(notable_trait)`",
|
||||
);
|
||||
diag.span_suggestion_short(
|
||||
i_meta.span,
|
||||
"use `notable_trait` instead",
|
||||
"notable_trait",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.note("`doc(spotlight)` is now a no-op");
|
||||
let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
|
||||
if i_meta.has_name(sym::spotlight) {
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
errors::DocTestUnknownSpotlight {
|
||||
path,
|
||||
span: i_meta.span
|
||||
}
|
||||
if i_meta.has_name(sym::include) {
|
||||
if let Some(value) = i_meta.value_str() {
|
||||
// if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
|
||||
let applicability = if list.len() == 1 {
|
||||
Applicability::MachineApplicable
|
||||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
let inner = if attr.style == AttrStyle::Inner {
|
||||
"!"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
diag.span_suggestion(
|
||||
attr.meta().unwrap().span,
|
||||
"use `doc = include_str!` instead",
|
||||
format!(
|
||||
"#{inner}[doc = include_str!(\"{value}\")]",
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
);
|
||||
} else if i_meta.has_name(sym::include) &&
|
||||
let Some(value) = i_meta.value_str() {
|
||||
let applicability = if list.len() == 1 {
|
||||
Applicability::MachineApplicable
|
||||
} else {
|
||||
Applicability::MaybeIncorrect
|
||||
};
|
||||
// If there are multiple attributes, the suggestion would suggest
|
||||
// deleting all of them, which is incorrect.
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
errors::DocTestUnknownInclude {
|
||||
path,
|
||||
value: value.to_string(),
|
||||
inner: (attr.style == AttrStyle::Inner)
|
||||
.then_some("!")
|
||||
.unwrap_or(""),
|
||||
sugg: (attr.meta().unwrap().span, applicability),
|
||||
}
|
||||
diag.emit();
|
||||
},
|
||||
);
|
||||
);
|
||||
} else {
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
errors::DocTestUnknownAny { path }
|
||||
);
|
||||
}
|
||||
is_valid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
|lint| {
|
||||
lint.build("invalid `doc` attribute").emit();
|
||||
},
|
||||
errors::DocInvalid,
|
||||
);
|
||||
is_valid = false;
|
||||
}
|
||||
@ -1180,14 +1023,7 @@ impl CheckAttrVisitor<'_> {
|
||||
match target {
|
||||
Target::Struct | Target::Enum | Target::TyAlias => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"`pass_by_value` attribute should be applied to a struct, enum or type alias.",
|
||||
)
|
||||
.span_label(span, "is not a struct, enum or type alias")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::PassByValue { attr_span: attr.span, span });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1197,14 +1033,7 @@ impl CheckAttrVisitor<'_> {
|
||||
match target {
|
||||
Target::Method(MethodKind::Inherent) => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"`rustc_allow_incoherent_impl` attribute should be applied to impl items.",
|
||||
)
|
||||
.span_label(span, "the only currently supported targets are inherent methods")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1223,12 +1052,7 @@ impl CheckAttrVisitor<'_> {
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
"`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.",
|
||||
)
|
||||
.span_label(span, "only adts, extern types and traits are supported")
|
||||
.emit();
|
||||
.emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1238,19 +1062,12 @@ impl CheckAttrVisitor<'_> {
|
||||
fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
|
||||
let node = self.tcx.hir().get(hir_id);
|
||||
if let Some(kind) = node.fn_kind() && let rustc_hir::IsAsync::Async = kind.asyncness() {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build(
|
||||
"`must_use` attribute on `async` functions \
|
||||
applies to the anonymous `Future` returned by the \
|
||||
function, not the value within",
|
||||
)
|
||||
.span_label(
|
||||
span,
|
||||
"this attribute does nothing, the `Future`s \
|
||||
returned by async functions are already `must_use`",
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::MustUseAsync { span }
|
||||
);
|
||||
}
|
||||
|
||||
if !matches!(
|
||||
@ -1278,12 +1095,12 @@ impl CheckAttrVisitor<'_> {
|
||||
_ => "a",
|
||||
};
|
||||
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build(&format!(
|
||||
"`#[must_use]` has no effect when applied to {article} {target}"
|
||||
))
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::MustUseNoEffect { article, target },
|
||||
);
|
||||
}
|
||||
|
||||
// For now, its always valid
|
||||
@ -1295,11 +1112,7 @@ impl CheckAttrVisitor<'_> {
|
||||
match target {
|
||||
Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
|
||||
_ => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
|
||||
.span_label(span, "is not a struct, enum, or trait")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1319,16 +1132,12 @@ impl CheckAttrVisitor<'_> {
|
||||
_ => {
|
||||
// FIXME: #[cold] was previously allowed on non-functions and some crates used
|
||||
// this, so only emit a warning.
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("attribute should be applied to a function")
|
||||
.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
)
|
||||
.span_label(span, "not a function")
|
||||
.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::Cold { span },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1343,19 +1152,12 @@ impl CheckAttrVisitor<'_> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
let mut diag =
|
||||
lint.build("attribute should be applied to an `extern` block with non-Rust ABI");
|
||||
diag.warn(
|
||||
"this was previously accepted by the compiler but is \
|
||||
being phased out; it will become a hard error in \
|
||||
a future release!",
|
||||
);
|
||||
if target != Target::ForeignMod {
|
||||
diag.span_label(span, "not an `extern` block");
|
||||
}
|
||||
diag.emit();
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::Link { span: (target != Target::ForeignMod).then_some(span) },
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
|
||||
|
362
compiler/rustc_passes/src/errors.rs
Normal file
362
compiler/rustc_passes/src/errors.rs
Normal file
@ -0,0 +1,362 @@
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_macros::{LintDiagnostic, SessionDiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::outer_crate_level_attr)]
|
||||
pub struct OuterCrateLevelAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::inner_crate_level_attr)]
|
||||
pub struct InnerCrateLevelAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::ignored_attr_with_macro)]
|
||||
pub struct IgnoredAttrWithMacro<'a> {
|
||||
pub sym: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::ignored_attr)]
|
||||
pub struct IgnoredAttr<'a> {
|
||||
pub sym: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::inline_ignored_function_prototype)]
|
||||
pub struct IgnoredInlineAttrFnProto;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::inline_ignored_constants)]
|
||||
#[warn_]
|
||||
#[note]
|
||||
pub struct IgnoredInlineAttrConstants;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::inline_not_fn_or_closure, code = "E0518")]
|
||||
pub struct InlineNotFnOrClosure {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::no_coverage_ignored_function_prototype)]
|
||||
pub struct IgnoredNoCoverageFnProto;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::no_coverage_propagate)]
|
||||
pub struct IgnoredNoCoveragePropagate;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::no_coverage_fn_defn)]
|
||||
pub struct IgnoredNoCoverageFnDefn;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::no_coverage_not_coverable, code = "E0788")]
|
||||
pub struct IgnoredNoCoverageNotCoverable {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::should_be_applied_to_fn)]
|
||||
pub struct AttrShouldBeAppliedToFn {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::naked_tracked_caller, code = "E0736")]
|
||||
pub struct NakedTrackedCaller {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::should_be_applied_to_fn, code = "E0739")]
|
||||
pub struct TrackedCallerWrongLocation {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::should_be_applied_to_struct_enum, code = "E0701")]
|
||||
pub struct NonExhaustiveWrongLocation {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::should_be_applied_to_trait)]
|
||||
pub struct AttrShouldBeAppliedToTrait {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::target_feature_on_statement)]
|
||||
pub struct TargetFeatureOnStatement;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::should_be_applied_to_static)]
|
||||
pub struct AttrShouldBeAppliedToStatic {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_expect_str)]
|
||||
pub struct DocExpectStr<'a> {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
pub attr_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_empty)]
|
||||
pub struct DocAliasEmpty<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_bad_char)]
|
||||
pub struct DocAliasBadChar<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_str: &'a str,
|
||||
pub char_: char,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_start_end)]
|
||||
pub struct DocAliasStartEnd<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_bad_location)]
|
||||
pub struct DocAliasBadLocation<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_str: &'a str,
|
||||
pub location: &'a str,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_not_an_alias)]
|
||||
pub struct DocAliasNotAnAlias<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_alias_duplicated)]
|
||||
pub struct DocAliasDuplicated {
|
||||
#[label]
|
||||
pub first_defn: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_not_string_literal)]
|
||||
pub struct DocAliasNotStringLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_alias_malformed)]
|
||||
pub struct DocAliasMalformed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_keyword_empty_mod)]
|
||||
pub struct DocKeywordEmptyMod {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_keyword_not_mod)]
|
||||
pub struct DocKeywordNotMod {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_keyword_invalid_ident)]
|
||||
pub struct DocKeywordInvalidIdent {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub doc_keyword: Symbol,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_tuple_variadic_not_first)]
|
||||
pub struct DocTupleVariadicNotFirst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_keyword_only_impl)]
|
||||
pub struct DocKeywordOnlyImpl {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_inline_conflict)]
|
||||
#[help]
|
||||
pub struct DocKeywordConflict {
|
||||
#[primary_span]
|
||||
pub spans: MultiSpan,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_inline_only_use)]
|
||||
#[note]
|
||||
pub struct DocInlineOnlyUse {
|
||||
#[label]
|
||||
pub attr_span: Span,
|
||||
#[label(passes::not_a_use_item_label)]
|
||||
pub item_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::doc_attr_not_crate_level)]
|
||||
pub struct DocAttrNotCrateLevel<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub attr_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_test_unknown)]
|
||||
pub struct DocTestUnknown {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_test_takes_list)]
|
||||
pub struct DocTestTakesList;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_primitive)]
|
||||
pub struct DocPrimitive;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_test_unknown_any)]
|
||||
pub struct DocTestUnknownAny {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_test_unknown_spotlight)]
|
||||
#[note]
|
||||
#[note(passes::no_op_note)]
|
||||
pub struct DocTestUnknownSpotlight {
|
||||
pub path: String,
|
||||
#[suggestion_short(applicability = "machine-applicable", code = "notable_trait")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_test_unknown_include)]
|
||||
pub struct DocTestUnknownInclude {
|
||||
pub path: String,
|
||||
pub value: String,
|
||||
pub inner: &'static str,
|
||||
#[suggestion(code = "#{inner}[doc = include_str!(\"{value}\")]")]
|
||||
pub sugg: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::doc_invalid)]
|
||||
pub struct DocInvalid;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::pass_by_value)]
|
||||
pub struct PassByValue {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::allow_incoherent_impl)]
|
||||
pub struct AllowIncoherentImpl {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::has_incoherent_inherent_impl)]
|
||||
pub struct HasIncoherentInherentImpl {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::must_use_async)]
|
||||
pub struct MustUseAsync {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::must_use_no_effect)]
|
||||
pub struct MustUseNoEffect {
|
||||
pub article: &'static str,
|
||||
pub target: rustc_hir::Target,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(passes::must_not_suspend)]
|
||||
pub struct MustNotSuspend {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::cold)]
|
||||
#[warn_]
|
||||
pub struct Cold {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(passes::link)]
|
||||
#[warn_]
|
||||
pub struct Link {
|
||||
#[label]
|
||||
pub span: Option<Span>,
|
||||
}
|
@ -7,8 +7,8 @@
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_else)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(let_else)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(try_blocks)]
|
||||
@ -27,6 +27,7 @@ pub mod dead;
|
||||
mod debugger_visualizer;
|
||||
mod diagnostic_items;
|
||||
pub mod entry;
|
||||
mod errors;
|
||||
pub mod hir_id_validator;
|
||||
pub mod hir_stats;
|
||||
mod lang_items;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
@ -73,3 +73,19 @@ pub struct InPublicInterface<'a> {
|
||||
#[label(privacy::visibility_label)]
|
||||
pub vis_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(privacy::from_private_dep_in_public_interface)]
|
||||
pub struct FromPrivateDependencyInPublicInterface<'a> {
|
||||
pub kind: &'a str,
|
||||
pub descr: String,
|
||||
pub krate: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[lint(privacy::private_in_public_lint)]
|
||||
pub struct PrivateInPublicLint<'a> {
|
||||
pub vis_descr: &'static str,
|
||||
pub kind: &'a str,
|
||||
pub descr: String,
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ use std::ops::ControlFlow;
|
||||
use std::{cmp, fmt, mem};
|
||||
|
||||
use errors::{
|
||||
FieldIsPrivate, FieldIsPrivateLabel, InPublicInterface, InPublicInterfaceTraits, ItemIsPrivate,
|
||||
UnnamedItemIsPrivate,
|
||||
FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
|
||||
InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate,
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1716,19 +1716,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
|
||||
|
||||
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
if self.leaks_private_dep(def_id) {
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
|
||||
self.tcx.hir().local_def_id_to_hir_id(self.item_def_id),
|
||||
self.tcx.def_span(self.item_def_id.to_def_id()),
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} `{}` from private dependency '{}' in public \
|
||||
interface",
|
||||
kind,
|
||||
descr,
|
||||
self.tcx.crate_name(def_id.krate)
|
||||
))
|
||||
.emit();
|
||||
FromPrivateDependencyInPublicInterface {
|
||||
kind,
|
||||
descr: descr.to_string(),
|
||||
krate: self.tcx.crate_name(def_id.krate),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -1754,12 +1749,14 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
|
||||
}
|
||||
};
|
||||
let span = self.tcx.def_span(self.item_def_id.to_def_id());
|
||||
let descr = descr.to_string();
|
||||
if self.has_old_errors
|
||||
|| self.in_assoc_ty
|
||||
|| self.tcx.resolutions(()).has_pub_restricted
|
||||
{
|
||||
let descr = descr.to_string();
|
||||
let vis_span = self.tcx.def_span(def_id);
|
||||
let vis_span =
|
||||
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
|
||||
if kind == "trait" {
|
||||
self.tcx.sess.emit_err(InPublicInterfaceTraits {
|
||||
span,
|
||||
@ -1778,19 +1775,11 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let err_code = if kind == "trait" { "E0445" } else { "E0446" };
|
||||
self.tcx.struct_span_lint_hir(
|
||||
self.tcx.emit_spanned_lint(
|
||||
lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
hir_id,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build(&format!(
|
||||
"{} (error {})",
|
||||
format!("{} {} `{}` in public interface", vis_descr, kind, descr),
|
||||
err_code
|
||||
))
|
||||
.emit();
|
||||
},
|
||||
PrivateInPublicLint { vis_descr, kind, descr },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ LL | #![deny(warnings)]
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
help: to apply to the crate, use an inner attribute
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
@ -29,7 +29,7 @@ LL | pub fn foo() {}
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:15:12
|
||||
@ -39,7 +39,7 @@ LL | #![doc(test(no_crate_inject))]
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: conflicting doc inlining attributes
|
||||
--> $DIR/invalid-doc-attr.rs:28:7
|
||||
@ -59,7 +59,7 @@ LL | #[doc(test(no_crate_inject))]
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:22:11
|
||||
@ -72,7 +72,7 @@ LL | pub fn baz() {}
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -23,7 +23,7 @@ extern crate rustc_middle;
|
||||
use rustc_middle::ty::Ty;
|
||||
|
||||
extern crate rustc_errors;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
|
||||
extern crate rustc_session;
|
||||
|
||||
@ -140,7 +140,7 @@ struct CodeNotProvided {}
|
||||
#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
struct MessageWrongType {
|
||||
#[primary_span]
|
||||
//~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span`
|
||||
//~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
foo: String,
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ struct ErrorWithField {
|
||||
#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
struct ErrorWithMessageAppliedToField {
|
||||
#[label(typeck::label)]
|
||||
//~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
|
||||
//~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
name: String,
|
||||
}
|
||||
|
||||
@ -208,7 +208,7 @@ struct LabelOnSpan {
|
||||
#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
struct LabelOnNonSpan {
|
||||
#[label(typeck::label)]
|
||||
//~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span`
|
||||
//~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
id: u32,
|
||||
}
|
||||
|
||||
@ -538,7 +538,7 @@ struct LabelWithTrailingList {
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[lint(typeck::ambiguous_lifetime_bound)]
|
||||
//~^ ERROR only `#[error(..)]` and `#[warn(..)]` are supported
|
||||
//~^ ERROR only `#[error(..)]` and `#[warning(..)]` are supported
|
||||
struct LintsBad {
|
||||
}
|
||||
|
||||
@ -552,3 +552,17 @@ struct LintsGood {
|
||||
//~^ ERROR only `#[lint(..)]` is supported
|
||||
struct ErrorsBad {
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
struct ErrorWithMultiSpan {
|
||||
#[primary_span]
|
||||
span: MultiSpan,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
#[warn_]
|
||||
struct ErrorWithWarn {
|
||||
val: String,
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ error: `#[nonsense(...)]` is not a valid attribute
|
||||
LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: only `error`, `warning`, `help` and `note` are valid attributes
|
||||
= help: only `error`, `warning`, `help`, `note` and `warn_` are valid attributes
|
||||
|
||||
error: diagnostic kind not specified
|
||||
--> $DIR/diagnostic-derive.rs:53:1
|
||||
@ -233,7 +233,7 @@ LL | | struct SlugNotProvided {}
|
||||
|
|
||||
= help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
|
||||
|
||||
error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
|
||||
error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:142:5
|
||||
|
|
||||
LL | #[primary_span]
|
||||
@ -247,7 +247,7 @@ LL | #[nonsense]
|
||||
|
|
||||
= help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
|
||||
|
||||
error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
|
||||
error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:167:5
|
||||
|
|
||||
LL | #[label(typeck::label)]
|
||||
@ -279,7 +279,7 @@ LL | #[derive(SessionDiagnostic)]
|
||||
= note: if you intended to print `}`, you can escape it using `}}`
|
||||
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
|
||||
error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:210:5
|
||||
|
|
||||
LL | #[label(typeck::label)]
|
||||
@ -363,7 +363,7 @@ error: `#[label(...)]` is not a valid attribute
|
||||
LL | #[label(typeck::label, foo("..."))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: only `#[error(..)]` and `#[warn(..)]` are supported
|
||||
error: only `#[error(..)]` and `#[warning(..)]` are supported
|
||||
--> $DIR/diagnostic-derive.rs:540:1
|
||||
|
|
||||
LL | / #[lint(typeck::ambiguous_lifetime_bound)]
|
||||
|
@ -244,7 +244,7 @@ enum V {
|
||||
//~^ ERROR label without `#[primary_span]` field
|
||||
struct W {
|
||||
#[primary_span]
|
||||
//~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span`
|
||||
//~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
span: String,
|
||||
}
|
||||
|
||||
@ -508,3 +508,15 @@ enum AX {
|
||||
span: Span,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[warn_(parser::add_paren)]
|
||||
struct AY {
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
#[warn_(parser::add_paren)]
|
||||
struct AZ {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ error: subdiagnostic kind not specified
|
||||
LL | B {
|
||||
| ^
|
||||
|
||||
error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
|
||||
error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/subdiagnostic-derive.rs:246:5
|
||||
|
|
||||
LL | #[primary_span]
|
||||
|
@ -12,7 +12,7 @@ LL | #![deny(warnings)]
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
help: to apply to the crate, use an inner attribute
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
@ -29,7 +29,7 @@ LL | pub fn foo() {}
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:15:12
|
||||
@ -39,7 +39,7 @@ LL | #![doc(test(no_crate_inject))]
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: conflicting doc inlining attributes
|
||||
--> $DIR/invalid-doc-attr.rs:28:7
|
||||
@ -59,7 +59,7 @@ LL | #[doc(test(no_crate_inject))]
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:22:11
|
||||
@ -72,7 +72,7 @@ LL | pub fn baz() {}
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -7,14 +7,14 @@ LL | #[inline]
|
||||
LL | const FOO: u8 = 0;
|
||||
| ------------------ not a function or closure
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/multiple-invalid.rs:6:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | const FOO: u8 = 0;
|
||||
| ------------------ not a function
|
||||
| ------------------ not a function definition
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -259,7 +259,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
||||
LL | #[no_std]
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:1
|
||||
|
|
||||
LL | #[cold]
|
||||
@ -272,7 +272,7 @@ LL | | mod inner { #![cold] }
|
||||
... |
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- not a function
|
||||
| |_- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
@ -399,7 +399,7 @@ warning: `#[proc_macro_derive]` only has an effect on functions
|
||||
LL | #![proc_macro_derive()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
|
||||
|
|
||||
LL | #![cold]
|
||||
@ -743,35 +743,35 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
||||
LL | #[no_std] impl S { }
|
||||
| ^^^^^^^^^
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17
|
||||
|
|
||||
LL | mod inner { #![cold] }
|
||||
| ------------^^^^^^^^-- not a function
|
||||
| ------------^^^^^^^^-- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
|
||||
|
|
||||
LL | #[cold] struct S;
|
||||
| ^^^^^^^ --------- not a function
|
||||
| ^^^^^^^ --------- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
|
||||
|
|
||||
LL | #[cold] type T = S;
|
||||
| ^^^^^^^ ----------- not a function
|
||||
| ^^^^^^^ ----------- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
warning: attribute should be applied to a function
|
||||
warning: attribute should be applied to a function definition
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
|
||||
|
|
||||
LL | #[cold] impl S { }
|
||||
| ^^^^^^^ ---------- not a function
|
||||
| ^^^^^^^ ---------- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
|
@ -22,7 +22,7 @@ LL | #![deny(future_incompatible)]
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]`
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-54044.rs:3:1
|
||||
|
|
||||
LL | #[cold]
|
||||
| ^^^^^^^
|
||||
...
|
||||
LL | struct Foo;
|
||||
| ----------- not a function
|
||||
| ----------- not a function definition
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-54044.rs:1:9
|
||||
@ -14,14 +14,14 @@ LL | #![deny(unused_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-54044.rs:9:5
|
||||
|
|
||||
LL | #[cold]
|
||||
| ^^^^^^^
|
||||
...
|
||||
LL | 5;
|
||||
| - not a function
|
||||
| - not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
|
@ -4,11 +4,11 @@ error[E0518]: attribute should be applied to function or closure
|
||||
LL | pub struct Foo<#[inline] const N: usize>;
|
||||
| ^^^^^^^^^ -------------- not a function or closure
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-78957.rs:7:16
|
||||
|
|
||||
LL | pub struct Bar<#[cold] const N: usize>;
|
||||
| ^^^^^^^ -------------- not a function
|
||||
| ^^^^^^^ -------------- not a function definition
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/issue-78957.rs:1:9
|
||||
@ -29,11 +29,11 @@ error[E0518]: attribute should be applied to function or closure
|
||||
LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
|
||||
| ^^^^^^^^^ -- not a function or closure
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-78957.rs:15:17
|
||||
|
|
||||
LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
|
||||
| ^^^^^^^ -- not a function
|
||||
| ^^^^^^^ -- not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
@ -49,11 +49,11 @@ error[E0518]: attribute should be applied to function or closure
|
||||
LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
|
||||
| ^^^^^^^^^ - not a function or closure
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-78957.rs:23:17
|
||||
|
|
||||
LL | pub struct Bar3<#[cold] T>(PhantomData<T>);
|
||||
| ^^^^^^^ - not a function
|
||||
| ^^^^^^^ - not a function definition
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/issue-68060.rs:4:13
|
||||
|
|
||||
LL | #[target_feature(enable = "")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | |_| (),
|
||||
| ------ not a function
|
||||
| ------ not a function definition
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
struct Struct {}
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
impl Struct {}
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
union Union {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
const CONST: usize = 10;
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
fn function() {}
|
||||
|
||||
#[marker] //~ ERROR attribute can only be applied to a trait
|
||||
#[marker] //~ ERROR attribute should be applied to a trait
|
||||
type Type = ();
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:3:1
|
||||
|
|
||||
LL | #[marker]
|
||||
@ -6,7 +6,7 @@ LL | #[marker]
|
||||
LL | struct Struct {}
|
||||
| ---------------- not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:6:1
|
||||
|
|
||||
LL | #[marker]
|
||||
@ -14,7 +14,7 @@ LL | #[marker]
|
||||
LL | impl Struct {}
|
||||
| -------------- not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:9:1
|
||||
|
|
||||
LL | #[marker]
|
||||
@ -24,7 +24,7 @@ LL | | x: i32,
|
||||
LL | | }
|
||||
| |_- not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:14:1
|
||||
|
|
||||
LL | #[marker]
|
||||
@ -32,7 +32,7 @@ LL | #[marker]
|
||||
LL | const CONST: usize = 10;
|
||||
| ------------------------ not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:17:1
|
||||
|
|
||||
LL | #[marker]
|
||||
@ -40,7 +40,7 @@ LL | #[marker]
|
||||
LL | fn function() {}
|
||||
| ---------------- not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/marker-attribute-on-non-trait.rs:20:1
|
||||
|
|
||||
LL | #[marker]
|
||||
|
@ -3,11 +3,11 @@
|
||||
struct Foo;
|
||||
|
||||
#[non_exhaustive]
|
||||
//~^ ERROR attribute can only be applied to a struct or enum [E0701]
|
||||
//~^ ERROR attribute should be applied to a struct or enum [E0701]
|
||||
trait Bar { }
|
||||
|
||||
#[non_exhaustive]
|
||||
//~^ ERROR attribute can only be applied to a struct or enum [E0701]
|
||||
//~^ ERROR attribute should be applied to a struct or enum [E0701]
|
||||
union Baz {
|
||||
f1: u16,
|
||||
f2: u16
|
||||
|
@ -4,7 +4,7 @@ error: malformed `non_exhaustive` attribute input
|
||||
LL | #[non_exhaustive(anything)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[non_exhaustive]`
|
||||
|
||||
error[E0701]: attribute can only be applied to a struct or enum
|
||||
error[E0701]: attribute should be applied to a struct or enum
|
||||
--> $DIR/invalid-attribute.rs:5:1
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
@ -13,7 +13,7 @@ LL |
|
||||
LL | trait Bar { }
|
||||
| ------------- not a struct or enum
|
||||
|
||||
error[E0701]: attribute can only be applied to a struct or enum
|
||||
error[E0701]: attribute should be applied to a struct or enum
|
||||
--> $DIR/invalid-attribute.rs:9:1
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
|
@ -1,5 +1,5 @@
|
||||
#[track_caller]
|
||||
struct S;
|
||||
//~^^ ERROR attribute should be applied to function
|
||||
//~^^ ERROR attribute should be applied to a function definition
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,10 +1,10 @@
|
||||
error[E0739]: attribute should be applied to function
|
||||
error[E0739]: attribute should be applied to a function definition
|
||||
--> $DIR/only-for-fns.rs:1:1
|
||||
|
|
||||
LL | #[track_caller]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | struct S;
|
||||
| --------- not a function
|
||||
| --------- not a function definition
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -15,6 +15,6 @@ fn foo() {}
|
||||
// Regression test for the ICE described in #83512.
|
||||
trait Foo {
|
||||
#[doc(keyword = "match")]
|
||||
//~^ ERROR: `#[doc(keyword = "...")]` can only be used on modules
|
||||
//~^ ERROR: `#[doc(keyword = "...")]` should be used on modules
|
||||
fn quux() {}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
error: `#[doc(keyword = "...")]` can only be used on empty modules
|
||||
error: `#[doc(keyword = "...")]` should be used on empty modules
|
||||
--> $DIR/doc_keyword.rs:6:7
|
||||
|
|
||||
LL | #[doc(keyword = "hell")]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[doc(keyword = "...")]` can only be used on modules
|
||||
error: `#[doc(keyword = "...")]` should be used on modules
|
||||
--> $DIR/doc_keyword.rs:11:7
|
||||
|
|
||||
LL | #[doc(keyword = "hall")]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[doc(keyword = "...")]` can only be used on modules
|
||||
error: `#[doc(keyword = "...")]` should be used on modules
|
||||
--> $DIR/doc_keyword.rs:17:11
|
||||
|
|
||||
LL | #[doc(keyword = "match")]
|
||||
|
@ -34,43 +34,43 @@ LL | fn bar() {}
|
||||
= note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information
|
||||
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:34:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | mod another {}
|
||||
| -------------- not a function
|
||||
| -------------- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:39:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | const FOO: usize = 7;
|
||||
| --------------------- not a function
|
||||
| --------------------- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:44:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | struct Foo;
|
||||
| ----------- not a function
|
||||
| ----------- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:49:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | enum Bar {}
|
||||
| ----------- not a function
|
||||
| ----------- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:54:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
@ -81,16 +81,16 @@ LL | |
|
||||
LL | | f1: u16,
|
||||
LL | | f2: u16,
|
||||
LL | | }
|
||||
| |_- not a function
|
||||
| |_- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:62:1
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | trait Baz {}
|
||||
| ------------ not a function
|
||||
| ------------ not a function definition
|
||||
|
||||
error: cannot use `#[inline(always)]` with `#[target_feature]`
|
||||
--> $DIR/invalid-attribute.rs:67:1
|
||||
@ -98,7 +98,7 @@ error: cannot use `#[inline(always)]` with `#[target_feature]`
|
||||
LL | #[inline(always)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:85:5
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
@ -108,16 +108,16 @@ LL | / unsafe {
|
||||
LL | | foo();
|
||||
LL | | bar();
|
||||
LL | | }
|
||||
| |_____- not a function
|
||||
| |_____- not a function definition
|
||||
|
||||
error: attribute should be applied to a function
|
||||
error: attribute should be applied to a function definition
|
||||
--> $DIR/invalid-attribute.rs:93:5
|
||||
|
|
||||
LL | #[target_feature(enable = "sse2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | || {};
|
||||
| ----- not a function
|
||||
| ----- not a function definition
|
||||
|
||||
error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
|
||||
--> $DIR/invalid-attribute.rs:77:5
|
||||
|
@ -36,11 +36,11 @@ trait Tr5 {
|
||||
}
|
||||
|
||||
#[rustc_must_implement_one_of(abc, xyz)]
|
||||
//~^ attribute can only be applied to a trait
|
||||
//~^ attribute should be applied to a trait
|
||||
fn function() {}
|
||||
|
||||
#[rustc_must_implement_one_of(abc, xyz)]
|
||||
//~^ attribute can only be applied to a trait
|
||||
//~^ attribute should be applied to a trait
|
||||
struct Struct {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,7 +4,7 @@ error: malformed `rustc_must_implement_one_of` attribute input
|
||||
LL | #[rustc_must_implement_one_of]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:38:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(abc, xyz)]
|
||||
@ -13,7 +13,7 @@ LL |
|
||||
LL | fn function() {}
|
||||
| ---------------- not a trait
|
||||
|
||||
error: attribute can only be applied to a trait
|
||||
error: attribute should be applied to a trait
|
||||
--> $DIR/rustc_must_implement_one_of_misuse.rs:42:1
|
||||
|
|
||||
LL | #[rustc_must_implement_one_of(abc, xyz)]
|
||||
|
Loading…
Reference in New Issue
Block a user