diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs new file mode 100644 index 0000000000000..010b1ee4822e3 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -0,0 +1,30 @@ +use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Symbol, sym}; + +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct CrateNameParser; + +impl SingleAttributeParser for CrateNameParser { + const PATH: &[Symbol] = &[sym::crate_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let ArgParser::NameValue(n) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + let Some(name) = n.value_as_str() else { + cx.expected_string_literal(n.value_span, Some(n.value_as_lit())); + return None; + }; + + Some(AttributeKind::CrateName { name, name_span: n.value_span, style: cx.attr_style }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 8437713206e35..458643898a65e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -43,8 +43,8 @@ impl SingleAttributeParser for InlineParser { } } ArgParser::NameValue(_) => { - let suggestions = - >::TEMPLATE.suggestions(false, "inline"); + let suggestions = >::TEMPLATE + .suggestions(cx.attr_style, "inline"); let span = cx.attr_span; cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 886f7a889d303..2e4accabea960 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -96,7 +96,7 @@ impl AttributeParser for MacroUseParser { } } ArgParser::NameValue(_) => { - let suggestions = MACRO_USE_TEMPLATE.suggestions(false, sym::macro_use); + let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use); cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f7946ade6d2b2..3deb60ccbd47a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -31,6 +31,7 @@ pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; +pub(crate) mod crate_level; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index d767abbc250f3..fb167925696d3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -32,8 +32,8 @@ impl SingleAttributeParser for MustUseParser { Some(value_str) } ArgParser::List(_) => { - let suggestions = - >::TEMPLATE.suggestions(false, "must_use"); + let suggestions = >::TEMPLATE + .suggestions(cx.attr_style, "must_use"); cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 77b494328c70c..61d68c18a49b1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -23,7 +23,7 @@ impl SingleAttributeParser for IgnoreParser { ArgParser::NameValue(name_value) => { let Some(str_value) = name_value.value_as_str() else { let suggestions = >::TEMPLATE - .suggestions(false, "ignore"); + .suggestions(cx.attr_style, "ignore"); let span = cx.attr_span; cx.emit_lint( AttributeLintKind::IllFormedAttributeInput { suggestions }, @@ -34,8 +34,8 @@ impl SingleAttributeParser for IgnoreParser { Some(str_value) } ArgParser::List(_) => { - let suggestions = - >::TEMPLATE.suggestions(false, "ignore"); + let suggestions = >::TEMPLATE + .suggestions(cx.attr_style, "ignore"); let span = cx.attr_span; cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 10134915b2782..300117d22fb60 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,4 +1,4 @@ -use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name}; +use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; use rustc_span::{Symbol, sym}; @@ -23,10 +23,6 @@ pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) } -pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { - first_attr_value_str_by_name(attrs, sym::crate_name) -} - pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( attrs: impl Iterator, symbol: Symbol, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 80dfdffdb5548..e037bfd2a49e9 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -4,13 +4,14 @@ use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId}; +use rustc_ast::{self as ast, AttrStyle, LitKind, MetaItemLit, NodeId}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ @@ -22,6 +23,7 @@ use crate::attributes::codegen_attrs::{ TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; +use crate::attributes::crate_level::CrateNameParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -59,6 +61,7 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; +use crate::lints::lint_name; use crate::parser::{ArgParser, MetaItemParser, PathParser}; use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; @@ -157,6 +160,7 @@ attribute_parsers!( // tidy-alphabetical-start Single, + Single, Single, Single, Single, @@ -301,6 +305,9 @@ pub struct AcceptContext<'f, 'sess, S: Stage> { /// The span of the attribute currently being parsed pub(crate) attr_span: Span, + /// Whether it is an inner or outer attribute + pub(crate) attr_style: AttrStyle, + /// The expected structure of the attribute. /// /// Used in reporting errors to give a hint to users what the attribute *should* look like. @@ -382,6 +389,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) }), }, + attr_style: self.attr_style, }) } @@ -392,6 +400,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedIntegerLiteral, + attr_style: self.attr_style, }) } @@ -402,6 +411,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedList, + attr_style: self.attr_style, }) } @@ -412,6 +422,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedNoArgs, + attr_style: self.attr_style, }) } @@ -423,6 +434,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedIdentifier, + attr_style: self.attr_style, }) } @@ -435,6 +447,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedNameValue(name), + attr_style: self.attr_style, }) } @@ -446,6 +459,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::DuplicateKey(key), + attr_style: self.attr_style, }) } @@ -458,6 +472,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::UnexpectedLiteral, + attr_style: self.attr_style, }) } @@ -468,6 +483,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedSingleArgument, + attr_style: self.attr_style, }) } @@ -478,6 +494,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { template: self.template.clone(), attribute: self.attr_path.clone(), reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument, + attr_style: self.attr_style, }) } @@ -496,6 +513,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: false, list: false, }, + attr_style: self.attr_style, }) } @@ -514,6 +532,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: false, list: true, }, + attr_style: self.attr_style, }) } @@ -532,6 +551,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { strings: true, list: false, }, + attr_style: self.attr_style, }) } @@ -675,13 +695,34 @@ impl<'sess> AttributeParser<'sess, Early> { target_span: Span, target_node_id: NodeId, features: Option<&'sess Features>, + ) -> Option { + Self::parse_limited_should_emit( + sess, + attrs, + sym, + target_span, + target_node_id, + features, + ShouldEmit::Nothing, + ) + } + + /// Usually you want `parse_limited`, which defaults to no errors. + pub fn parse_limited_should_emit( + sess: &'sess Session, + attrs: &[ast::Attribute], + sym: Symbol, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + should_emit: ShouldEmit, ) -> Option { let mut p = Self { features, tools: Vec::new(), parse_only: Some(sym), sess, - stage: Early { emit_errors: ShouldEmit::Nothing }, + stage: Early { emit_errors: should_emit }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -689,8 +730,13 @@ impl<'sess> AttributeParser<'sess, Early> { target_node_id, OmitDoc::Skip, std::convert::identity, - |_lint| { - panic!("can't emit lints here for now (nothing uses this atm)"); + |AttributeLint { id, span, kind }| { + sess.psess.buffer_lint( + lint_name(&kind), + span, + id, + BuiltinLintDiag::AttributeLint(kind), + ); }, ); assert!(parsed.len() <= 1); @@ -731,6 +777,7 @@ impl<'sess> AttributeParser<'sess, Early> { }, }, attr_span: attr.span, + attr_style: attr.style, template, attr_path: path.get_attribute_path(), }; @@ -840,6 +887,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { emit_lint: &mut emit_lint, }, attr_span: lower_span(attr.span), + attr_style: attr.style, template: &accept.template, attr_path: path.get_attribute_path(), }; diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index fc1377e53143f..cb794a70ac092 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -92,10 +92,8 @@ mod session_diagnostics; pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; pub use attributes::cfg_old::*; -pub use attributes::util::{ - find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, -}; +pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit}; -pub use lints::emit_attribute_lint; +pub use lints::{decorate_attribute_lint_kind, emit_attribute_lint}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 22f5531bc8079..f20503611935a 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,38 +1,48 @@ -use rustc_errors::{DiagArgValue, LintEmitter}; +use rustc_errors::{AttributeLintDecorator, DeferedAttributeLintDecorator, DiagArgValue}; use rustc_hir::HirId; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_session::lint::Lint; use crate::session_diagnostics; -pub fn emit_attribute_lint(lint: &AttributeLint, lint_emitter: L) { - let AttributeLint { id, span, kind } = lint; +pub(crate) fn lint_name(kind: &AttributeLintKind) -> &'static Lint { + use rustc_session::lint::builtin::*; + match kind { + AttributeLintKind::UnusedDuplicate { .. } => UNUSED_ATTRIBUTES, + AttributeLintKind::IllFormedAttributeInput { .. } => ILL_FORMED_ATTRIBUTE_INPUT, + AttributeLintKind::EmptyAttribute { .. } => UNUSED_ATTRIBUTES, + } +} +pub fn decorate_attribute_lint_kind( + kind: &AttributeLintKind, + lint_emitter: L, +) { match kind { - &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter - .emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *span, - session_diagnostics::UnusedDuplicate { this, other, warning }, - ), + &AttributeLintKind::UnusedDuplicate { this, other, warning } => { + lint_emitter.decorate(session_diagnostics::UnusedDuplicate { this, other, warning }) + } AttributeLintKind::IllFormedAttributeInput { suggestions } => { - lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT, - *id, - *span, - session_diagnostics::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - }, - ); + lint_emitter.decorate(session_diagnostics::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + }); } - AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { attr_span: *first_span }, - ), + AttributeLintKind::EmptyAttribute { first_span } => lint_emitter + .decorate(session_diagnostics::EmptyAttributeList { attr_span: *first_span }), } } + +pub fn emit_attribute_lint>( + lint: &AttributeLint, + lint_emitter: L, +) { + let AttributeLint { id, span, kind } = lint; + + let lint_name = lint_name(&lint.kind); + + let emit = lint_emitter.prepare(lint_name, *id, *span); + decorate_attribute_lint_kind(kind, emit); +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 1de25ca252b82..d47de58299a64 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast as ast; +use rustc_ast::{self as ast, AttrStyle}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -555,6 +555,7 @@ pub(crate) enum AttributeParseErrorReason { pub(crate) struct AttributeParseError { pub(crate) span: Span, pub(crate) attr_span: Span, + pub(crate) attr_style: AttrStyle, pub(crate) template: AttributeTemplate, pub(crate) attribute: AttrPath, pub(crate) reason: AttributeParseErrorReason, @@ -690,7 +691,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { } } - let suggestions = self.template.suggestions(false, &name); + let suggestions = self.template.suggestions(self.attr_style, &name); diag.span_suggestions( self.attr_span, if suggestions.len() == 1 { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2534cddf10573..c95397443d172 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -60,7 +60,6 @@ pub use rustc_error_messages::{ SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_hashes::Hash128; -use rustc_hir::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -105,17 +104,23 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24); #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); +pub trait AttributeLintDecorator { + fn decorate(self, diag: impl for<'a> LintDiagnostic<'a, ()>); +} + /// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. /// Always the `TyCtxt`. -pub trait LintEmitter: Copy { +pub trait DeferedAttributeLintDecorator: Copy { + type ID: Copy; + type Decorator: AttributeLintDecorator; + #[track_caller] - fn emit_node_span_lint( + fn prepare( self, lint: &'static Lint, - hir_id: HirId, + id: Self::ID, span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, - ); + ) -> Self::Decorator; } #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5c63d4808db2f..5de864bd4515e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -6,6 +6,7 @@ use AttributeDuplicates::*; use AttributeGate::*; use AttributeType::*; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::AttrStyle; use rustc_hir::attrs::EncodeCrossCrate; use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; @@ -130,9 +131,12 @@ pub struct AttributeTemplate { } impl AttributeTemplate { - pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec { + pub fn suggestions(&self, style: AttrStyle, name: impl std::fmt::Display) -> Vec { let mut suggestions = vec![]; - let inner = if inner { "!" } else { "" }; + let inner = match style { + AttrStyle::Outer => "", + AttrStyle::Inner => "!", + }; if self.word { suggestions.push(format!("#{inner}[{name}]")); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5f4193154674a..39608277d7bfb 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -303,6 +303,9 @@ pub enum AttributeKind { /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), + /// Represents `#[crate_name = ...]` + CrateName { name: Symbol, name_span: Span, style: AttrStyle }, + ///Represents `#[rustc_deny_explicit_impl]`. DenyExplicitImpl(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e3a7f0b97a8f0..4ef9158c707a0 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -7,6 +7,11 @@ pub enum EncodeCrossCrate { } impl AttributeKind { + /// Whether this attribute should be encoded in metadata files. + /// + /// If this is "Yes", then another crate can do `tcx.get_all_attrs(did)` for a did in this crate, and get the attribute. + /// When this is No, the attribute is filtered out while encoding and other crate won't be able to observe it. + /// This can be unexpectedly good for performance, so unless necessary for cross-crate compilation, prefer No. pub fn encode_cross_crate(&self) -> EncodeCrossCrate { use AttributeKind::*; use EncodeCrossCrate::*; @@ -30,6 +35,7 @@ impl AttributeKind { ConstTrait(..) => No, Coroutine(..) => No, Coverage(..) => No, + CrateName { .. } => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, DoNotImplementViaObject(..) => No, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3ba224723e365..a1d91f0bca401 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -5,7 +5,8 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; -use rustc_ast as ast; +use rustc_ast::{self as ast}; +use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; @@ -15,6 +16,7 @@ use rustc_errors::timings::TimingSection; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; @@ -1244,8 +1246,7 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol // in all code paths that require the crate name very early on, namely before // macro expansion. - let attr_crate_name = - validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs); + let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::ErrorsAndLints); let validate = |name, span| { rustc_session::output::validate_crate_name(sess, name, span); @@ -1283,6 +1284,28 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol sym::rust_out } +pub(crate) fn parse_crate_name( + sess: &Session, + attrs: &[ast::Attribute], + emit_errors: ShouldEmit, +) -> Option<(Symbol, Span)> { + let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) = + AttributeParser::parse_limited_should_emit( + sess, + &attrs, + sym::crate_name, + DUMMY_SP, + rustc_ast::node_id::CRATE_NODE_ID, + None, + emit_errors, + )? + else { + unreachable!("crate_name is the only attr we could've parsed here"); + }; + + Some((name, name_span)) +} + fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`]) // because that would require expanding this while in the middle of expansion, which needs to diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0ca4fcc66ca55..8beb734652dbf 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, OnceLock}; use std::{env, thread}; use rustc_ast as ast; +use rustc_attr_parsing::ShouldEmit; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; @@ -23,6 +24,7 @@ use rustc_target::spec::Target; use tracing::info; use crate::errors; +use crate::passes::parse_crate_name; /// Function pointer type that constructs a new CodegenBackend. type MakeBackendFn = fn() -> Box; @@ -519,11 +521,10 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.dcx().emit_fatal(errors::MultipleOutputTypesToStdout); } - let crate_name = sess - .opts - .crate_name - .clone() - .or_else(|| rustc_attr_parsing::find_crate_name(attrs).map(|n| n.to_string())); + let crate_name = + sess.opts.crate_name.clone().or_else(|| { + parse_crate_name(sess, attrs, ShouldEmit::Nothing).map(|i| i.0.to_string()) + }); match sess.io.output_file { None => { diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f0fbf5bc81e9b..d1e25ad6a07dc 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,8 +1,10 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; +use rustc_attr_parsing::decorate_attribute_lint_kind; use rustc_errors::{ - Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, + Applicability, AttributeLintDecorator, Diag, DiagArgValue, LintDiagnostic, + elided_lifetime_in_path_suggestion, }; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; @@ -468,5 +470,15 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) } + BuiltinLintDiag::AttributeLint(attr) => { + decorate_attribute_lint_kind(&attr, DiagEmitter(diag)); + } + } +} + +struct DiagEmitter<'a, 'b>(&'a mut Diag<'b, ()>); +impl AttributeLintDecorator for DiagEmitter<'_, '_> { + fn decorate(self, diag: impl for<'a> LintDiagnostic<'a, ()>) { + diag.decorate_lint(self.0); } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 7e5f43ba77f43..feb9c806bfc79 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -5,7 +5,7 @@ use rustc_hir::attrs::{AttributeKind, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; +use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_middle::hir::nested_filter::All; use rustc_middle::ty; use rustc_session::config::CrateType; @@ -343,35 +343,27 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - ast::attr::find_by_name(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then( - |attr| { - if let Attribute::Unparsed(n) = attr - && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } = - n.as_ref() - && let ast::LitKind::Str(name, ..) = lit.kind - { - // Discard the double quotes surrounding the literal. - let sp = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .ok() - .and_then(|snippet| { - let left = snippet.find('"')?; - let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; - - Some( - lit.span - .with_lo(lit.span.lo() + BytePos(left as u32 + 1)) - .with_hi(lit.span.hi() - BytePos(right as u32)), - ) - }) - .unwrap_or(lit.span); - - Some(Ident::new(name, sp)) - } else { - None - } + find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::CrateName{name, name_span,..} => (name, name_span)).map( + |(&name, &span)| { + // Discard the double quotes surrounding the literal. + let sp = cx + .sess() + .source_map() + .span_to_snippet(span) + .ok() + .and_then(|snippet| { + let left = snippet.find('"')?; + let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?; + + Some( + span + .with_lo(span.lo() + BytePos(left as u32 + 1)) + .with_hi(span.hi() - BytePos(right as u32)), + ) + }) + .unwrap_or(span); + + Ident::new(name, sp) }, ) }; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index fe068d96b7424..4117429b41e5f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -9,6 +9,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_error_messages::{DiagMessage, MultiSpan}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefPathHash; +use rustc_hir::lints::AttributeLintKind; use rustc_hir::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; pub use rustc_span::edition::Edition; @@ -807,6 +808,7 @@ pub enum BuiltinLintDiag { cfg_name: Symbol, controlled_by: &'static str, }, + AttributeLint(AttributeLintKind), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 49a4733de3b0a..f487e6c080e58 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,8 @@ use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, + Applicability, AttributeLintDecorator, DeferedAttributeLintDecorator, Diag, DiagCtxtHandle, + ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind}; @@ -1417,15 +1418,24 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } -impl<'tcx> LintEmitter for TyCtxt<'tcx> { - fn emit_node_span_lint( +pub struct Decorator<'tcx>(TyCtxt<'tcx>, &'static Lint, HirId, MultiSpan); +impl AttributeLintDecorator for Decorator<'_> { + fn decorate(self, decorator: impl for<'a> LintDiagnostic<'a, ()>) { + self.0.emit_node_span_lint(self.1, self.2, self.3, decorator); + } +} + +impl<'tcx> DeferedAttributeLintDecorator for TyCtxt<'tcx> { + type ID = HirId; + type Decorator = Decorator<'tcx>; + + fn prepare( self, lint: &'static Lint, hir_id: HirId, span: impl Into, - decorator: impl for<'a> LintDiagnostic<'a, ()>, - ) { - self.emit_node_span_lint(lint, hir_id, span, decorator); + ) -> Self::Decorator { + Decorator(self, lint, hir_id, span.into()) } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..08735bfd52aed 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -289,7 +289,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroTransparency(_) | AttributeKind::Pointee(..) | AttributeKind::Dummy - | AttributeKind::RustcBuiltinMacro { .. }, + | AttributeKind::RustcBuiltinMacro { .. } + | AttributeKind::CrateName { .. }, ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) @@ -453,22 +454,49 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); if hir_id != CRATE_HIR_ID { - if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) - { - match style { - Some(ast::AttrStyle::Outer) => self.tcx.emit_node_span_lint( + match attr { + // FIXME(jdonszelmann) after https://github.com/rust-lang/rust/pull/145085 merges, move to attribute parsing + &Attribute::Parsed(AttributeKind::CrateName { + name_span: span, style, .. + }) => match style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::OuterCrateLevelAttr, ), - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + span, errors::InnerCrateLevelAttr, ), + }, + Attribute::Parsed(_) => { /* not crate-level */ } + Attribute::Unparsed(attr) => { + // FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by + // the above + if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = + attr.path + .segments + .first() + .and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) + { + match attr.style { + ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::OuterCrateLevelAttr, + ), + ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::InnerCrateLevelAttr, + ), + } + } } } } diff --git a/tests/ui/attributes/crate-name-empty.stderr b/tests/ui/attributes/crate-name-empty.stderr index 509a42d05f711..31d9dd0e9489c 100644 --- a/tests/ui/attributes/crate-name-empty.stderr +++ b/tests/ui/attributes/crate-name-empty.stderr @@ -1,8 +1,8 @@ error: crate name must not be empty - --> $DIR/crate-name-empty.rs:3:1 + --> $DIR/crate-name-empty.rs:3:17 | LL | #![crate_name = ""] - | ^^^^^^^^^^^^^^^^^^^ + | ^^ error: aborting due to 1 previous error diff --git a/tests/ui/attributes/crate-name-macro-call.stderr b/tests/ui/attributes/crate-name-macro-call.stderr index ab562b41a31f4..697e36cbdc33f 100644 --- a/tests/ui/attributes/crate-name-macro-call.stderr +++ b/tests/ui/attributes/crate-name-macro-call.stderr @@ -1,8 +1,12 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/crate-name-macro-call.rs:4:1 | LL | #![crate_name = concat!("my", "crate")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` + | ^^^^^^^^^^^^^^^^----------------------^ + | | | + | | expected a string literal here + | help: must be of the form: `#![crate_name = "name"]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/crate-name-mismatch.stderr b/tests/ui/attributes/crate-name-mismatch.stderr index 4021fbe7c181f..6416ad2d41a76 100644 --- a/tests/ui/attributes/crate-name-mismatch.stderr +++ b/tests/ui/attributes/crate-name-mismatch.stderr @@ -1,8 +1,8 @@ error: `--crate-name` and `#[crate_name]` are required to match, but `foo` != `bar` - --> $DIR/crate-name-mismatch.rs:5:1 + --> $DIR/crate-name-mismatch.rs:5:17 | LL | #![crate_name = "bar"] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs index 93d47bf0d714e..30e817a5a735c 100644 --- a/tests/ui/attributes/lint_on_root.rs +++ b/tests/ui/attributes/lint_on_root.rs @@ -1,7 +1,7 @@ // NOTE: this used to panic in debug builds (by a sanity assertion) // and not emit any lint on release builds. See https://github.com/rust-lang/rust/issues/142891. #![inline = ""] -//~^ ERROR valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` +//~^ ERROR valid forms for the attribute are `#![inline(always|never)]` and `#![inline]` //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr index aa0645b619420..24fcaa9562023 100644 --- a/tests/ui/attributes/lint_on_root.stderr +++ b/tests/ui/attributes/lint_on_root.stderr @@ -1,4 +1,4 @@ -error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` +error: valid forms for the attribute are `#![inline(always|never)]` and `#![inline]` --> $DIR/lint_on_root.rs:3:1 | LL | #![inline = ""] @@ -11,7 +11,7 @@ LL | #![inline = ""] error: aborting due to 1 previous error Future incompatibility report: Future breakage diagnostic: -error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` +error: valid forms for the attribute are `#![inline(always|never)]` and `#![inline]` --> $DIR/lint_on_root.rs:3:1 | LL | #![inline = ""] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index dd9dd3a6ce7fc..67988c028dcaa 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -31,12 +31,6 @@ error: malformed `windows_subsystem` attribute input LL | #![windows_subsystem] | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]` -error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:71:1 - | -LL | #[crate_name] - | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` - error: malformed `no_sanitize` attribute input --> $DIR/malformed-attrs.rs:89:1 | @@ -369,6 +363,12 @@ LL - #[used()] LL + #[used] | +error[E0539]: malformed `crate_name` attribute input + --> $DIR/malformed-attrs.rs:71:1 + | +LL | #[crate_name] + | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` + error[E0539]: malformed `target_feature` attribute input --> $DIR/malformed-attrs.rs:76:1 | diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr index c39c98dde3198..a6b02028e3bdc 100644 --- a/tests/ui/attributes/malformed-reprs.stderr +++ b/tests/ui/attributes/malformed-reprs.stderr @@ -5,7 +5,7 @@ LL | #![repr] | ^^^^^^^^ | | | expected this to be a list - | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | | transparent)]` + | help: must be of the form: `#![repr(C | Rust | align(...) | packed(...) | | transparent)]` error[E0589]: invalid `repr(align)` attribute: not a power of two --> $DIR/malformed-reprs.rs:9:14 diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index a838ec5df8ead..7a494c4865ee2 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -22,10 +22,10 @@ LL | #![coverage = "off"] help: try changing it to one of the following valid forms of the attribute | LL - #![coverage = "off"] -LL + #[coverage(off)] +LL + #![coverage(off)] | LL - #![coverage = "off"] -LL + #[coverage(on)] +LL + #![coverage(on)] | error[E0539]: malformed `coverage` attribute input diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index dd161360a5c4b..94fdae84bc492 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -19,12 +19,10 @@ LL | #![coverage] | help: try changing it to one of the following valid forms of the attribute | -LL - #![coverage] -LL + #[coverage(off)] - | -LL - #![coverage] -LL + #[coverage(on)] - | +LL | #![coverage(off)] + | +++++ +LL | #![coverage(on)] + | ++++ error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:21:1 diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index f2ae50b75a348..9d718d5d3e502 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -320,10 +320,10 @@ LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:16 | LL | #[crate_name = "0900"] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1 @@ -960,34 +960,34 @@ LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:31 | LL | mod inner { #![crate_name="0900"] } - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:20 | LL | #[crate_name = "0900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:20 | LL | #[crate_name = "0900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:20 | LL | #[crate_name = "0900"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:20 | LL | #[crate_name = "0900"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ warning: crate-level attribute should be in the root module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17 diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr index 6bf09a2b13171..88f7ecba0047b 100644 --- a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr +++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr @@ -1,8 +1,12 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/print-crate-name-request-malformed-crate-name.rs:5:1 | LL | #![crate_name = concat!("wrapped")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` + | ^^^^^^^^^^^^^^^^------------------^ + | | | + | | expected a string literal here + | help: must be of the form: `#![crate_name = "name"]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stdout b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stdout new file mode 100644 index 0000000000000..9034e9065eafa --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stdout @@ -0,0 +1 @@ +print_crate_name_request_malformed_crate_name diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr index de62aed79fce5..d3e60948e4c14 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr @@ -1,4 +1,4 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/print-file-names-request-malformed-crate-name-1.rs:4:1 | LL | #![crate_name] @@ -6,3 +6,4 @@ LL | #![crate_name] error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stdout b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stdout new file mode 100644 index 0000000000000..bc5a0ae26fd6c --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stdout @@ -0,0 +1 @@ +print-file-names-request-malformed-crate-name-1 diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr index 42c33de12210d..949bb589dbba4 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr @@ -1,8 +1,12 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/print-file-names-request-malformed-crate-name-2.rs:7:1 | LL | #![crate_name = concat!("this_one_is_not")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` + | ^^^^^^^^^^^^^^^^--------------------------^ + | | | + | | expected a string literal here + | help: must be of the form: `#![crate_name = "name"]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stdout b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stdout new file mode 100644 index 0000000000000..ae84025106c73 --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stdout @@ -0,0 +1 @@ +this_one_is_okay diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr index cb5ffaab9ca20..fbefa3a208899 100644 --- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr @@ -1,8 +1,12 @@ -error: malformed `crate_name` attribute input +error[E0539]: malformed `crate_name` attribute input --> $DIR/print-file-names-request-malformed-crate-name.rs:5:1 | LL | #![crate_name = concat!("wrapped")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]` + | ^^^^^^^^^^^^^^^^------------------^ + | | | + | | expected a string literal here + | help: must be of the form: `#![crate_name = "name"]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stdout b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stdout new file mode 100644 index 0000000000000..04b42a204203f --- /dev/null +++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stdout @@ -0,0 +1 @@ +print-file-names-request-malformed-crate-name diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index cfa6c2b4228cd..a334c49788cb2 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -11,8 +11,12 @@ // - no_main: extra setup #![deny(unused_attributes)] #![crate_name = "unused_attr_duplicate"] -#![crate_name = "unused_attr_duplicate2"] //~ ERROR unused attribute -//~^ WARN this was previously accepted +#![crate_name = "unused_attr_duplicate2"] +//~^ ERROR unused attribute +//~| WARN this was previously accepted +//~| ERROR unused attribute +//~| WARN this was previously accepted +// FIXME(jdonszelmann) this error is given twice now. I'll look at this in the future #![recursion_limit = "128"] #![recursion_limit = "256"] //~ ERROR unused attribute //~^ WARN this was previously accepted diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 6c44e884ba54f..203211d0d5620 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -1,14 +1,15 @@ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:33:1 + --> $DIR/unused-attr-duplicate.rs:14:1 | -LL | #[no_link] - | ^^^^^^^^^^ help: remove this attribute +LL | #![crate_name = "unused_attr_duplicate2"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:32:1 + --> $DIR/unused-attr-duplicate.rs:13:1 | -LL | #[no_link] - | ^^^^^^^^^^ +LL | #![crate_name = "unused_attr_duplicate"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! note: the lint level is defined here --> $DIR/unused-attr-duplicate.rs:12:9 | @@ -16,291 +17,304 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:14:1 + --> $DIR/unused-attr-duplicate.rs:37:1 | -LL | #![crate_name = "unused_attr_duplicate2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[no_link] + | ^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:13:1 + --> $DIR/unused-attr-duplicate.rs:36:1 | -LL | #![crate_name = "unused_attr_duplicate"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +LL | #[no_link] + | ^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:17:1 + --> $DIR/unused-attr-duplicate.rs:21:1 | LL | #![recursion_limit = "256"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:16:1 + --> $DIR/unused-attr-duplicate.rs:20:1 | LL | #![recursion_limit = "128"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:20:1 + --> $DIR/unused-attr-duplicate.rs:24:1 | LL | #![type_length_limit = "1"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:19:1 + --> $DIR/unused-attr-duplicate.rs:23:1 | LL | #![type_length_limit = "1048576"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:23:1 + --> $DIR/unused-attr-duplicate.rs:27:1 | LL | #![no_std] | ^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:22:1 + --> $DIR/unused-attr-duplicate.rs:26:1 | LL | #![no_std] | ^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:27:1 + --> $DIR/unused-attr-duplicate.rs:31:1 | LL | #![windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:26:1 + --> $DIR/unused-attr-duplicate.rs:30:1 | LL | #![windows_subsystem = "console"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:30:1 + --> $DIR/unused-attr-duplicate.rs:34:1 | LL | #![no_builtins] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:29:1 + --> $DIR/unused-attr-duplicate.rs:33:1 | LL | #![no_builtins] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:40:5 + --> $DIR/unused-attr-duplicate.rs:44:5 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:39:5 + --> $DIR/unused-attr-duplicate.rs:43:5 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:37:1 + --> $DIR/unused-attr-duplicate.rs:41:1 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:36:1 + --> $DIR/unused-attr-duplicate.rs:40:1 | LL | #[macro_use] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:47:1 + --> $DIR/unused-attr-duplicate.rs:51:1 | LL | #[path = "bar.rs"] | ^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:46:1 + --> $DIR/unused-attr-duplicate.rs:50:1 | LL | #[path = "auxiliary/lint_unused_extern_crate.rs"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:53:1 + --> $DIR/unused-attr-duplicate.rs:57:1 | LL | #[ignore = "some text"] | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:52:1 + --> $DIR/unused-attr-duplicate.rs:56:1 | LL | #[ignore] | ^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:55:1 + --> $DIR/unused-attr-duplicate.rs:59:1 | LL | #[should_panic(expected = "values don't match")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:54:1 + --> $DIR/unused-attr-duplicate.rs:58:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:60:1 + --> $DIR/unused-attr-duplicate.rs:64:1 | LL | #[must_use = "some message"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:59:1 + --> $DIR/unused-attr-duplicate.rs:63:1 | LL | #[must_use] | ^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:66:1 + --> $DIR/unused-attr-duplicate.rs:70:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:65:1 + --> $DIR/unused-attr-duplicate.rs:69:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:72:1 + --> $DIR/unused-attr-duplicate.rs:76:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:71:1 + --> $DIR/unused-attr-duplicate.rs:75:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:76:1 + --> $DIR/unused-attr-duplicate.rs:80:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:75:1 + --> $DIR/unused-attr-duplicate.rs:79:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:79:1 + --> $DIR/unused-attr-duplicate.rs:83:1 | LL | #[cold] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:78:1 + --> $DIR/unused-attr-duplicate.rs:82:1 | LL | #[cold] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:81:1 + --> $DIR/unused-attr-duplicate.rs:85:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:80:1 + --> $DIR/unused-attr-duplicate.rs:84:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:88:5 + --> $DIR/unused-attr-duplicate.rs:92:5 | LL | #[link_name = "this_does_not_exist"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:90:5 + --> $DIR/unused-attr-duplicate.rs:94:5 | LL | #[link_name = "rust_dbg_extern_identity_u32"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:94:1 + --> $DIR/unused-attr-duplicate.rs:98:1 | LL | #[export_name = "exported_symbol_name"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:96:1 + --> $DIR/unused-attr-duplicate.rs:100:1 | LL | #[export_name = "exported_symbol_name2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:100:1 + --> $DIR/unused-attr-duplicate.rs:104:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:99:1 + --> $DIR/unused-attr-duplicate.rs:103:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:104:1 + --> $DIR/unused-attr-duplicate.rs:108:1 | LL | #[used] | ^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:103:1 + --> $DIR/unused-attr-duplicate.rs:107:1 | LL | #[used] | ^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:107:1 + --> $DIR/unused-attr-duplicate.rs:111:1 | LL | #[link_section = ".text"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:110:1 + --> $DIR/unused-attr-duplicate.rs:114:1 | LL | #[link_section = ".bss"] | ^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: unused attribute - --> $DIR/unused-attr-duplicate.rs:25:1 + --> $DIR/unused-attr-duplicate.rs:14:1 + | +LL | #![crate_name = "unused_attr_duplicate2"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:13:1 + | +LL | #![crate_name = "unused_attr_duplicate"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:29:1 | LL | #![no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:24:1 + --> $DIR/unused-attr-duplicate.rs:28:1 | LL | #![no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: aborting due to 25 previous errors diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr index 0b5942a287d03..c53632e0a45c2 100644 --- a/tests/ui/resolve/path-attr-in-const-block.stderr +++ b/tests/ui/resolve/path-attr-in-const-block.stderr @@ -11,7 +11,7 @@ LL | #![path = foo!()] | ^^^^^^^^^^------^ | | | | | expected a string literal here - | help: must be of the form: `#[path = "file"]` + | help: must be of the form: `#![path = "file"]` error: aborting due to 2 previous errors