diff --git a/Cargo.lock b/Cargo.lock index fb4cf235c6f49..1dc403904ced3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3207,7 +3207,6 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3216,7 +3215,6 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", - "rustc_parse", "rustc_session", "rustc_span", "rustc_target", @@ -3265,10 +3263,14 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", + "rustc_errors", + "rustc_feature", + "rustc_fluent_macro", + "rustc_lexer", "rustc_macros", "rustc_serialize", + "rustc_session", "rustc_span", - "thin-vec", ] [[package]] @@ -3283,13 +3285,11 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", - "rustc_hir", "rustc_lexer", "rustc_macros", "rustc_serialize", "rustc_session", "rustc_span", - "thin-vec", ] [[package]] @@ -3342,7 +3342,6 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_fluent_macro", - "rustc_hir", "rustc_index", "rustc_lexer", "rustc_lint_defs", @@ -3599,7 +3598,6 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_codes", "rustc_error_messages", @@ -3634,7 +3632,6 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", - "rustc_hir", "rustc_lexer", "rustc_lint_defs", "rustc_macros", @@ -3693,7 +3690,6 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", - "rustc_attr_data_structures", "rustc_data_structures", "rustc_hashes", "rustc_index", @@ -3741,7 +3737,6 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_parsing", "rustc_hir", "rustc_span", ] @@ -4249,7 +4244,6 @@ name = "rustc_query_impl" version = "0.0.0" dependencies = [ "measureme", - "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_hashes", @@ -4272,7 +4266,6 @@ dependencies = [ "rustc-rayon-core", "rustc_abi", "rustc_ast", - "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -4323,7 +4316,6 @@ version = "0.0.0" dependencies = [ "bitflags", "rustc_abi", - "rustc_ast", "rustc_data_structures", "rustc_hir", "rustc_middle", @@ -4420,7 +4412,6 @@ dependencies = [ "punycode", "rustc-demangle", "rustc_abi", - "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hashes", diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 2ec4f4b055514..3215ce6b0cb47 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -11,7 +11,6 @@ doctest = false rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } @@ -20,7 +19,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 1d9ca6bb9c8cb..88ce6f80e10bd 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -108,7 +108,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span); + self.lower_attrs(hir_id, &l.attrs); self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index efbd1711daa92..af53c7ec21572 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -77,8 +77,9 @@ impl<'hir> LoweringContext<'_, 'hir> { self.attrs.insert( ex.hir_id.local_id, &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span) - .into_iter() + e.attrs + .iter() + .map(|a| self.lower_attr(a)) .chain(old_attrs.iter().cloned()), ), ); @@ -97,7 +98,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + self.lower_attrs(expr_hir_id, &e.attrs); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -669,7 +670,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span); + self.lower_attrs(hir_id, &arm.attrs); let is_never_pattern = pat.is_never_pattern(); let body = if let Some(body) = &arm.body && !is_never_pattern @@ -838,7 +839,6 @@ impl<'hir> LoweringContext<'_, 'hir> { style: AttrStyle::Outer, span: unstable_span, }], - span, ); } } @@ -1673,7 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1936,7 +1936,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span); + self.lower_attrs(expr.hir_id, &e.attrs); expr } @@ -1993,7 +1993,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span); + self.lower_attrs(val_expr.hir_id, &attrs); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2024,7 +2024,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); + self.lower_attrs(ret_expr.hir_id, &attrs); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a4fc4b3e3a121..1d3db64b47ed9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -11,7 +11,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; @@ -93,8 +93,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); - // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); hir::OwnerNode::Crate(module) }) } @@ -158,7 +157,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -621,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { owner_id, ident: self.lower_ident(i.ident), @@ -679,7 +678,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span); + self.lower_attrs(hir_id, &v.attrs); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -741,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -760,7 +759,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -896,7 +895,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( @@ -1057,7 +1056,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span); + self.lower_attrs(hir_id, ¶m.attrs); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1c69937eed07a..b865cbedbbb78 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -45,7 +45,6 @@ use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -61,8 +60,7 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; -use rustc_span::symbol::{Ident, Symbol, kw, sym}; -use rustc_span::{DUMMY_SP, DesugaringKind, Span}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -139,13 +137,10 @@ struct LoweringContext<'a, 'hir> { allow_async_iterator: Arc<[Symbol]>, allow_for_await: Arc<[Symbol]>, allow_async_fn_traits: Arc<[Symbol]>, - - attribute_parser: AttributeParser<'hir>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { - let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { // Pseudo-globals. tcx, @@ -186,8 +181,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - - attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), } } @@ -223,6 +216,7 @@ impl ResolverAstLowering { None } + /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&self, id: NodeId) -> Option { self.partial_res_map.get(&id).copied() } @@ -861,38 +855,45 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ret } - fn lower_attrs( - &mut self, - id: HirId, - attrs: &[Attribute], - target_span: Span, - ) -> &'hir [hir::Attribute] { + fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); - debug_assert_eq!(id.owner, self.current_hir_id_owner); - let ret = self.arena.alloc_from_iter(lowered_attrs); - - // this is possible if an item contained syntactical attribute, - // but none of them parse succesfully or all of them were ignored - // for not being built-in attributes at all. They could be remaining - // unexpanded attributes used as markers in proc-macro derives for example. - // This will have emitted some diagnostics for the misparse, but will then - // not emit the attribute making the list empty. - if ret.is_empty() { - &[] - } else { - self.attrs.insert(id.local_id, ret); - ret - } + let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); + debug_assert!(!ret.is_empty()); + self.attrs.insert(id.local_id, ret); + ret } } - fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec { - self.attribute_parser - .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) + fn lower_attr(&self, attr: &Attribute) -> hir::Attribute { + // Note that we explicitly do not walk the path. Since we don't really + // lower attributes (we use the AST version) there is nowhere to keep + // the `HirId`s. We don't actually need HIR version of attributes anyway. + // Tokens are also not needed after macro expansion and parsing. + let kind = match attr.kind { + AttrKind::Normal(ref normal) => hir::AttrKind::Normal(Box::new(hir::AttrItem { + unsafety: self.lower_safety(normal.item.unsafety, hir::Safety::Safe), + path: hir::AttrPath { + segments: normal + .item + .path + .segments + .iter() + .map(|i| i.ident) + .collect::>() + .into_boxed_slice(), + span: normal.item.path.span, + }, + args: self.lower_attr_args(&normal.item.args), + })), + AttrKind::DocComment(comment_kind, data) => { + hir::AttrKind::DocComment(comment_kind, data) + } + }; + + hir::Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) } } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { @@ -904,6 +905,34 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + fn lower_attr_args(&self, args: &AttrArgs) -> hir::AttrArgs { + match args { + AttrArgs::Empty => hir::AttrArgs::Empty, + AttrArgs::Delimited(args) => hir::AttrArgs::Delimited(self.lower_delim_args(args)), + // This is an inert key-value attribute - it will never be visible to macros + // after it gets lowered to HIR. Therefore, we can extract literals to handle + // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). + &AttrArgs::Eq { eq_span, ref expr } => { + // In valid code the value always ends up as a single literal. Otherwise, a dummy + // literal suffices because the error is handled elsewhere. + let lit = if let ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) + { + lit + } else { + let guar = self.dcx().has_errors().unwrap(); + MetaItemLit { + symbol: kw::Empty, + suffix: None, + kind: LitKind::Err(guar), + span: DUMMY_SP, + } + }; + hir::AttrArgs::Eq { eq_span, expr: lit } + } + } + } + fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } } @@ -1816,7 +1845,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span()); + self.lower_attrs(hir_id, ¶m.attrs); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2dcfe7c745da5..e1f3afbcf5908 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs); hir::PatField { hir_id, diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 25944392a52a9..5a0ec865f9d4d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -207,6 +207,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} +ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library + ast_passes_static_without_body = free static item without body .suggestion = provide a definition for the static diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9f0d2325475a2..6eb9bb1c0dafa 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -732,6 +732,13 @@ pub(crate) struct AssociatedSuggestion2 { pub potential_assoc: Ident, } +#[derive(Diagnostic)] +#[diag(ast_passes_stability_outside_std, code = E0734)] +pub(crate) struct StabilityOutsideStd { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_feature_on_non_nightly, code = E0554)] pub(crate) struct FeatureOnNonNightly { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0f80e49320ed4..e5d8013058f65 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -178,6 +178,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } + + // Emit errors for non-staged-api crates. + if !self.features.staged_api() { + if attr.has_name(sym::unstable) + || attr.has_name(sym::stable) + || attr.has_name(sym::rustc_const_unstable) + || attr.has_name(sym::rustc_const_stable) + || attr.has_name(sym::rustc_default_body_unstable) + { + self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span }); + } + } } fn visit_item(&mut self, i: &'a ast::Item) { diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml index b18923c337ff8..19d0d5a306d6e 100644 --- a/compiler/rustc_attr_data_structures/Cargo.toml +++ b/compiler/rustc_attr_data_structures/Cargo.toml @@ -5,12 +5,16 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_abi = {path = "../rustc_abi"} -rustc_ast = {path = "../rustc_ast"} -rustc_ast_pretty = {path = "../rustc_ast_pretty"} -rustc_data_structures = {path = "../rustc_data_structures"} -rustc_macros = {path = "../rustc_macros"} -rustc_serialize = {path = "../rustc_serialize"} -rustc_span = {path = "../rustc_span"} -thin-vec = "0.2.12" +rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9ac8de0227d79..b4027a096c532 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -1,12 +1,9 @@ use rustc_abi::Align; -use rustc_ast::token::CommentKind; -use rustc_ast::{self as ast, AttrStyle}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; -use rustc_span::hygiene::Transparency; +use rustc_ast as ast; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol}; -use thin_vec::ThinVec; -use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; +use crate::RustcVersion; #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum InlineAttr { @@ -57,7 +54,7 @@ impl OptimizeAttr { } } -#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)] +#[derive(Clone, Debug, Encodable, Decodable)] pub enum DiagnosticAttribute { // tidy-alphabetical-start DoNotRecommend, @@ -65,7 +62,7 @@ pub enum DiagnosticAttribute { // tidy-alphabetical-end } -#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] +#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)] pub enum ReprAttr { ReprInt(IntType), ReprRust, @@ -74,8 +71,6 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(Align), - // this one is just so we can emit a lint for it - ReprEmpty, } pub use ReprAttr::*; @@ -85,13 +80,13 @@ pub enum TransparencyError { } #[derive(Eq, PartialEq, Debug, Copy, Clone)] -#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] +#[derive(Encodable, Decodable)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy), } -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub struct Deprecation { pub since: DeprecatedSince, /// The note to issue a reason. @@ -103,7 +98,7 @@ pub struct Deprecation { } /// Release in which an API is deprecated. -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub enum DeprecatedSince { RustcVersion(RustcVersion), /// Deprecated in the future ("to be determined"). @@ -137,61 +132,3 @@ impl Deprecation { matches!(self.since, DeprecatedSince::RustcVersion(_)) } } - -/// Attributes represent parsed, *built in*, inert attributes. That means, -/// attributes that are not actually ever expanded. -/// For more information on this, see the module docs on the rustc_attr_parsing crate. -/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler. -/// These are kept around after the AST, into the HIR and further on. -/// -/// The word parsed could be a little misleading here, because the parser already parses -/// attributes early on. However, the result, an [`ast::Attribute`] -/// is only parsed at a high level, still containing a token stream in many cases. That is -/// because the structure of the contents varies from attribute to attribute. -/// With a parsed attribute I mean that each attribute is processed individually into a -/// final structure, which on-site (the place where the attribute is useful for, think the -/// the place where `must_use` is checked) little to no extra parsing or validating needs to -/// happen. -/// -/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html) -#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] -pub enum AttributeKind { - // tidy-alphabetical-start - AllowConstFnUnstable(ThinVec), - AllowInternalUnstable(ThinVec<(Symbol, Span)>), - BodyStability { - stability: DefaultBodyStability, - /// Span of the `#[rustc_default_body_unstable(...)]` attribute - span: Span, - }, - Confusables { - symbols: ThinVec, - // FIXME(jdonszelmann): remove when target validation code is moved - first_span: Span, - }, - ConstStability { - stability: PartialConstStability, - /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute - span: Span, - }, - ConstStabilityIndirect, - Deprecation { - deprecation: Deprecation, - span: Span, - }, - Diagnostic(DiagnosticAttribute), - DocComment { - style: AttrStyle, - kind: CommentKind, - span: Span, - comment: Symbol, - }, - MacroTransparency(Transparency), - Repr(ThinVec<(ReprAttr, Span)>), - Stability { - stability: Stability, - /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute - span: Span, - }, - // tidy-alphabetical-end -} diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index e4bb459e6df5a..4f204aeab640f 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -10,142 +10,7 @@ mod attributes; mod stability; mod version; -use std::num::NonZero; - pub use attributes::*; -use rustc_abi::Align; -use rustc_ast::token::CommentKind; -use rustc_ast::{AttrStyle, IntTy, UintTy}; -use rustc_ast_pretty::pp::Printer; -use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol}; +pub(crate) use rustc_session::HashStableContext; pub use stability::*; -use thin_vec::ThinVec; pub use version::*; - -/// Requirements for a `StableHashingContext` to be used in this crate. -/// This is a hack to allow using the `HashStable_Generic` derive macro -/// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {} - -/// This trait is used to print attributes in `rustc_hir_pretty`. -/// -/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. -/// The output will look a lot like a `Debug` implementation, but fields of several types -/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the -/// representation much. -pub trait PrintAttribute { - fn print_something(&self) -> bool; - fn print_attribute(&self, p: &mut Printer); -} - -impl PrintAttribute for &T { - fn print_something(&self) -> bool { - T::print_something(self) - } - - fn print_attribute(&self, p: &mut Printer) { - T::print_attribute(self, p) - } -} -impl PrintAttribute for Option { - fn print_something(&self) -> bool { - self.as_ref().is_some_and(|x| x.print_something()) - } - fn print_attribute(&self, p: &mut Printer) { - if let Some(i) = self { - T::print_attribute(i, p) - } - } -} -impl PrintAttribute for ThinVec { - fn print_something(&self) -> bool { - self.is_empty() || self[0].print_something() - } - fn print_attribute(&self, p: &mut Printer) { - let mut last_printed = false; - p.word("["); - for i in self { - if last_printed { - p.word_space(","); - } - i.print_attribute(p); - last_printed = i.print_something(); - } - p.word("]"); - } -} -macro_rules! print_skip { - ($($t: ty),* $(,)?) => {$( - impl PrintAttribute for $t { - fn print_something(&self) -> bool { false } - fn print_attribute(&self, _: &mut Printer) { } - })* - }; -} - -macro_rules! print_disp { - ($($t: ty),* $(,)?) => {$( - impl PrintAttribute for $t { - fn print_something(&self) -> bool { true } - fn print_attribute(&self, p: &mut Printer) { - p.word(format!("{}", self)); - } - } - )*}; -} -macro_rules! print_debug { - ($($t: ty),* $(,)?) => {$( - impl PrintAttribute for $t { - fn print_something(&self) -> bool { true } - fn print_attribute(&self, p: &mut Printer) { - p.word(format!("{:?}", self)); - } - } - )*}; -} - -macro_rules! print_tup { - (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* }; - () => {}; - ($t: ident $($ts: ident)*) => { - #[allow(non_snake_case, unused)] - impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { - fn print_something(&self) -> bool { - let ($t, $($ts),*) = self; - print_tup!(num_print_something $t $($ts)*) != 0 - } - - fn print_attribute(&self, p: &mut Printer) { - let ($t, $($ts),*) = self; - let parens = print_tup!(num_print_something $t $($ts)*) > 1; - if parens { - p.word("("); - } - - let mut printed_anything = $t.print_something(); - - $t.print_attribute(p); - - $( - if printed_anything && $ts.print_something() { - p.word_space(","); - printed_anything = true; - } - $ts.print_attribute(p); - )* - - if parens { - p.word(")"); - } - } - } - - print_tup!($($ts)*); - }; -} - -print_tup!(A B C D E F G H); -print_skip!(Span, ()); -print_disp!(Symbol, u16, bool, NonZero); -print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index c0ca08a60f8b3..c2213fc9ed881 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -1,9 +1,9 @@ use std::num::NonZero; -use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Symbol, sym}; -use crate::{PrintAttribute, RustcVersion}; +use crate::RustcVersion; /// The version placeholder that recently stabilized features contain inside the /// `since` field of the `#[stable]` attribute. @@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N"); /// - `#[stable]` /// - `#[unstable]` #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, @@ -43,7 +43,7 @@ impl Stability { /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct ConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -83,7 +83,7 @@ impl ConstStability { /// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked` /// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct PartialConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -103,7 +103,7 @@ impl PartialConstStability { /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub enum StabilityLevel { /// `#[unstable]` Unstable { @@ -145,7 +145,7 @@ pub enum StabilityLevel { /// Rust release in which a feature is stabilized. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub enum StableSince { /// also stores the original symbol for printing Version(RustcVersion), @@ -171,7 +171,7 @@ impl StabilityLevel { } #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub enum UnstableReason { None, Default, @@ -180,7 +180,7 @@ pub enum UnstableReason { /// Represents the `#[rustc_default_body_unstable]` attribute. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct DefaultBodyStability { pub level: StabilityLevel, pub feature: Symbol, diff --git a/compiler/rustc_attr_data_structures/src/version.rs b/compiler/rustc_attr_data_structures/src/version.rs index 69b0e041d819d..6be875ad4be86 100644 --- a/compiler/rustc_attr_data_structures/src/version.rs +++ b/compiler/rustc_attr_data_structures/src/version.rs @@ -1,13 +1,9 @@ use std::fmt::{self, Display}; -use rustc_macros::{ - Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, -}; - -use crate::PrintAttribute; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, current_rustc_version}; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct RustcVersion { pub major: u16, pub minor: u16, diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index c335eeb5f7120..f681e9397d9f1 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -13,11 +13,9 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 45174c9582d33..faa2865cb9130 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,8 +6,6 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details -attr_parsing_empty_confusables = - expected at least one confusable name attr_parsing_expected_one_cfg_pattern = expected 1 cfg-pattern @@ -23,8 +21,8 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names -attr_parsing_incorrect_meta_item = expected a quoted string literal -attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes +attr_parsing_incorrect_meta_item = + incorrect meta item attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -90,20 +88,18 @@ attr_parsing_multiple_stability_levels = attr_parsing_non_ident_feature = 'feature' is not an identifier -attr_parsing_repr_ident = - meta item in `repr` must be an identifier - attr_parsing_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +attr_parsing_rustc_const_stable_indirect_pairing = + `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied + attr_parsing_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute attr_parsing_soft_no_args = `soft` should not have any arguments -attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library - attr_parsing_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} @@ -111,10 +107,6 @@ attr_parsing_unknown_meta_item = attr_parsing_unknown_version_literal = unknown version literal format, assuming it refers to a future version -attr_parsing_unrecognized_repr_hint = - unrecognized representation hint - .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` - attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change @@ -130,8 +122,3 @@ attr_parsing_unsupported_literal_generic = unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix - -attr_parsing_unused_multiple = - multiple `{$name}` attributes - .suggestion = remove this attribute - .note = attribute also specified here diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index d37ede86cfd2a..13d246b08a8f4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,67 +1,49 @@ -use std::iter; +use rustc_ast::attr::{AttributeExt, filter_by_name}; +use rustc_session::Session; +use rustc_span::{Symbol, sym}; -use rustc_attr_data_structures::AttributeKind; -use rustc_span::{Span, Symbol, sym}; - -use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; -use crate::parser::ArgParser; use crate::session_diagnostics; -pub(crate) struct AllowInternalUnstableParser; -impl CombineAttributeParser for AllowInternalUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; - type Item = (Symbol, Span); - const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; - - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { - parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span)) - } +pub fn allow_internal_unstable( + sess: &Session, + attrs: &[impl AttributeExt], +) -> impl Iterator { + allow_unstable(sess, attrs, sym::allow_internal_unstable) } -pub(crate) struct AllowConstFnUnstableParser; -impl CombineAttributeParser for AllowConstFnUnstableParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; - type Item = Symbol; - const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; - - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { - parse_unstable(cx, args, Self::PATH[0]) - } +pub fn rustc_allow_const_fn_unstable( + sess: &Session, + attrs: &[impl AttributeExt], +) -> impl Iterator { + allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) } -fn parse_unstable<'a>( - cx: &AcceptContext<'_>, - args: &'a ArgParser<'a>, +fn allow_unstable( + sess: &Session, + attrs: &[impl AttributeExt], symbol: Symbol, -) -> impl IntoIterator { - let mut res = Vec::new(); - - let Some(list) = args.list() else { - cx.emit_err(session_diagnostics::ExpectsFeatureList { - span: cx.attr_span, - name: symbol.to_ident_string(), - }); - return res; - }; - - for param in list.mixed() { - let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.word_without_args()) { - res.push(ident.name); - } else { - cx.emit_err(session_diagnostics::ExpectsFeatures { - span: param_span, +) -> impl Iterator { + let attrs = filter_by_name(attrs, symbol); + let list = attrs + .filter_map(move |attr| { + attr.meta_item_list().or_else(|| { + sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList { + span: attr.span(), + name: symbol.to_ident_string(), + }); + None + }) + }) + .flatten(); + + list.into_iter().filter_map(move |it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + sess.dcx().emit_err(session_diagnostics::ExpectsFeatures { + span: it.span(), name: symbol.to_ident_string(), }); } - } - - res + name + }) } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 0d6d521b40c61..bb9aaaa2fea9e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,4 +1,6 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; +//! Parsing and validation of builtin attributes + +use rustc_ast::{self as ast, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::RustcVersion; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; @@ -7,11 +9,10 @@ use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; -use rustc_span::symbol::kw; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, kw, sym}; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; +use crate::util::UnsupportedLiteralReason; +use crate::{fluent_generated, parse_version, session_diagnostics}; #[derive(Clone, Debug)] pub struct Condition { @@ -24,7 +25,7 @@ pub struct Condition { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( - cfg: &MetaItemInner, + cfg: &ast::MetaItemInner, sess: &Session, lint_node_id: NodeId, features: Option<&Features>, @@ -79,7 +80,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Fea /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( - cfg: &MetaItemInner, + cfg: &ast::MetaItemInner, sess: &Session, features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, @@ -87,8 +88,8 @@ pub fn eval_condition( let dcx = sess.dcx(); let cfg = match cfg { - MetaItemInner::MetaItem(meta_item) => meta_item, - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + ast::MetaItemInner::MetaItem(meta_item) => meta_item, + ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { if let Some(features) = features { // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` // and `true`, and we want to keep the former working without feature gate @@ -117,7 +118,7 @@ pub fn eval_condition( }; match &cfg.kind { - MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { + ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { @@ -149,7 +150,7 @@ pub fn eval_condition( RustcVersion::CURRENT >= min_version } } - MetaItemKind::List(mis) => { + ast::MetaItemKind::List(mis) => { for mi in mis.iter() { if mi.meta_item_or_bool().is_none() { dcx.emit_err(session_diagnostics::UnsupportedLiteral { @@ -208,7 +209,12 @@ pub fn eval_condition( seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); } - res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) + res & eval_condition( + &ast::MetaItemInner::MetaItem(mi), + sess, + features, + eval, + ) }) } _ => { @@ -220,7 +226,7 @@ pub fn eval_condition( } } } - MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { + ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); true } @@ -233,7 +239,7 @@ pub fn eval_condition( }); true } - MetaItemKind::Word | MetaItemKind::NameValue(..) => { + ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { let ident = cfg.ident().expect("multi-segment cfg predicate"); eval(Condition { name: ident.name, diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 6cff952fcf229..2ced759fd8883 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,58 +1,21 @@ -use rustc_attr_data_structures::AttributeKind; -use rustc_span::{Span, Symbol, sym}; -use thin_vec::ThinVec; +//! Parsing and validation of builtin attributes -use super::{AcceptMapping, AttributeParser}; -use crate::context::FinalizeContext; -use crate::session_diagnostics; +use rustc_ast::MetaItemInner; +use rustc_ast::attr::AttributeExt; +use rustc_span::Symbol; -#[derive(Default)] -pub(crate) struct ConfusablesParser { - confusables: ThinVec, - first_span: Option, -} - -impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { - let Some(list) = args.list() else { - // FIXME(jdonszelmann): error when not a list? Bring validation code here. - // NOTE: currently subsequent attributes are silently ignored using - // tcx.get_attr(). - return; - }; - - if list.is_empty() { - cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); - } - - for param in list.mixed() { - let span = param.span(); +/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names. +pub fn parse_confusables(attr: &impl AttributeExt) -> Option> { + let metas = attr.meta_item_list()?; - let Some(lit) = param.lit() else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span, - suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { - lo: span.shrink_to_lo(), - hi: span.shrink_to_hi(), - }), - }); - continue; - }; + let mut candidates = Vec::new(); - this.confusables.push(lit.symbol); - } - - this.first_span.get_or_insert(cx.attr_span); - })]; - - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { - if self.confusables.is_empty() { + for meta in metas { + let MetaItemInner::Lit(meta_lit) = meta else { return None; - } - - Some(AttributeKind::Confusables { - symbols: self.confusables, - first_span: self.first_span.unwrap(), - }) + }; + candidates.push(meta_lit.symbol); } + + Some(candidates) } diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 7d1417446b21d..d7415a7198fd6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,122 +1,121 @@ -use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; -use rustc_span::symbol::Ident; +//! Parsing and validation of builtin attributes + +use rustc_ast::attr::AttributeExt; +use rustc_ast::{MetaItem, MetaItemInner}; +use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::{DeprecatedSince, Deprecation}; +use rustc_feature::Features; +use rustc_session::Session; use rustc_span::{Span, Symbol, sym}; -use super::SingleAttributeParser; -use super::util::parse_version; -use crate::context::AcceptContext; -use crate::parser::ArgParser; -use crate::session_diagnostics; -use crate::session_diagnostics::UnsupportedLiteralReason; +use super::util::UnsupportedLiteralReason; +use crate::{parse_version, session_diagnostics}; -pub(crate) struct DeprecationParser; +/// Finds the deprecation attribute. `None` if none exists. +pub fn find_deprecation( + sess: &Session, + features: &Features, + attrs: &[impl AttributeExt], +) -> Option<(Deprecation, Span)> { + let mut depr: Option<(Deprecation, Span)> = None; + let is_rustc = features.staged_api(); -fn get( - cx: &AcceptContext<'_>, - ident: Ident, - param_span: Span, - arg: &ArgParser<'_>, - item: &Option, -) -> Option { - if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { - span: param_span, - item: ident.to_string(), - }); - return None; - } - if let Some(v) = arg.name_value() { - if let Some(value_str) = v.value_as_str() { - Some(value_str) - } else { - let lit = v.value_as_lit(); - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: v.value_span, - reason: UnsupportedLiteralReason::DeprecatedString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: cx.sess().source_map().start_point(lit.span), - }); - None + 'outer: for attr in attrs { + if !attr.has_name(sym::deprecated) { + continue; } - } else { - // FIXME(jdonszelmann): suggestion? - cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None }); - None - } -} - -impl SingleAttributeParser for DeprecationParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; - - fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) { - // FIXME(jdonszelmann): merge with errors from check_attrs.rs - cx.emit_err(session_diagnostics::UnusedMultiple { - this: cx.attr_span, - other: first_span, - name: sym::deprecated, - }); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { - let features = cx.features(); let mut since = None; let mut note = None; let mut suggestion = None; - let is_rustc = features.staged_api(); - - if let Some(value) = args.name_value() - && let Some(value_str) = value.value_as_str() - { - note = Some(value_str) - } else if let Some(list) = args.list() { - for param in list.mixed() { - let param_span = param.span(); - let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, - reason: UnsupportedLiteralReason::DeprecatedKvPair, - is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), + if attr.is_doc_comment() { + continue; + } else if attr.is_word() { + } else if let Some(value) = attr.value_str() { + note = Some(value) + } else if let Some(list) = attr.meta_item_list() { + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + sess.dcx().emit_err(session_diagnostics::MultipleItem { + span: meta.span, + item: pprust::path_to_string(&meta.path), }); - return None; - }; + return false; + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + if let Some(lit) = meta.name_value_literal() { + sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { + span: lit.span, + reason: UnsupportedLiteralReason::DeprecatedString, + is_bytestr: lit.kind.is_bytestr(), + start_point_span: sess.source_map().start_point(lit.span), + }); + } else { + sess.dcx() + .emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); + } + false + } + }; - let (ident, arg) = param.word_or_empty(); + for meta in &list { + match meta { + MetaItemInner::MetaItem(mi) => match mi.name_or_empty() { + sym::since => { + if !get(mi, &mut since) { + continue 'outer; + } + } + sym::note => { + if !get(mi, &mut note) { + continue 'outer; + } + } + sym::suggestion => { + if !features.deprecated_suggestion() { + sess.dcx().emit_err( + session_diagnostics::DeprecatedItemSuggestion { + span: mi.span, + is_nightly: sess.is_nightly_build(), + details: (), + }, + ); + } - match ident.name { - sym::since => { - since = Some(get(cx, ident, param_span, arg, &since)?); - } - sym::note => { - note = Some(get(cx, ident, param_span, arg, ¬e)?); - } - sym::suggestion => { - if !features.deprecated_suggestion() { - cx.emit_err(session_diagnostics::DeprecatedItemSuggestion { - span: param_span, - is_nightly: cx.sess().is_nightly_build(), - details: (), + if !get(mi, &mut suggestion) { + continue 'outer; + } + } + _ => { + sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { + span: meta.span(), + item: pprust::path_to_string(&mi.path), + expected: if features.deprecated_suggestion() { + &["since", "note", "suggestion"] + } else { + &["since", "note"] + }, }); + continue 'outer; } - - suggestion = Some(get(cx, ident, param_span, arg, &suggestion)?); - } - _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: ident.to_string(), - expected: if features.deprecated_suggestion() { - &["since", "note", "suggestion"] - } else { - &["since", "note"] - }, + }, + MetaItemInner::Lit(lit) => { + sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { + span: lit.span, + reason: UnsupportedLiteralReason::DeprecatedKvPair, + is_bytestr: false, + start_point_span: sess.source_map().start_point(lit.span), }); - return None; + continue 'outer; } } } + } else { + continue; } let since = if let Some(since) = since { @@ -127,24 +126,23 @@ impl SingleAttributeParser for DeprecationParser { } else if let Some(version) = parse_version(since) { DeprecatedSince::RustcVersion(version) } else { - cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); + sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() }); DeprecatedSince::Err } } else if is_rustc { - cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); + sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() }); DeprecatedSince::Err } else { DeprecatedSince::Unspecified }; if is_rustc && note.is_none() { - cx.emit_err(session_diagnostics::MissingNote { span: cx.attr_span }); - return None; + sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span() }); + continue; } - Some(AttributeKind::Deprecation { - deprecation: Deprecation { since, note, suggestion }, - span: cx.attr_span, - }) + depr = Some((Deprecation { since, note, suggestion }, attr.span())); } + + depr } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..a78e0b54b64aa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -1,152 +1,17 @@ -//! This module defines traits for attribute parsers, little state machines that recognize and parse -//! attributes out of a longer list of attributes. The main trait is called [`AttributeParser`]. -//! You can find more docs about [`AttributeParser`]s on the trait itself. -//! However, for many types of attributes, implementing [`AttributeParser`] is not necessary. -//! It allows for a lot of flexibility you might not want. -//! -//! Specifically, you might not care about managing the state of your [`AttributeParser`] -//! state machine yourself. In this case you can choose to implement: -//! -//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it -//! appears more than once in a list of attributes -//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the -//! contents of attributes, if an attribute appear multiple times in a list -//! -//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed. - -use std::marker::PhantomData; - -use rustc_attr_data_structures::AttributeKind; -use rustc_span::Span; -use thin_vec::ThinVec; - -use crate::context::{AcceptContext, FinalizeContext}; -use crate::parser::ArgParser; - -pub(crate) mod allow_unstable; -pub(crate) mod cfg; -pub(crate) mod confusables; -pub(crate) mod deprecation; -pub(crate) mod repr; -pub(crate) mod stability; -pub(crate) mod transparency; -pub(crate) mod util; - -type AcceptFn = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; - -/// An [`AttributeParser`] is a type which searches for syntactic attributes. -/// -/// Parsers are often tiny state machines that gets to see all syntactical attributes on an item. -/// [`Default::default`] creates a fresh instance that sits in some kind of initial state, usually that the -/// attribute it is looking for was not yet seen. -/// -/// Then, it defines what paths this group will accept in [`AttributeParser::ATTRIBUTES`]. -/// These are listed as pairs, of symbols and function pointers. The function pointer will -/// be called when that attribute is found on an item, which can influence the state of the little -/// state machine. -/// -/// Finally, after all attributes on an item have been seen, and possibly been accepted, -/// the [`finalize`](AttributeParser::finalize) functions for all attribute parsers are called. Each can then report -/// whether it has seen the attribute it has been looking for. -/// -/// The state machine is automatically reset to parse attributes on the next item. -pub(crate) trait AttributeParser: Default + 'static { - /// The symbols for the attributes that this parser is interested in. - /// - /// If an attribute has this symbol, the `accept` function will be called on it. - const ATTRIBUTES: AcceptMapping; - - /// The parser has gotten a chance to accept the attributes on an item, - /// here it can produce an attribute. - fn finalize(self, cx: &FinalizeContext<'_>) -> Option; -} - -/// Alternative to [`AttributeParser`] that automatically handles state management. -/// A slightly simpler and more restricted way to convert attributes. -/// Assumes that an attribute can only appear a single time on an item, -/// and errors when it sees more. -/// -/// [`Single where T: SingleAttributeParser`](Single) implements [`AttributeParser`]. -/// -/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple -/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait SingleAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; - - /// Caled when a duplicate attribute is found. - /// - /// `first_span` is the span of the first occurrence of this attribute. - // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span); - - /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option; -} - -pub(crate) struct Single(PhantomData, Option<(AttributeKind, Span)>); - -impl Default for Single { - fn default() -> Self { - Self(Default::default(), Default::default()) - } -} - -impl AttributeParser for Single { - const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { - if let Some((_, s)) = group.1 { - T::on_duplicate(cx, s); - return; - } - - if let Some(pa) = T::convert(cx, args) { - group.1 = Some((pa, cx.attr_span)); - } - })]; - - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { - Some(self.1?.0) - } -} - -type ConvertFn = fn(ThinVec) -> AttributeKind; - -/// Alternative to [`AttributeParser`] that automatically handles state management. -/// If multiple attributes appear on an element, combines the values of each into a -/// [`ThinVec`]. -/// [`Combine where T: CombineAttributeParser`](Combine) implements [`AttributeParser`]. -/// -/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple -/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait CombineAttributeParser: 'static { - const PATH: &'static [rustc_span::Symbol]; - - type Item; - const CONVERT: ConvertFn; - - /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a; -} - -pub(crate) struct Combine( - PhantomData, - ThinVec<::Item>, -); - -impl Default for Combine { - fn default() -> Self { - Self(Default::default(), Default::default()) - } -} - -impl AttributeParser for Combine { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; - - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { - if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } - } -} +mod allow_unstable; +mod cfg; +mod confusables; +mod deprecation; +mod repr; +mod stability; +mod transparency; + +pub mod util; + +pub use allow_unstable::*; +pub use cfg::*; +pub use confusables::*; +pub use deprecation::*; +pub use repr::*; +pub use stability::*; +pub use transparency::*; diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 26ca637faec68..28c381160b874 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,13 +1,15 @@ +//! Parsing and validation of builtin attributes + use rustc_abi::Align; -use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; -use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; -use rustc_span::{Span, Symbol, sym}; +use rustc_ast::attr::AttributeExt; +use rustc_ast::{self as ast, MetaItemKind}; +use rustc_attr_data_structures::IntType; +use rustc_attr_data_structures::ReprAttr::*; +use rustc_session::Session; +use rustc_span::{Symbol, sym}; -use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; -use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; -use crate::session_diagnostics; -use crate::session_diagnostics::IncorrectReprFormatGenericCause; +use crate::ReprAttr; +use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; /// Parse #[repr(...)] forms. /// @@ -16,216 +18,185 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause; /// the same discriminant size that the corresponding C enum would or C /// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// concerns to the only non-ZST field. -// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct? -pub(crate) struct ReprParser; - -impl CombineAttributeParser for ReprParser { - type Item = (ReprAttr, Span); - const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; - const CONVERT: ConvertFn = AttributeKind::Repr; - - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { - let mut reprs = Vec::new(); - - let Some(list) = args.list() else { - return reprs; - }; - - if list.is_empty() { - // this is so validation can emit a lint - reprs.push((ReprAttr::ReprEmpty, cx.attr_span)); - } +pub fn find_repr_attrs(sess: &Session, attr: &impl AttributeExt) -> Vec { + if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() } +} - for param in list.mixed() { - if let Some(_) = param.lit() { - cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span }); - continue; +pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec { + assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}"); + let mut acc = Vec::new(); + let dcx = sess.dcx(); + + if let Some(items) = attr.meta_item_list() { + for item in items { + let mut recognised = false; + if item.is_word() { + let hint = match item.name_or_empty() { + sym::Rust => Some(ReprRust), + sym::C => Some(ReprC), + sym::packed => Some(ReprPacked(Align::ONE)), + sym::simd => Some(ReprSimd), + sym::transparent => Some(ReprTransparent), + sym::align => { + sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg { + span: item.span(), + }); + recognised = true; + None + } + name => int_type_of_word(name).map(ReprInt), + }; + + if let Some(h) = hint { + recognised = true; + acc.push(h); + } + } else if let Some((name, value)) = item.singleton_lit_list() { + let mut literal_error = None; + let mut err_span = item.span(); + if name == sym::align { + recognised = true; + match parse_alignment(&value.kind) { + Ok(literal) => acc.push(ReprAlign(literal)), + Err(message) => { + err_span = value.span; + literal_error = Some(message) + } + }; + } else if name == sym::packed { + recognised = true; + match parse_alignment(&value.kind) { + Ok(literal) => acc.push(ReprPacked(literal)), + Err(message) => { + err_span = value.span; + literal_error = Some(message) + } + }; + } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent) + || int_type_of_word(name).is_some() + { + recognised = true; + sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { + span: item.span(), + name: name.to_ident_string(), + }); + } + if let Some(literal_error) = literal_error { + sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric { + span: err_span, + repr_arg: name.to_ident_string(), + error_part: literal_error, + }); + } + } else if let Some(meta_item) = item.meta_item() { + match &meta_item.kind { + MetaItemKind::NameValue(value) => { + if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { + let name = meta_item.name_or_empty().to_ident_string(); + recognised = true; + sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric { + span: item.span(), + repr_arg: &name, + cause: IncorrectReprFormatGenericCause::from_lit_kind( + item.span(), + &value.kind, + &name, + ), + }); + } else if matches!( + meta_item.name_or_empty(), + sym::Rust | sym::C | sym::simd | sym::transparent + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { + recognised = true; + sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); + } + } + MetaItemKind::List(nested_items) => { + if meta_item.has_name(sym::align) { + recognised = true; + if let [nested_item] = nested_items.as_slice() { + sess.dcx().emit_err( + session_diagnostics::IncorrectReprFormatExpectInteger { + span: nested_item.span(), + }, + ); + } else { + sess.dcx().emit_err( + session_diagnostics::IncorrectReprFormatAlignOneArg { + span: meta_item.span, + }, + ); + } + } else if meta_item.has_name(sym::packed) { + recognised = true; + if let [nested_item] = nested_items.as_slice() { + sess.dcx().emit_err( + session_diagnostics::IncorrectReprFormatPackedExpectInteger { + span: nested_item.span(), + }, + ); + } else { + sess.dcx().emit_err( + session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { + span: meta_item.span, + }, + ); + } + } else if matches!( + meta_item.name_or_empty(), + sym::Rust | sym::C | sym::simd | sym::transparent + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { + recognised = true; + sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); + } + } + _ => (), + } + } + if !recognised { + // Not a word we recognize. This will be caught and reported by + // the `check_mod_attrs` pass, but this pass doesn't always run + // (e.g. if we only pretty-print the source), so we have to gate + // the `span_delayed_bug` call as follows: + if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) { + dcx.span_delayed_bug(item.span(), "unrecognized representation hint"); + } } - - reprs.extend( - param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())), - ); } - - reprs } -} - -macro_rules! int_pat { - () => { - sym::i8 - | sym::u8 - | sym::i16 - | sym::u16 - | sym::i32 - | sym::u32 - | sym::i64 - | sym::u64 - | sym::i128 - | sym::u128 - | sym::isize - | sym::usize - }; + acc } fn int_type_of_word(s: Symbol) -> Option { - use IntType::*; + use rustc_attr_data_structures::IntType::*; match s { - sym::i8 => Some(SignedInt(IntTy::I8)), - sym::u8 => Some(UnsignedInt(UintTy::U8)), - sym::i16 => Some(SignedInt(IntTy::I16)), - sym::u16 => Some(UnsignedInt(UintTy::U16)), - sym::i32 => Some(SignedInt(IntTy::I32)), - sym::u32 => Some(UnsignedInt(UintTy::U32)), - sym::i64 => Some(SignedInt(IntTy::I64)), - sym::u64 => Some(UnsignedInt(UintTy::U64)), - sym::i128 => Some(SignedInt(IntTy::I128)), - sym::u128 => Some(UnsignedInt(UintTy::U128)), - sym::isize => Some(SignedInt(IntTy::Isize)), - sym::usize => Some(UnsignedInt(UintTy::Usize)), + sym::i8 => Some(SignedInt(ast::IntTy::I8)), + sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), + sym::i16 => Some(SignedInt(ast::IntTy::I16)), + sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), + sym::i32 => Some(SignedInt(ast::IntTy::I32)), + sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), + sym::i64 => Some(SignedInt(ast::IntTy::I64)), + sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), + sym::i128 => Some(SignedInt(ast::IntTy::I128)), + sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), + sym::isize => Some(SignedInt(ast::IntTy::Isize)), + sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), _ => None, } } -fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option { - use ReprAttr::*; - - // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the - // structure. - let (ident, args) = param.word_or_empty(); - - match (ident.name, args) { - (sym::align, ArgParser::NoArgs) => { - cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span }); - None - } - (sym::align, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Align), - - (sym::packed, ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)), - (sym::packed, ArgParser::List(l)) => { - parse_repr_align(cx, l, param.span(), AlignKind::Packed) - } - - (sym::align | sym::packed, ArgParser::NameValue(l)) => { - cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric { - span: param.span(), - // FIXME(jdonszelmann) can just be a string in the diag type - repr_arg: &ident.to_string(), - cause: IncorrectReprFormatGenericCause::from_lit_kind( - param.span(), - &l.value_as_lit().kind, - ident.name.as_str(), - ), - }); - None - } - - (sym::Rust, ArgParser::NoArgs) => Some(ReprRust), - (sym::C, ArgParser::NoArgs) => Some(ReprC), - (sym::simd, ArgParser::NoArgs) => Some(ReprSimd), - (sym::transparent, ArgParser::NoArgs) => Some(ReprTransparent), - (i @ int_pat!(), ArgParser::NoArgs) => { - // int_pat!() should make sure it always parses - Some(ReprInt(int_type_of_word(i).unwrap())) - } - - ( - sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), - ArgParser::NameValue(_), - ) => { - cx.emit_err(session_diagnostics::InvalidReprHintNoValue { - span: param.span(), - name: ident.to_string(), - }); - None - } - (sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::List(_)) => { - cx.emit_err(session_diagnostics::InvalidReprHintNoParen { - span: param.span(), - name: ident.to_string(), - }); - None - } - - _ => { - cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() }); - None - } - } -} - -enum AlignKind { - Packed, - Align, -} - -fn parse_repr_align( - cx: &AcceptContext<'_>, - list: &MetaItemListParser<'_>, - param_span: Span, - align_kind: AlignKind, -) -> Option { - use AlignKind::*; - - let Some(align) = list.single() else { - match align_kind { - Packed => { - cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { - span: param_span, - }); - } - Align => { - cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { - span: param_span, - }); - } - } - - return None; - }; - - let Some(lit) = align.lit() else { - match align_kind { - Packed => { - cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger { - span: align.span(), - }); - } - Align => { - cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { - span: align.span(), - }); - } - } - - return None; - }; - - match parse_alignment(&lit.kind) { - Ok(literal) => Some(match align_kind { - AlignKind::Packed => ReprAttr::ReprPacked(literal), - AlignKind::Align => ReprAttr::ReprAlign(literal), - }), - Err(message) => { - cx.emit_err(session_diagnostics::InvalidReprGeneric { - span: lit.span, - repr_arg: match align_kind { - Packed => "packed".to_string(), - Align => "align".to_string(), - }, - error_part: message, - }); - None - } - } -} - -fn parse_alignment(node: &LitKind) -> Result { - if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { +pub fn parse_alignment(node: &ast::LitKind) -> Result { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first if literal.get().is_power_of_two() { // Only possible error is larger than 2^29 diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6d76456e83c80..454b8b5de82b5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,258 +1,266 @@ +//! Parsing and validation of builtin attributes + use std::num::NonZero; +use rustc_ast::MetaItem; +use rustc_ast::attr::AttributeExt; +use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{ - AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, + ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason, + VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; +use rustc_session::Session; use rustc_span::{Span, Symbol, kw, sym}; -use super::util::parse_version; -use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; -use crate::context::{AcceptContext, FinalizeContext}; -use crate::parser::{ArgParser, MetaItemParser}; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; - -macro_rules! reject_outside_std { - ($cx: ident) => { - // Emit errors for non-staged-api crates. - if !$cx.features().staged_api() { - $cx.emit_err(session_diagnostics::StabilityOutsideStd { span: $cx.attr_span }); - return; - } - }; -} - -#[derive(Default)] -pub(crate) struct StabilityParser { - allowed_through_unstable_modules: Option, - stability: Option<(Stability, Span)>, -} - -impl StabilityParser { - /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { - if let Some((_, _)) = self.stability { - cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); - true - } else { - false - } - } -} +use crate::attributes::util::UnsupportedLiteralReason; +use crate::{parse_version, session_diagnostics}; + +/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules` +/// attributes in `attrs`. Returns `None` if no stability attributes are found. +pub fn find_stability( + sess: &Session, + attrs: &[impl AttributeExt], + item_sp: Span, +) -> Option<(Stability, Span)> { + let mut stab: Option<(Stability, Span)> = None; + let mut allowed_through_unstable_modules = None; + + for attr in attrs { + match attr.name_or_empty() { + sym::rustc_allowed_through_unstable_modules => { + // The value is mandatory, but avoid ICEs in case such code reaches this function. + allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| { + sess.dcx().span_delayed_bug( + item_sp, + "`#[rustc_allowed_through_unstable_modules]` without deprecation message", + ); + kw::Empty + })) + } + sym::unstable => { + if stab.is_some() { + sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { + span: attr.span(), + }); + break; + } -impl AttributeParser for StabilityParser { - const ATTRIBUTES: AcceptMapping = &[ - (&[sym::stable], |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_stability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); + if let Some((feature, level)) = parse_unstability(sess, attr) { + stab = Some((Stability { level, feature }, attr.span())); + } } - }), - (&[sym::unstable], |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_unstability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); + sym::stable => { + if stab.is_some() { + sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { + span: attr.span(), + }); + break; + } + if let Some((feature, level)) = parse_stability(sess, attr) { + stab = Some((Stability { level, feature }, attr.span())); + } } - }), - (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| { - reject_outside_std!(cx); - this.allowed_through_unstable_modules = - Some(match args.name_value().and_then(|i| i.value_as_str()) { - Some(msg) => msg, - None => kw::Empty, - }); - }), - ]; + _ => {} + } + } - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { - if let Some(atum) = self.allowed_through_unstable_modules { - if let Some(( + if let Some(allowed_through_unstable_modules) = allowed_through_unstable_modules { + match &mut stab { + Some(( Stability { - level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. }, + level: StabilityLevel::Stable { allowed_through_unstable_modules: in_stab, .. }, .. }, _, - )) = self.stability - { - *allowed_through_unstable_modules = Some(atum); - } else { - cx.dcx().emit_err(session_diagnostics::RustcAllowedUnstablePairing { - span: cx.target_span, - }); + )) => *in_stab = Some(allowed_through_unstable_modules), + _ => { + sess.dcx() + .emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); } } - - let (stability, span) = self.stability?; - - Some(AttributeKind::Stability { stability, span }) } -} -// FIXME(jdonszelmann) change to Single -#[derive(Default)] -pub(crate) struct BodyStabilityParser { - stability: Option<(DefaultBodyStability, Span)>, + stab } -impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping = - &[(&[sym::rustc_default_body_unstable], |this, cx, args| { - reject_outside_std!(cx); - if this.stability.is_some() { - cx.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); - } else if let Some((feature, level)) = parse_unstability(cx, args) { - this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span)); - } - })]; - - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { - let (stability, span) = self.stability?; +/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` +/// attributes in `attrs`. Returns `None` if no stability attributes are found. +pub fn find_const_stability( + sess: &Session, + attrs: &[impl AttributeExt], + item_sp: Span, +) -> Option<(ConstStability, Span)> { + let mut const_stab: Option<(ConstStability, Span)> = None; + let mut promotable = false; + let mut const_stable_indirect = false; + + for attr in attrs { + match attr.name_or_empty() { + sym::rustc_promotable => promotable = true, + sym::rustc_const_stable_indirect => const_stable_indirect = true, + sym::rustc_const_unstable => { + if const_stab.is_some() { + sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { + span: attr.span(), + }); + break; + } - Some(AttributeKind::BodyStability { stability, span }) + if let Some((feature, level)) = parse_unstability(sess, attr) { + const_stab = Some(( + ConstStability { + level, + feature, + const_stable_indirect: false, + promotable: false, + }, + attr.span(), + )); + } + } + sym::rustc_const_stable => { + if const_stab.is_some() { + sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { + span: attr.span(), + }); + break; + } + if let Some((feature, level)) = parse_stability(sess, attr) { + const_stab = Some(( + ConstStability { + level, + feature, + const_stable_indirect: false, + promotable: false, + }, + attr.span(), + )); + } + } + _ => {} + } } -} - -pub(crate) struct ConstStabilityIndirectParser; -// FIXME(jdonszelmann): single word attribute group when we have these -impl SingleAttributeParser for ConstStabilityIndirectParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; - - // ignore - fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} - fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { - Some(AttributeKind::ConstStabilityIndirect) + // Merge promotable and const_stable_indirect into stability info + if promotable { + match &mut const_stab { + Some((stab, _)) => stab.promotable = promotable, + _ => { + _ = sess + .dcx() + .emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }) + } + } + } + if const_stable_indirect { + match &mut const_stab { + Some((stab, _)) => { + if stab.is_const_unstable() { + stab.const_stable_indirect = true; + } else { + _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing { + span: item_sp, + }) + } + } + _ => { + // This function has no const stability attribute, but has `const_stable_indirect`. + // We ignore that; unmarked functions are subject to recursive const stability + // checks by default so we do carry out the user's intent. + } + } } -} -#[derive(Default)] -pub(crate) struct ConstStabilityParser { - promotable: bool, - stability: Option<(PartialConstStability, Span)>, + const_stab } -impl ConstStabilityParser { - /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { - if let Some((_, _)) = self.stability { - cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); - true - } else { - false - } +/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate +/// without the `staged_api` feature. +pub fn unmarked_crate_const_stab( + _sess: &Session, + attrs: &[impl AttributeExt], + regular_stab: Stability, +) -> ConstStability { + assert!(regular_stab.level.is_unstable()); + // The only attribute that matters here is `rustc_const_stable_indirect`. + // We enforce recursive const stability rules for those functions. + let const_stable_indirect = + attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect); + ConstStability { + feature: regular_stab.feature, + const_stable_indirect, + promotable: false, + level: regular_stab.level, } } -impl AttributeParser for ConstStabilityParser { - const ATTRIBUTES: AcceptMapping = &[ - (&[sym::rustc_const_stable], |this, cx, args| { - reject_outside_std!(cx); - - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_stability(cx, args) - { - this.stability = Some(( - PartialConstStability { level, feature, promotable: false }, - cx.attr_span, - )); - } - }), - (&[sym::rustc_const_unstable], |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_unstability(cx, args) - { - this.stability = Some(( - PartialConstStability { level, feature, promotable: false }, - cx.attr_span, - )); +/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. +/// Returns `None` if no stability attributes are found. +pub fn find_body_stability( + sess: &Session, + attrs: &[impl AttributeExt], +) -> Option<(DefaultBodyStability, Span)> { + let mut body_stab: Option<(DefaultBodyStability, Span)> = None; + + for attr in attrs { + if attr.has_name(sym::rustc_default_body_unstable) { + if body_stab.is_some() { + sess.dcx() + .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span() }); + break; } - }), - (&[sym::rustc_promotable], |this, cx, _| { - reject_outside_std!(cx); - this.promotable = true; - }), - ]; - - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { - if self.promotable { - if let Some((ref mut stab, _)) = self.stability { - stab.promotable = true; - } else { - cx.dcx() - .emit_err(session_diagnostics::RustcPromotablePairing { span: cx.target_span }); + + if let Some((feature, level)) = parse_unstability(sess, attr) { + body_stab = Some((DefaultBodyStability { level, feature }, attr.span())); } } - - let (stability, span) = self.stability?; - - Some(AttributeKind::ConstStability { stability, span }) } + + body_stab } -/// Tries to insert the value of a `key = value` meta item into an option. -/// -/// Emits an error when either the option was already Some, or the arguments weren't of form -/// `name = value` -fn insert_value_into_option_or_error( - cx: &AcceptContext<'_>, - param: &MetaItemParser<'_>, - item: &mut Option, -) -> Option<()> { +fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option) -> Option<()> { if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { - span: param.span(), - item: param.path_without_args().to_string(), + sess.dcx().emit_err(session_diagnostics::MultipleItem { + span: meta.span, + item: pprust::path_to_string(&meta.path), }); None - } else if let Some(v) = param.args().name_value() - && let Some(s) = v.value_as_str() - { - *item = Some(s); + } else if let Some(v) = meta.value_str() { + *item = Some(v); Some(()) } else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span: param.span(), - suggestion: None, - }); + sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); None } } /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// its stability information. -pub(crate) fn parse_stability( - cx: &AcceptContext<'_>, - args: &ArgParser<'_>, -) -> Option<(Symbol, StabilityLevel)> { +fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> { + let metas = attr.meta_item_list()?; + let mut feature = None; let mut since = None; - - for param in args.list()?.mixed() { - let param_span = param.span(); - let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param_span, + for meta in metas { + let Some(mi) = meta.meta_item() else { + sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { + span: meta.span(), reason: UnsupportedLiteralReason::Generic, is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param_span), + start_point_span: sess.source_map().start_point(meta.span()), }); return None; }; - match param.word_or_empty_without_args().name { - sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since)?, + match mi.name_or_empty() { + sym::feature => insert_or_error(sess, mi, &mut feature)?, + sym::since => insert_or_error(sess, mi, &mut since)?, _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: param.path_without_args().to_string(), + sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { + span: meta.span(), + item: pprust::path_to_string(&mi.path), expected: &["feature", "since"], }); return None; @@ -263,9 +271,9 @@ pub(crate) fn parse_stability( let feature = match feature { Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(_bad_feature) => { - Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span })) + Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() })) } - None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })), + None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })), }; let since = if let Some(since) = since { @@ -274,11 +282,11 @@ pub(crate) fn parse_stability( } else if let Some(version) = parse_version(since) { StableSince::Version(version) } else { - cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); + sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() }); StableSince::Err } } else { - cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); + sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() }); StableSince::Err }; @@ -291,48 +299,46 @@ pub(crate) fn parse_stability( } } -// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` +/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. -pub(crate) fn parse_unstability( - cx: &AcceptContext<'_>, - args: &ArgParser<'_>, -) -> Option<(Symbol, StabilityLevel)> { +fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> { + let metas = attr.meta_item_list()?; + let mut feature = None; let mut reason = None; let mut issue = None; let mut issue_num = None; let mut is_soft = false; let mut implied_by = None; - for param in args.list()?.mixed() { - let Some(param) = param.meta_item() else { - cx.emit_err(session_diagnostics::UnsupportedLiteral { - span: param.span(), + for meta in metas { + let Some(mi) = meta.meta_item() else { + sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { + span: meta.span(), reason: UnsupportedLiteralReason::Generic, is_bytestr: false, - start_point_span: cx.sess().source_map().start_point(param.span()), + start_point_span: sess.source_map().start_point(meta.span()), }); return None; }; - let (word, args) = param.word_or_empty(); - match word.name { - sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, + match mi.name_or_empty() { + sym::feature => insert_or_error(sess, mi, &mut feature)?, + sym::reason => insert_or_error(sess, mi, &mut reason)?, sym::issue => { - insert_value_into_option_or_error(cx, ¶m, &mut issue)?; + insert_or_error(sess, mi, &mut issue)?; - // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item + // These unwraps are safe because `insert_or_error` ensures the meta item // is a name/value pair string literal. issue_num = match issue.unwrap().as_str() { "none" => None, - issue_str => match issue_str.parse::>() { + issue => match issue.parse::>() { Ok(num) => Some(num), Err(err) => { - cx.emit_err( + sess.dcx().emit_err( session_diagnostics::InvalidIssueString { - span: param.span(), + span: mi.span, cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( - args.name_value().unwrap().value_span, + mi.name_value_literal_span().unwrap(), err.kind(), ), }, @@ -343,16 +349,16 @@ pub(crate) fn parse_unstability( }; } sym::soft => { - if !args.no_args() { - cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() }); + if !mi.is_word() { + sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span }); } is_soft = true; } - sym::implied_by => insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?, + sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?, _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param.span(), - item: param.path_without_args().to_string(), + sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { + span: meta.span(), + item: pprust::path_to_string(&mi.path), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; @@ -363,13 +369,14 @@ pub(crate) fn parse_unstability( let feature = match feature { Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(_bad_feature) => { - Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span })) + Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() })) } - None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })), + None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })), }; - let issue = - issue.ok_or_else(|| cx.emit_err(session_diagnostics::MissingIssue { span: cx.attr_span })); + let issue = issue.ok_or_else(|| { + sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span() }) + }); match (feature, issue) { (Ok(feature), Ok(_)) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ad83a1f7af80c..f4065a7704841 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,33 +1,36 @@ -use rustc_attr_data_structures::AttributeKind; +use rustc_ast::attr::AttributeExt; +use rustc_attr_data_structures::TransparencyError; use rustc_span::hygiene::Transparency; use rustc_span::sym; -use super::{AcceptContext, SingleAttributeParser}; -use crate::parser::ArgParser; - -pub(crate) struct TransparencyParser; - -// FIXME(jdonszelmann): make these proper diagnostics -#[allow(rustc::untranslatable_diagnostic)] -#[allow(rustc::diagnostic_outside_of_impl)] -impl SingleAttributeParser for TransparencyParser { - const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; - - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) { - cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { - match args.name_value().and_then(|nv| nv.value_as_str()) { - Some(sym::transparent) => Some(Transparency::Transparent), - Some(sym::semitransparent) => Some(Transparency::SemiTransparent), - Some(sym::opaque) => Some(Transparency::Opaque), - Some(other) => { - cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); - None +pub fn find_transparency( + attrs: &[impl AttributeExt], + macro_rules: bool, +) -> (Transparency, Option) { + let mut transparency = None; + let mut error = None; + for attr in attrs { + if attr.has_name(sym::rustc_macro_transparency) { + if let Some((_, old_span)) = transparency { + error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span())); + break; + } else if let Some(value) = attr.value_str() { + transparency = Some(( + match value { + sym::transparent => Transparency::Transparent, + sym::semitransparent => Transparency::SemiTransparent, + sym::opaque => Transparency::Opaque, + _ => { + error = + Some(TransparencyError::UnknownTransparency(value, attr.span())); + continue; + } + }, + attr.span(), + )); } - None => None, } - .map(AttributeKind::MacroTransparency) } + let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }; + (transparency.map_or(fallback, |t| t.0), error) } diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 05a9029c59aa5..e36f7dfff5a5f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -3,6 +3,22 @@ use rustc_attr_data_structures::RustcVersion; use rustc_feature::is_builtin_attr_name; use rustc_span::{Symbol, sym}; +pub(crate) enum UnsupportedLiteralReason { + Generic, + CfgString, + CfgBoolean, + DeprecatedString, + DeprecatedKvPair, +} + +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) +} + /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are /// not accepted in this position, unlike when parsing CFG_RELEASE. @@ -18,11 +34,3 @@ pub fn parse_version(s: Symbol) -> Option { let patch = digits.next().unwrap_or("0").parse().ok()?; Some(RustcVersion { major, minor, patch }) } - -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) -} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs deleted file mode 100644 index 99eee0d3c4a29..0000000000000 --- a/compiler/rustc_attr_parsing/src/context.rs +++ /dev/null @@ -1,348 +0,0 @@ -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::ops::Deref; -use std::sync::LazyLock; - -use rustc_ast::{self as ast, DelimArgs}; -use rustc_attr_data_structures::AttributeKind; -use rustc_errors::{DiagCtxtHandle, Diagnostic}; -use rustc_feature::Features; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; -use rustc_session::Session; -use rustc_span::symbol::kw; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; - -use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; -use crate::attributes::confusables::ConfusablesParser; -use crate::attributes::deprecation::DeprecationParser; -use crate::attributes::repr::ReprParser; -use crate::attributes::stability::{ - BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, -}; -use crate::attributes::transparency::TransparencyParser; -use crate::attributes::{AttributeParser as _, Combine, Single}; -use crate::parser::{ArgParser, MetaItemParser}; - -macro_rules! attribute_groups { - ( - pub(crate) static $name: ident = [$($names: ty),* $(,)?]; - ) => { - pub(crate) static $name: LazyLock<( - BTreeMap<&'static [Symbol], Vec, &ArgParser<'_>) + Send + Sync>>>, - Vec) -> Option>> - )> = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec, &ArgParser<'_>) + Send + Sync>>>::new(); - let mut finalizes = Vec::) -> Option>>::new(); - $( - { - thread_local! { - static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default()); - }; - - for (k, v) in <$names>::ATTRIBUTES { - accepts.entry(*k).or_default().push(Box::new(|cx, args| { - STATE_OBJECT.with_borrow_mut(|s| { - v(s, cx, args) - }) - })); - } - - finalizes.push(Box::new(|cx| { - let state = STATE_OBJECT.take(); - state.finalize(cx) - })); - } - )* - - (accepts, finalizes) - }); - }; -} - -attribute_groups!( - pub(crate) static ATTRIBUTE_MAPPING = [ - // tidy-alphabetical-start - BodyStabilityParser, - ConfusablesParser, - ConstStabilityParser, - StabilityParser, - // tidy-alphabetical-end - - // tidy-alphabetical-start - Combine, - Combine, - Combine, - // tidy-alphabetical-end - - // tidy-alphabetical-start - Single, - Single, - Single, - // tidy-alphabetical-end - ]; -); - -/// Context given to every attribute parser when accepting -/// -/// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'a> { - pub(crate) group_cx: &'a FinalizeContext<'a>, - /// The span of the attribute currently being parsed - pub(crate) attr_span: Span, -} - -impl<'a> AcceptContext<'a> { - pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed { - if self.limit_diagnostics { - self.dcx().create_err(diag).delay_as_bug() - } else { - self.dcx().emit_err(diag) - } - } -} - -impl<'a> Deref for AcceptContext<'a> { - type Target = FinalizeContext<'a>; - - fn deref(&self) -> &Self::Target { - &self.group_cx - } -} - -/// Context given to every attribute parser during finalization. -/// -/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. -pub(crate) struct FinalizeContext<'a> { - /// The parse context, gives access to the session and the - /// diagnostics context. - pub(crate) cx: &'a AttributeParser<'a>, - /// The span of the syntactical component this attribute was applied to - pub(crate) target_span: Span, -} - -impl<'a> Deref for FinalizeContext<'a> { - type Target = AttributeParser<'a>; - - fn deref(&self) -> &Self::Target { - &self.cx - } -} - -#[derive(PartialEq, Clone, Copy, Debug)] -pub enum OmitDoc { - Lower, - Skip, -} - -/// Context created once, for example as part of the ast lowering -/// context, through which all attributes can be lowered. -pub struct AttributeParser<'sess> { - #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes - tools: Vec, - sess: &'sess Session, - features: Option<&'sess Features>, - - /// *only* parse attributes with this symbol. - /// - /// Used in cases where we want the lowering infrastructure for - /// parse just a single attribute. - parse_only: Option, - - /// Can be used to instruct parsers to reduce the number of diagnostics it emits. - /// Useful when using `parse_limited` and you know the attr will be reparsed later. - pub(crate) limit_diagnostics: bool, -} - -impl<'sess> AttributeParser<'sess> { - /// This method allows you to parse attributes *before* you have access to features or tools. - /// One example where this is necessary, is to parse `feature` attributes themselves for - /// example. - /// - /// Try to use this as little as possible. Attributes *should* be lowered during `rustc_ast_lowering`. - /// Some attributes require access to features to parse, which would crash if you tried to do so - /// through [`parse_limited`](Self::parse_limited). - /// - /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with - /// that symbol are picked out of the list of instructions and parsed. Those are returned. - pub fn parse_limited( - sess: &'sess Session, - attrs: &[ast::Attribute], - sym: Symbol, - target_span: Span, - limit_diagnostics: bool, - ) -> Option { - let mut parsed = Self { - sess, - features: None, - tools: Vec::new(), - parse_only: Some(sym), - limit_diagnostics, - } - .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity); - - assert!(parsed.len() <= 1); - - parsed.pop() - } - - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false } - } - - pub(crate) fn sess(&self) -> &'sess Session { - self.sess - } - - pub(crate) fn features(&self) -> &'sess Features { - self.features.expect("features not available at this point in the compiler") - } - - pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { - self.sess.dcx() - } - - /// Parse a list of attributes. - /// - /// `target_span` is the span of the thing this list of attributes is applied to, - /// and when `omit_doc` is set, doc attributes are filtered out. - pub fn parse_attribute_list<'a>( - &'a self, - attrs: &'a [ast::Attribute], - target_span: Span, - omit_doc: OmitDoc, - - lower_span: impl Copy + Fn(Span) -> Span, - ) -> Vec { - let mut attributes = Vec::new(); - - let group_cx = FinalizeContext { cx: self, target_span }; - - for attr in attrs { - // if we're only looking for a single attribute, - // skip all the ones we don't care about - if let Some(expected) = self.parse_only { - if attr.name_or_empty() != expected { - continue; - } - } - - // sometimes, for example for `#![doc = include_str!("readme.md")]`, - // doc still contains a non-literal. You might say, when we're lowering attributes - // that's expanded right? But no, sometimes, when parsing attributes on macros, - // we already use the lowering logic and these are still there. So, when `omit_doc` - // is set we *also* want to ignore these - if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc { - continue; - } - - match &attr.kind { - ast::AttrKind::DocComment(comment_kind, symbol) => { - if omit_doc == OmitDoc::Skip { - continue; - } - - attributes.push(Attribute::Parsed(AttributeKind::DocComment { - style: attr.style, - kind: *comment_kind, - span: lower_span(attr.span), - comment: *symbol, - })) - } - // // FIXME: make doc attributes go through a proper attribute parser - // ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => { - // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); - // - // attributes.push(Attribute::Parsed(AttributeKind::DocComment { - // style: attr.style, - // kind: CommentKind::Line, - // span: attr.span, - // comment: p.args().name_value(), - // })) - // } - ast::AttrKind::Normal(n) => { - let parser = MetaItemParser::from_attr(n, self.dcx()); - let (path, args) = parser.deconstruct(); - let parts = path.segments().map(|i| i.name).collect::>(); - - if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { - for f in accepts { - let cx = AcceptContext { - group_cx: &group_cx, - attr_span: lower_span(attr.span), - }; - - f(&cx, &args) - } - } else { - // if we're here, we must be compiling a tool attribute... Or someone forgot to - // parse their fancy new attribute. Let's warn them in any case. If you are that - // person, and you really your attribute should remain unparsed, carefully read the - // documentation in this module and if you still think so you can add an exception - // to this assertion. - - // FIXME(jdonszelmann): convert other attributes, and check with this that - // we caught em all - // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; - // assert!( - // self.tools.contains(&parts[0]) || true, - // // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), - // "attribute {path} wasn't parsed and isn't a know tool attribute", - // ); - - attributes.push(Attribute::Unparsed(Box::new(AttrItem { - path: AttrPath::from_ast(&n.item.path), - args: self.lower_attr_args(&n.item.args, lower_span), - id: HashIgnoredAttrId { attr_id: attr.id }, - style: attr.style, - span: lower_span(attr.span), - }))); - } - } - } - } - - let mut parsed_attributes = Vec::new(); - for f in &ATTRIBUTE_MAPPING.1 { - if let Some(attr) = f(&group_cx) { - parsed_attributes.push(Attribute::Parsed(attr)); - } - } - - attributes.extend(parsed_attributes); - - attributes - } - - fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { - match args { - ast::AttrArgs::Empty => AttrArgs::Empty, - ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs { - dspan: args.dspan, - delim: args.delim, - tokens: args.tokens.flattened(), - }), - // This is an inert key-value attribute - it will never be visible to macros - // after it gets lowered to HIR. Therefore, we can extract literals to handle - // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - ast::AttrArgs::Eq { eq_span, expr } => { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = - ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span)) - { - lit - } else { - let guar = self.dcx().has_errors().unwrap(); - ast::MetaItemLit { - symbol: kw::Empty, - suffix: None, - kind: ast::LitKind::Err(guar), - span: DUMMY_SP, - } - }; - AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit } - } - } - } -} diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 9841166b37dbd..a1264a6875f69 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -1,79 +1,8 @@ -//! Centralized logic for parsing and attributes. +//! Functions and types dealing with attributes and meta items. //! -//! Part of a series of crates: -//! - rustc_attr_data_structures: contains types that the parsers parse into -//! - rustc_attr_parsing: this crate -//! - (in the future): rustc_attr_validation -//! -//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229). -//! There used to be only one definition of attributes in the compiler: `ast::Attribute`. -//! These were then parsed or validated or both in places distributed all over the compiler. -//! This was a mess... -//! -//! Attributes are markers on items. -//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax. -//! This could either be a user provided proc macro, or something compiler provided. -//! `derive` is an example of one that the compiler provides. -//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active". -//! I personally like calling these *active* compiler-provided attributes, built-in *macros*, -//! because they still expand, and this helps to differentiate them from built-in *attributes*. -//! However, I'll be the first to admit that the naming here can be confusing. -//! -//! The alternative to active attributes, are inert attributes. -//! These can occur in user code (proc-macro helper attributes). -//! But what's important is, many built-in attributes are inert like this. -//! There is nothing they expand to during the macro expansion process, -//! sometimes because they literally cannot expand to something that is valid Rust. -//! They are really just markers to guide the compilation process. -//! An example is `#[inline(...)]` which changes how code for functions is generated. -//! -//! ```text -//! Active Inert -//! ┌──────────────────────┬──────────────────────┐ -//! │ (mostly in) │ these are parsed │ -//! │ rustc_builtin_macros │ here! │ -//! │ │ │ -//! │ │ │ -//! │ #[derive(...)] │ #[stable()] │ -//! Built-in │ #[cfg()] │ #[inline()] │ -//! │ #[cfg_attr()] │ #[repr()] │ -//! │ │ │ -//! │ │ │ -//! │ │ │ -//! ├──────────────────────┼──────────────────────┤ -//! │ │ │ -//! │ │ │ -//! │ │ `b` in │ -//! │ │ #[proc_macro_derive( │ -//! User created │ #[proc_macro_attr()] │ a, │ -//! │ │ attributes(b) │ -//! │ │ ] │ -//! │ │ │ -//! │ │ │ -//! │ │ │ -//! └──────────────────────┴──────────────────────┘ -//! ``` -//! -//! In this crate, syntactical attributes (sequences of tokens that look like -//! `#[something(something else)]`) are parsed into more semantic attributes, markers on items. -//! Multiple syntactic attributes might influence a single semantic attribute. For example, -//! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define -//! a "stability" of an item. So, the stability attribute has an -//! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]` -//! and `#[unstable()]` syntactic attributes, and at the end produce a single [`AttributeKind::Stability`]. -//! -//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be -//! combined into a single semantic attribute. For example: -//! -//! ``` -//! #[repr(C)] -//! #[repr(packed)] -//! struct Meow {} -//! ``` -//! -//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this -//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single -//! syntactical annotation. +//! FIXME(Centril): For now being, much of the logic is still in `rustc_ast::attr`. +//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` +//! to this crate. // tidy-alphabetical-start #![allow(internal_features)] @@ -83,59 +12,11 @@ #![warn(unreachable_pub)] // tidy-alphabetical-end -#[macro_use] mod attributes; -mod context; -pub mod parser; mod session_diagnostics; -pub use attributes::cfg::*; -pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; -pub use context::{AttributeParser, OmitDoc}; +pub use attributes::*; pub use rustc_attr_data_structures::*; +pub use util::{find_crate_name, is_builtin_attr, parse_version}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - -/// Finds attributes in sequences of attributes by pattern matching. -/// -/// A little like `matches` but for attributes. -/// -/// ```rust,ignore (illustrative) -/// // finds the repr attribute -/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { -/// -/// } -/// -/// // checks if one has matched -/// if find_attr!(attrs, AttributeKind::Repr(_)) { -/// -/// } -/// ``` -/// -/// Often this requires you to first end up with a list of attributes. -/// A common way to get those is through `tcx.get_all_attrs(did)` -#[macro_export] -macro_rules! find_attr { - ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ - $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() - }}; - - ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator) {} - check_attribute_iterator(&$attributes_list); - - let find_attribute = |iter| { - for i in $attributes_list { - match i { - rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { - return Some($e); - } - _ => {} - } - } - - None - }; - find_attribute($attributes_list) - }}; -} diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs deleted file mode 100644 index 0ee0ea4ea5953..0000000000000 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ /dev/null @@ -1,624 +0,0 @@ -//! This is in essence an (improved) duplicate of `rustc_ast/attr/mod.rs`. -//! That module is intended to be deleted in its entirety. -//! -//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` - -use std::fmt::{Debug, Display}; -use std::iter::Peekable; - -use rustc_ast::token::{self, Delimiter, Token}; -use rustc_ast::tokenstream::{TokenStreamIter, TokenTree}; -use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; -use rustc_ast_pretty::pprust; -use rustc_errors::DiagCtxtHandle; -use rustc_hir::{self as hir, AttrPath}; -use rustc_span::symbol::{Ident, kw}; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol}; - -pub struct SegmentIterator<'a> { - offset: usize, - path: &'a PathParser<'a>, -} - -impl<'a> Iterator for SegmentIterator<'a> { - type Item = &'a Ident; - - fn next(&mut self) -> Option { - if self.offset >= self.path.len() { - return None; - } - - let res = match self.path { - PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident, - PathParser::Attr(attr_path) => &attr_path.segments[self.offset], - }; - - self.offset += 1; - Some(res) - } -} - -#[derive(Clone, Debug)] -pub enum PathParser<'a> { - Ast(&'a Path), - Attr(AttrPath), -} - -impl<'a> PathParser<'a> { - pub fn get_attribute_path(&self) -> hir::AttrPath { - AttrPath { - segments: self.segments().copied().collect::>().into_boxed_slice(), - span: self.span(), - } - } - - pub fn segments(&'a self) -> impl Iterator { - SegmentIterator { offset: 0, path: self } - } - - pub fn span(&self) -> Span { - match self { - PathParser::Ast(path) => path.span, - PathParser::Attr(attr_path) => attr_path.span, - } - } - - pub fn len(&self) -> usize { - match self { - PathParser::Ast(path) => path.segments.len(), - PathParser::Attr(attr_path) => attr_path.segments.len(), - } - } - - pub fn segments_is(&self, segments: &[Symbol]) -> bool { - self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) - } - - pub fn word(&self) -> Option { - (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap()) - } - - pub fn word_or_empty(&self) -> Ident { - self.word().unwrap_or_else(Ident::empty) - } - - /// Asserts that this MetaItem is some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. - pub fn word_is(&self, sym: Symbol) -> bool { - self.word().map(|i| i.name == sym).unwrap_or(false) - } -} - -impl Display for PathParser<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)), - PathParser::Attr(attr_path) => write!(f, "{attr_path}"), - } - } -} - -#[derive(Clone, Debug)] -#[must_use] -pub enum ArgParser<'a> { - NoArgs, - List(MetaItemListParser<'a>), - NameValue(NameValueParser), -} - -impl<'a> ArgParser<'a> { - pub fn span(&self) -> Option { - match self { - Self::NoArgs => None, - Self::List(l) => Some(l.span), - Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())), - } - } - - pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self { - match value { - AttrArgs::Empty => Self::NoArgs, - AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { - Self::List(MetaItemListParser::new(args, dcx)) - } - AttrArgs::Delimited(args) => { - Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() }) - } - AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { - eq_span: *eq_span, - value: expr_to_lit(dcx, &expr), - value_span: expr.span, - }), - } - } - - /// Asserts that this MetaItem is a list - /// - /// Some examples: - /// - /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list - /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list - pub fn list(&self) -> Option<&MetaItemListParser<'a>> { - match self { - Self::List(l) => Some(l), - Self::NameValue(_) | Self::NoArgs => None, - } - } - - /// Asserts that this MetaItem is a name-value pair. - /// - /// Some examples: - /// - /// - `#[clippy::cyclomatic_complexity = "100"]`: `clippy::cyclomatic_complexity = "100"` is a name value pair, - /// where the name is a path (`clippy::cyclomatic_complexity`). You already checked the path - /// to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is - /// there - /// - `#[doc = "hello"]`: `doc = "hello` is also a name value pair - pub fn name_value(&self) -> Option<&NameValueParser> { - match self { - Self::NameValue(n) => Some(n), - Self::List(_) | Self::NoArgs => None, - } - } - - /// Asserts that there are no arguments - pub fn no_args(&self) -> bool { - matches!(self, Self::NoArgs) - } -} - -/// Inside lists, values could be either literals, or more deeply nested meta items. -/// This enum represents that. -/// -/// Choose which one you want using the provided methods. -#[derive(Debug, Clone)] -pub enum MetaItemOrLitParser<'a> { - MetaItemParser(MetaItemParser<'a>), - Lit(MetaItemLit), - Err(Span, ErrorGuaranteed), -} - -impl<'a> MetaItemOrLitParser<'a> { - pub fn span(&self) -> Span { - match self { - MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => { - generic_meta_item_parser.span() - } - MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span, - MetaItemOrLitParser::Err(span, _) => *span, - } - } - - pub fn lit(&self) -> Option<&MetaItemLit> { - match self { - MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit), - _ => None, - } - } - - pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> { - match self { - MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), - _ => None, - } - } -} - -/// Utility that deconstructs a MetaItem into usable parts. -/// -/// MetaItems are syntactically extremely flexible, but specific attributes want to parse -/// them in custom, more restricted ways. This can be done using this struct. -/// -/// MetaItems consist of some path, and some args. The args could be empty. In other words: -/// -/// - `name` -> args are empty -/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses -/// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the -/// `= value` part -/// -/// The syntax of MetaItems can be found at -#[derive(Clone)] -pub struct MetaItemParser<'a> { - path: PathParser<'a>, - args: ArgParser<'a>, -} - -impl<'a> Debug for MetaItemParser<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("MetaItemParser") - .field("path", &self.path) - .field("args", &self.args) - .finish() - } -} - -impl<'a> MetaItemParser<'a> { - /// Create a new parser from a [`NormalAttr`], which is stored inside of any - /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self { - Self { - path: PathParser::Ast(&attr.item.path), - args: ArgParser::from_attr_args(&attr.item.args, dcx), - } - } -} - -impl<'a> MetaItemParser<'a> { - pub fn span(&self) -> Span { - if let Some(other) = self.args.span() { - self.path.span().with_hi(other.hi()) - } else { - self.path.span() - } - } - - /// Gets just the path, without the args. - pub fn path_without_args(&self) -> PathParser<'a> { - self.path.clone() - } - - /// Gets just the args parser, without caring about the path. - pub fn args(&self) -> &ArgParser<'a> { - &self.args - } - - pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { - (self.path_without_args(), self.args()) - } - - /// Asserts that this MetaItem starts with a path. Some examples: - /// - /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path - /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path - /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { - self.deconstruct() - } - - /// Asserts that this MetaItem starts with a word, or single segment path. - /// Doesn't return the args parser. - /// - /// For examples. see [`Self::word`] - pub fn word_without_args(&self) -> Option { - Some(self.word()?.0) - } - - /// Like [`word`](Self::word), but returns an empty symbol instead of None - pub fn word_or_empty_without_args(&self) -> Ident { - self.word_or_empty().0 - } - - /// Asserts that this MetaItem starts with a word, or single segment path. - /// - /// Some examples: - /// - `#[inline]`: `inline` is a word - /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, - /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { - let (path, args) = self.deconstruct(); - Some((path.word()?, args)) - } - - /// Like [`word`](Self::word), but returns an empty symbol instead of None - pub fn word_or_empty(&self) -> (Ident, &ArgParser<'a>) { - let (path, args) = self.deconstruct(); - (path.word().unwrap_or(Ident::empty()), args) - } - - /// Asserts that this MetaItem starts with some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. - pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { - self.path_without_args().word_is(sym).then(|| self.args()) - } - - /// Asserts that this MetaItem starts with some specific path. - /// - /// See [`word`](Self::path) for examples of what a word is. - pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { - self.path_without_args().segments_is(segments).then(|| self.args()) - } -} - -#[derive(Clone)] -pub struct NameValueParser { - pub eq_span: Span, - value: MetaItemLit, - pub value_span: Span, -} - -impl Debug for NameValueParser { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NameValueParser") - .field("eq_span", &self.eq_span) - .field("value", &self.value) - .field("value_span", &self.value_span) - .finish() - } -} - -impl NameValueParser { - pub fn value_as_lit(&self) -> &MetaItemLit { - &self.value - } - - pub fn value_as_str(&self) -> Option { - self.value_as_lit().kind.str() - } -} - -fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr) -> MetaItemLit { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) - { - lit - } else { - let guar = dcx.has_errors().unwrap(); - MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span: DUMMY_SP } - } -} - -struct MetaItemListParserContext<'a> { - // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside - inside_delimiters: Peekable>, - dcx: DiagCtxtHandle<'a>, -} - -impl<'a> MetaItemListParserContext<'a> { - fn done(&mut self) -> bool { - self.inside_delimiters.peek().is_none() - } - - fn next_path(&mut self) -> Option { - // FIXME: Share code with `parse_path`. - let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt)); - - match tt.as_deref()? { - &TokenTree::Token( - Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, - _, - ) => { - // here we have either an ident or pathsep `::`. - - let mut segments = if let &token::Ident(name, _) = kind { - // when we lookahead another pathsep, more path's coming - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - vec![Ident::new(name, span)] - } else { - // else we have a single identifier path, that's all - return Some(AttrPath { - segments: vec![Ident::new(name, span)].into_boxed_slice(), - span, - }); - } - } else { - // if `::` is all we get, we just got a path root - vec![Ident::new(kw::PathRoot, span)] - }; - - // one segment accepted. accept n more - loop { - // another ident? - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = - self.inside_delimiters - .next() - .map(|tt| TokenTree::uninterpolate(tt)) - .as_deref() - { - segments.push(Ident::new(name, span)); - } else { - return None; - } - // stop unless we see another `::` - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - } else { - break; - } - } - let span = span.with_hi(segments.last().unwrap().span.hi()); - Some(AttrPath { segments: segments.into_boxed_slice(), span }) - } - TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => { - None - } - _ => { - // malformed attributes can get here. We can't crash, but somewhere else should've - // already warned for this. - None - } - } - } - - fn value(&mut self) -> Option { - match self.inside_delimiters.next() { - Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { - MetaItemListParserContext { - inside_delimiters: inner_tokens.iter().peekable(), - dcx: self.dcx, - } - .value() - } - Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token), - _ => None, - } - } - - /// parses one element on the inside of a list attribute like `#[my_attr( )]` - /// - /// parses a path followed be either: - /// 1. nothing (a word attr) - /// 2. a parenthesized list - /// 3. an equals sign and a literal (name-value) - /// - /// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]` - /// where no path is given before the literal - /// - /// Some exceptions too for interpolated attributes which are already pre-processed - fn next(&mut self) -> Option> { - // a list element is either a literal - if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek() - && let Some(lit) = MetaItemLit::from_token(token) - { - self.inside_delimiters.next(); - return Some(MetaItemOrLitParser::Lit(lit)); - } - - // or a path. - let path = - if let Some(TokenTree::Token(Token { kind: token::Interpolated(nt), span, .. }, _)) = - self.inside_delimiters.peek() - { - match &**nt { - // or maybe a full nt meta including the path but we return immediately - token::Nonterminal::NtMeta(item) => { - self.inside_delimiters.next(); - - return Some(MetaItemOrLitParser::MetaItemParser(MetaItemParser { - path: PathParser::Ast(&item.path), - args: ArgParser::from_attr_args(&item.args, self.dcx), - })); - } - // an already interpolated path from a macro expansion is a path, no need to parse - // one from tokens - token::Nonterminal::NtPath(path) => { - self.inside_delimiters.next(); - - AttrPath::from_ast(path) - } - _ => { - self.inside_delimiters.next(); - // we go into this path if an expr ended up in an attribute that - // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]` - // where the macro didn't expand to a literal. An error is already given - // for this at this point, and then we do continue. This makes this path - // reachable... - let e = self.dcx.span_delayed_bug( - *span, - "expr in place where literal is expected (builtin attr parsing)", - ); - - return Some(MetaItemOrLitParser::Err(*span, e)); - } - } - } else { - self.next_path()? - }; - - // Paths can be followed by: - // - `(more meta items)` (another list) - // - `= lit` (a name-value) - // - nothing - Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() { - Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => { - self.inside_delimiters.next(); - - MetaItemParser { - path: PathParser::Attr(path), - args: ArgParser::List(MetaItemListParser::new_tts( - inner_tokens.iter(), - dspan.entire(), - self.dcx, - )), - } - } - Some(TokenTree::Delimited(_, ..)) => { - self.inside_delimiters.next(); - // self.dcx.span_delayed_bug(span.entire(), "wrong delimiters"); - return None; - } - Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => { - self.inside_delimiters.next(); - let value = self.value()?; - MetaItemParser { - path: PathParser::Attr(path), - args: ArgParser::NameValue(NameValueParser { - eq_span: *span, - value_span: value.span, - value, - }), - } - } - _ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs }, - })) - } - - fn parse(mut self, span: Span) -> MetaItemListParser<'a> { - let mut sub_parsers = Vec::new(); - - while !self.done() { - let Some(n) = self.next() else { - continue; - }; - sub_parsers.push(n); - - match self.inside_delimiters.peek() { - None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => { - self.inside_delimiters.next(); - } - Some(_) => {} - } - } - - MetaItemListParser { sub_parsers, span } - } -} - -#[derive(Debug, Clone)] -pub struct MetaItemListParser<'a> { - sub_parsers: Vec>, - pub span: Span, -} - -impl<'a> MetaItemListParser<'a> { - fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> { - MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) - } - - fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self { - MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) - } - - /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed<'s>(&'s self) -> impl Iterator> + 's { - self.sub_parsers.iter() - } - - pub fn len(&self) -> usize { - self.sub_parsers.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Asserts that every item in the list is another list starting with a word. - /// - /// See [`MetaItemParser::word`] for examples of words. - pub fn all_word_list<'s>(&'s self) -> Option)>> { - self.mixed().map(|i| i.meta_item()?.word()).collect() - } - - /// Asserts that every item in the list is another list starting with a full path. - /// - /// See [`MetaItemParser::path`] for examples of paths. - pub fn all_path_list<'s>(&'s self) -> Option, &'s ArgParser<'a>)>> { - self.mixed().map(|i| Some(i.meta_item()?.path())).collect() - } - - /// Returns Some if the list contains only a single element. - /// - /// Inside the Some is the parser to parse this single element. - pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> { - let mut iter = self.mixed(); - iter.next().filter(|_| iter.next().is_none()) - } -} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 9d34b807ac2fe..92bc2a8aeb05e 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -6,16 +6,9 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuar use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; +use crate::attributes::util::UnsupportedLiteralReason; use crate::fluent_generated as fluent; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, - DeprecatedString, - DeprecatedKvPair, -} - #[derive(Diagnostic)] #[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] pub(crate) struct ExpectedOneCfgPattern { @@ -46,21 +39,6 @@ pub(crate) struct MultipleItem { pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, - - #[subdiagnostic] - pub suggestion: Option, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - attr_parsing_incorrect_meta_item_suggestion, - applicability = "maybe-incorrect" -)] -pub(crate) struct IncorrectMetaItemSuggestion { - #[suggestion_part(code = "\"")] - pub lo: Span, - #[suggestion_part(code = "\"")] - pub hi: Span, } /// Error code: E0541 @@ -359,6 +337,13 @@ pub(crate) struct RustcPromotablePairing { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_parsing_rustc_const_stable_indirect_pairing)] +pub(crate) struct RustcConstStableIndirectPairing { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { @@ -438,44 +423,3 @@ pub(crate) struct UnknownVersionLiteral { #[primary_span] pub span: Span, } - -// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated. -#[derive(Diagnostic)] -#[diag(attr_parsing_unused_multiple)] -pub(crate) struct UnusedMultiple { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable")] - pub this: Span, - #[note] - pub other: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_stability_outside_std, code = E0734)] -pub(crate) struct StabilityOutsideStd { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_empty_confusables)] -pub(crate) struct EmptyConfusables { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_repr_ident, code = E0565)] -pub(crate) struct ReprIdent { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)] -#[help] -pub(crate) struct UnrecognizedReprHint { - #[primary_span] - pub span: Span, -} diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index b5f4f2efd1f5b..f29be2ee81855 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -20,7 +20,6 @@ rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6b59ac2582755..234ec8582165b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -185,9 +185,8 @@ use rustc_ast::{ self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, VariantData, }; -use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked}; +use rustc_attr_parsing as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_hir::Attribute; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -481,10 +480,14 @@ impl<'a> TraitDef<'a> { ) { match item { Annotatable::Item(item) => { - let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) - ); + let is_packed = item.attrs.iter().any(|attr| { + for r in attr::find_repr_attrs(cx.sess, attr) { + if let attr::ReprPacked(_) = r { + return true; + } + } + false + }); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index da9f8d6929720..27331ce4ca66f 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -94,7 +94,7 @@ impl<'tcx> AssertModuleSource<'tcx> { other => { self.tcx .dcx() - .emit_fatal(errors::UnknownReuseKind { span: attr.span(), kind: other }); + .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other }); } } } else { @@ -102,7 +102,7 @@ impl<'tcx> AssertModuleSource<'tcx> { }; if !self.tcx.sess.opts.unstable_opts.query_dep_graph { - self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span() }); + self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span }); } if !self.check_config(attr) { @@ -115,7 +115,7 @@ impl<'tcx> AssertModuleSource<'tcx> { if !user_path.starts_with(&crate_name) { self.tcx.dcx().emit_fatal(errors::MalformedCguName { - span: attr.span(), + span: attr.span, user_path, crate_name, }); @@ -145,7 +145,7 @@ impl<'tcx> AssertModuleSource<'tcx> { let cgu_names: Vec<&str> = self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord(); self.tcx.dcx().emit_err(errors::NoModuleNamed { - span: attr.span(), + span: attr.span, user_path, cgu_name, cgu_names: cgu_names.join(", "), @@ -155,7 +155,7 @@ impl<'tcx> AssertModuleSource<'tcx> { self.cgu_reuse_tracker.set_expectation( cgu_name, user_path, - attr.span(), + attr.span, expected_reuse, comp_kind, ); @@ -175,7 +175,7 @@ impl<'tcx> AssertModuleSource<'tcx> { } } - self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span(), name }); + self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span, name }); } /// Scan for a `cfg="foo"` attribute and check whether we have a diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 73a97d32c2d64..40238f4b4915a 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -5,9 +5,7 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; -use rustc_ast as ast; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; -use rustc_attr_parsing::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_map; @@ -31,6 +29,7 @@ use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; +use {rustc_ast as ast, rustc_attr_parsing as attr}; use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; @@ -1062,7 +1061,7 @@ pub(crate) fn provide(providers: &mut Providers) { let any_for_speed = defids.items().any(|id| { let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); - matches!(optimize, OptimizeAttr::Speed) + matches!(optimize, attr::OptimizeAttr::Speed) }); if any_for_speed { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 673740b4aab9f..97bc84c0b698b 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -5,8 +5,7 @@ use rustc_ast::expand::autodiff_attrs::{ AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, }; use rustc_ast::{MetaItem, MetaItemInner, attr}; -use rustc_attr_parsing::ReprAttr::ReprAlign; -use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; @@ -105,26 +104,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { - tcx.dcx().span_delayed_bug( - attr.span(), - "this attribute can only be applied to functions", - ); + tcx.dcx() + .span_delayed_bug(attr.span, "this attribute can only be applied to functions"); None } }; - if let hir::Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - codegen_fn_attrs.alignment = reprs - .iter() - .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }); - } - - _ => {} - } - } - let Some(Ident { name, .. }) = attr.ident() else { continue; }; @@ -145,14 +130,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; mixed_export_name_no_mangle_lint_state.track_no_mangle( - attr.span(), + attr.span, tcx.local_def_id_to_hir_id(did), attr, ); } else { tcx.dcx() .struct_span_err( - attr.span(), + attr.span, format!( "`#[no_mangle]` cannot be used on {} {} as it has no name", tcx.def_descr_article(did.to_def_id()), @@ -173,7 +158,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { feature_err( &tcx.sess, sym::used_with_arg, - attr.span(), + attr.span, "`#[used(linker)]` is currently unstable", ) .emit(); @@ -185,7 +170,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { feature_err( &tcx.sess, sym::used_with_arg, - attr.span(), + attr.span, "`#[used(compiler)]` is currently unstable", ) .emit(); @@ -193,7 +178,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } Some(_) => { - tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); + tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span }); } None => { // Unfortunately, unconditionally using `llvm.used` causes @@ -238,7 +223,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { { struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0737, "`#[track_caller]` requires Rust ABI" ) @@ -246,12 +231,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if is_closure && !tcx.features().closure_track_caller() - && !attr.span().allows_unstable(sym::closure_track_caller) + && !attr.span.allows_unstable(sym::closure_track_caller) { feature_err( &tcx.sess, sym::closure_track_caller, - attr.span(), + attr.span, "`#[track_caller]` on closures is currently unstable", ) .emit(); @@ -265,19 +250,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // so it may not contain any null characters. struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0648, "`export_name` may not contain null characters" ) .emit(); } codegen_fn_attrs.export_name = Some(s); - mixed_export_name_no_mangle_lint_state.track_export_name(attr.span()); + mixed_export_name_no_mangle_lint_state.track_export_name(attr.span); } } sym::target_feature => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { - tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn"); + tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn"); continue; }; let safe_target_features = @@ -307,7 +292,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // `main`, `start`, and other functions that are not usually // allowed. } else { - check_target_feature_trait_unsafe(tcx, did, attr.span()); + check_target_feature_trait_unsafe(tcx, did, attr.span); } } from_target_feature_attr( @@ -325,7 +310,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if tcx.is_mutable_static(did.into()) { let mut diag = tcx.dcx().struct_span_err( - attr.span(), + attr.span, "extern mutable statics are not allowed with `#[linkage]`", ); diag.note( @@ -344,7 +329,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Some(val) = attr.value_str() { if val.as_str().bytes().any(|b| b == 0) { let msg = format!("illegal null byte in link_section value: `{val}`"); - tcx.dcx().span_err(attr.span(), msg); + tcx.dcx().span_err(attr.span, msg); } else { codegen_fn_attrs.link_section = Some(val); } @@ -352,13 +337,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { - link_ordinal_span = Some(attr.span()); + link_ordinal_span = Some(attr.span); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { codegen_fn_attrs.link_ordinal = ordinal; } } sym::no_sanitize => { - no_sanitize_span = Some(attr.span()); + no_sanitize_span = Some(attr.span); if let Some(list) = attr.meta_item_list() { for item in list.iter() { match item.name_or_empty() { @@ -396,7 +381,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { { struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0779, "target does not support `#[instruction_set]`" ) @@ -408,7 +393,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { _ => { struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0779, "invalid instruction set specified", ) @@ -420,7 +405,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { [] => { struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0778, "`#[instruction_set]` requires an argument" ) @@ -430,7 +415,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { _ => { struct_span_code_err!( tcx.dcx(), - attr.span(), + attr.span, E0779, "cannot specify more than one instruction set" ) @@ -439,6 +424,27 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }) } + sym::repr => { + codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() + && let [item] = items.as_slice() + && let Some((sym::align, literal)) = item.singleton_lit_list() + { + rustc_attr_parsing::parse_alignment(&literal.kind) + .inspect_err(|msg| { + struct_span_code_err!( + tcx.dcx(), + literal.span, + E0589, + "invalid `repr(align)` attribute: {}", + msg + ) + .emit(); + }) + .ok() + } else { + None + }; + } sym::patchable_function_entry => { codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { let mut prefix = None; @@ -504,7 +510,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if let (None, None) = (prefix, entry) { - tcx.dcx().span_err(attr.span(), "must specify at least one parameter"); + tcx.dcx().span_err(attr.span, "must specify at least one parameter"); } Some(PatchableFunctionEntry::from_prefix_and_entry( @@ -530,19 +536,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let Some(ref items) = attr.meta_item_list() else { return ia; }; - inline_span = Some(attr.span()); + inline_span = Some(attr.span); let [item] = &items[..] else { - struct_span_code_err!(tcx.dcx(), attr.span(), E0534, "expected one argument").emit(); + struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); return InlineAttr::None; }; - if item.has_name(sym::always) { InlineAttr::Always } else if item.has_name(sym::never) { InlineAttr::Never } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") + struct_span_code_err!(tcx.dcx(), item.span(), E0535, "invalid argument") .with_help("valid inline arguments are `always` and `never`") .emit(); @@ -555,9 +560,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if attr.is_word() { - InlineAttr::Force { attr_span: attr.span(), reason: None } + InlineAttr::Force { attr_span: attr.span, reason: None } } else if let Some(val) = attr.value_str() { - InlineAttr::Force { attr_span: attr.span(), reason: Some(val) } + InlineAttr::Force { attr_span: attr.span, reason: Some(val) } } else { debug!("`rustc_force_inline` not checked by attribute validation"); ia @@ -577,16 +582,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); if attr.is_word() { - err(attr.span(), "expected one argument"); + err(attr.span, "expected one argument"); return ia; } let Some(ref items) = attr.meta_item_list() else { return OptimizeAttr::Default; }; - inline_span = Some(attr.span()); + inline_span = Some(attr.span); let [item] = &items[..] else { - err(attr.span(), "expected one argument"); + err(attr.span, "expected one argument"); return OptimizeAttr::Default; }; if item.has_name(sym::size) { @@ -698,7 +703,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let span = tcx .get_attrs(did, sym::target_feature) .next() - .map_or_else(|| tcx.def_span(did), |a| a.span()); + .map_or_else(|| tcx.def_span(did), |a| a.span); tcx.dcx() .create_err(errors::TargetFeatureDisableOrEnable { features, @@ -747,7 +752,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { use rustc_ast::{LitIntType, LitKind, MetaItemLit}; let meta_item_list = attr.meta_item_list()?; let [sole_meta_list] = &meta_item_list[..] else { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() }); + tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span }); return None; }; if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = @@ -771,13 +776,13 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { } else { let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`"); tcx.dcx() - .struct_span_err(attr.span(), msg) + .struct_span_err(attr.span, msg) .with_note("the value may not exceed `u16::MAX`") .emit(); None } } else { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span() }); + tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span }); None } } @@ -823,7 +828,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { export_name: Some(export_name), no_mangle: Some(no_mangle), hir_id: Some(hir_id), - no_mangle_attr: Some(_), + no_mangle_attr: Some(no_mangle_attr), } = self { tcx.emit_node_span_lint( @@ -832,7 +837,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { no_mangle, errors::MixedExportNameAndNoMangle { no_mangle, - no_mangle_attr: "#[unsafe(no_mangle)]".to_string(), + no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr), export_name, removal_span: no_mangle, }, @@ -864,7 +869,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { _ => { //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute //branch above. - span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source"); + span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source"); } }; @@ -876,12 +881,12 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { } let [mode, input_activities @ .., ret_activity] = &list[..] else { - span_bug!(attr.span(), "rustc_autodiff attribute must contain mode and activities"); + span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities"); }; let mode = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = mode { p1.segments.first().unwrap().ident } else { - span_bug!(attr.span(), "rustc_autodiff attribute must contain mode"); + span_bug!(attr.span, "rustc_autodiff attribute must contain mode"); }; // parse mode @@ -897,7 +902,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity { p1.segments.first().unwrap().ident } else { - span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity"); + span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity"); }; // Then parse it into an actual DiffActivity @@ -932,11 +937,11 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { for &input in &arg_activities { if !valid_input_activity(mode, input) { - span_bug!(attr.span(), "Invalid input activity {} for {} mode", input, mode); + span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode); } } if !valid_ret_activity(mode, ret_activity) { - span_bug!(attr.span(), "Invalid return activity {} for {} mode", ret_activity, mode); + span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode); } Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 659d4a304563e..52e000858b4c7 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -4,13 +4,12 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. -use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_errors::DiagCtxtHandle; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; +use {rustc_attr_parsing as attr, rustc_hir as hir}; pub use self::qualifs::Qualif; @@ -82,8 +81,7 @@ pub fn rustc_allow_const_fn_unstable( feature_gate: Symbol, ) -> bool { let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); - - find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate)) + attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) } /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index b11793c190a14..c1d8cd9bb9ed2 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -10,7 +10,6 @@ derive_setters = "0.1.6" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index db6532f41eab2..7f383946c1463 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -8,7 +8,6 @@ use std::process::ExitStatus; use rustc_abi::TargetDataLayoutErrors; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::RustcVersion; use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; @@ -97,12 +96,6 @@ into_diag_arg_using_display!( rustc_abi::ExternAbi, ); -impl IntoDiagArg for RustcVersion { - fn into_diag_arg(self) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string())) - } -} - impl IntoDiagArg for rustc_type_ir::TraitRef { fn into_diag_arg(self) -> DiagArgValue { self.to_string().into_diag_arg() diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 0ba139ea5cc57..33bada106ca79 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -17,7 +17,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 4a250145308cf..819694d1cdc1f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -11,12 +11,11 @@ use rustc_ast::token::Nonterminal; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_parsing::{AttributeKind, Deprecation, Stability, find_attr}; +use rustc_attr_parsing::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; -use rustc_hir as hir; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::Parser; @@ -839,23 +838,19 @@ impl SyntaxExtension { /// and other properties converted from attributes. pub fn new( sess: &Session, + features: &Features, kind: SyntaxExtensionKind, span: Span, helper_attrs: Vec, edition: Edition, name: Symbol, - attrs: &[hir::Attribute], + attrs: &[impl AttributeExt], is_local: bool, ) -> SyntaxExtension { let allow_internal_unstable = - find_attr!(attrs, AttributeKind::AllowInternalUnstable(i) => i) - .map(|i| i.as_slice()) - .unwrap_or_default(); - // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style - // let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe); - let allow_internal_unsafe = - ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some(); + rustc_attr_parsing::allow_internal_unstable(sess, attrs).collect::>(); + let allow_internal_unsafe = ast::attr::contains_name(attrs, sym::allow_internal_unsafe); let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros)); @@ -872,17 +867,16 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - - let stability = find_attr!(attrs, AttributeKind::Stability{stability, ..} => *stability); - - // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem - if let Some(sp) = find_attr!(attrs, AttributeKind::ConstStability{span, ..} => *span) { + let stability = attr::find_stability(sess, attrs, span); + let const_stability = attr::find_const_stability(sess, attrs, span); + let body_stability = attr::find_body_stability(sess, attrs); + if let Some((_, sp)) = const_stability { sess.dcx().emit_err(errors::MacroConstStability { span: sp, head_span: sess.source_map().guess_head_span(span), }); } - if let Some(sp) = find_attr!(attrs, AttributeKind::BodyStability{span, ..} => *span) { + if let Some((_, sp)) = body_stability { sess.dcx().emit_err(errors::MacroBodyStability { span: sp, head_span: sess.source_map().guess_head_span(span), @@ -893,10 +887,9 @@ impl SyntaxExtension { kind, span, allow_internal_unstable: (!allow_internal_unstable.is_empty()) - // FIXME(jdonszelmann): avoid the into_iter/collect? - .then(|| allow_internal_unstable.iter().map(|i| i.0).collect::>().into()), - stability, - deprecation: find_attr!(attrs, AttributeKind::Deprecation{deprecation, ..} => *deprecation), + .then(|| allow_internal_unstable.into()), + stability: stability.map(|(s, _)| s), + deprecation: attr::find_deprecation(sess, features, attrs).map(|(d, _)| d), helper_attrs, edition, builtin_name, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index cc7e3e651050a..b02a9b93c8af0 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -3,17 +3,17 @@ use std::collections::hash_map::Entry; use std::{mem, slice}; use ast::token::IdentIsRaw; +use rustc_ast::attr::AttributeExt; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_parsing::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, ErrorGuaranteed}; use rustc_feature::Features; -use rustc_hir as hir; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -371,7 +371,7 @@ pub fn compile_declarative_macro( features: &Features, macro_def: &ast::MacroDef, ident: Ident, - attrs: &[hir::Attribute], + attrs: &[impl AttributeExt], span: Span, node_id: NodeId, edition: Edition, @@ -379,6 +379,7 @@ pub fn compile_declarative_macro( let mk_syn_ext = |expander| { SyntaxExtension::new( sess, + features, SyntaxExtensionKind::LegacyBang(expander), span, Vec::new(), @@ -390,6 +391,7 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); + let dcx = sess.dcx(); let lhs_nm = Ident::new(sym::lhs, span); let rhs_nm = Ident::new(sym::rhs, span); let tt_spec = Some(NonterminalKind::TT); @@ -540,8 +542,16 @@ pub fn compile_declarative_macro( check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) - .unwrap_or(Transparency::fallback(macro_rules)); + let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules); + match transparency_error { + Some(TransparencyError::UnknownTransparency(value, span)) => { + dcx.span_err(span, format!("unknown macro transparency: `{value}`")); + } + Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => { + dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes"); + } + None => {} + } if let Some(guar) = guar { // To avoid warning noise, only consider the rules of this diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 7ca8539845a04..98300fc40fbeb 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -9,7 +9,6 @@ odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f0eaec55dbdd3..61f64e62058fc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,20 +1,18 @@ -// ignore-tidy-filelength use std::fmt; use rustc_abi::ExternAbi; +// ignore-tidy-filelength use rustc_ast::attr::AttributeExt; use rustc_ast::token::CommentKind; use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::{ - self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, - LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, + self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, + IntTy, Label, LitIntType, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ - AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, - ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability, - Mutability, UnOp, + BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind, }; -use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::tagged_ptr::TaggedRef; @@ -1011,248 +1009,174 @@ pub enum AttrArgs { }, } +#[derive(Clone, Debug, Encodable, Decodable)] +pub enum AttrKind { + /// A normal attribute. + Normal(Box), + + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). + /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` + /// variant (which is much less compact and thus more expensive). + DocComment(CommentKind, Symbol), +} + #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrPath { pub segments: Box<[Ident]>, pub span: Span, } -impl AttrPath { - pub fn from_ast(path: &ast::Path) -> Self { - AttrPath { - segments: path.segments.iter().map(|i| i.ident).collect::>().into_boxed_slice(), - span: path.span, - } - } -} - -impl fmt::Display for AttrPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::>().join("::")) - } -} - #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrItem { + pub unsafety: Safety, // Not lowered to hir::Path because we have no NodeId to resolve to. pub path: AttrPath, pub args: AttrArgs, - pub id: HashIgnoredAttrId, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct Attribute { + pub kind: AttrKind, + pub id: AttrId, /// Denotes if the attribute decorates the following construct (outer) /// or the construct this attribute is contained within (inner). pub style: AttrStyle, - /// Span of the entire attribute pub span: Span, } -/// The derived implementation of [`HashStable_Generic`] on [`Attribute`]s shouldn't hash -/// [`AttrId`]s. By wrapping them in this, we make sure we never do. -#[derive(Copy, Debug, Encodable, Decodable, Clone)] -pub struct HashIgnoredAttrId { - pub attr_id: AttrId, -} - -#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] -pub enum Attribute { - /// A parsed built-in attribute. - /// - /// Each attribute has a span connected to it. However, you must be somewhat careful using it. - /// That's because sometimes we merge multiple attributes together, like when an item has - /// multiple `repr` attributes. In this case the span might not be very useful. - Parsed(AttributeKind), - - /// An attribute that could not be parsed, out of a token-like representation. - /// This is the case for custom tool attributes. - Unparsed(Box), -} - impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { - match &self { - Attribute::Unparsed(normal) => &normal, - _ => panic!("unexpected parsed attribute"), + match &self.kind { + AttrKind::Normal(normal) => &normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } pub fn unwrap_normal_item(self) -> AttrItem { - match self { - Attribute::Unparsed(normal) => *normal, - _ => panic!("unexpected parsed attribute"), + match self.kind { + AttrKind::Normal(normal) => *normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } pub fn value_lit(&self) -> Option<&MetaItemLit> { - match &self { - Attribute::Unparsed(n) => match n.as_ref() { - AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr), - _ => None, - }, + match &self.kind { + AttrKind::Normal(box AttrItem { args: AttrArgs::Eq { expr, .. }, .. }) => Some(expr), _ => None, } } } impl AttributeExt for Attribute { - #[inline] fn id(&self) -> AttrId { - match &self { - Attribute::Unparsed(u) => u.id.attr_id, - _ => panic!(), - } + self.id } - #[inline] fn meta_item_list(&self) -> Option> { - match &self { - Attribute::Unparsed(n) => match n.as_ref() { - AttrItem { args: AttrArgs::Delimited(d), .. } => { - ast::MetaItemKind::list_from_tokens(d.tokens.clone()) - } - _ => None, - }, + match &self.kind { + AttrKind::Normal(box AttrItem { args: AttrArgs::Delimited(d), .. }) => { + ast::MetaItemKind::list_from_tokens(d.tokens.clone()) + } _ => None, } } - #[inline] fn value_str(&self) -> Option { self.value_lit().and_then(|x| x.value_str()) } - #[inline] fn value_span(&self) -> Option { self.value_lit().map(|i| i.span) } /// For a single-segment attribute, returns its name; otherwise, returns `None`. - #[inline] fn ident(&self) -> Option { - match &self { - Attribute::Unparsed(n) => { - if let [ident] = n.path.segments.as_ref() { - Some(*ident) - } else { - None - } - } + match &self.kind { + AttrKind::Normal(box AttrItem { + path: AttrPath { segments: box [ident], .. }, .. + }) => Some(*ident), _ => None, } } - #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { - match &self { - Attribute::Unparsed(n) => { - n.path.segments.len() == name.len() - && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) - } - _ => false, + match &self.kind { + AttrKind::Normal(n) => n.path.segments.iter().map(|segment| &segment.name).eq(name), + AttrKind::DocComment(..) => false, } } - #[inline] fn is_doc_comment(&self) -> bool { - matches!(self, Attribute::Parsed(AttributeKind::DocComment { .. })) + matches!(self.kind, AttrKind::DocComment(..)) } - #[inline] fn span(&self) -> Span { - match &self { - Attribute::Unparsed(u) => u.span, - // FIXME: should not be needed anymore when all attrs are parsed - Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, - Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, - a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), - } + self.span } - #[inline] fn is_word(&self) -> bool { - match &self { - Attribute::Unparsed(n) => { - matches!(n.args, AttrArgs::Empty) - } - _ => false, - } + matches!(self.kind, AttrKind::Normal(box AttrItem { args: AttrArgs::Empty, .. })) } - #[inline] fn ident_path(&self) -> Option> { - match &self { - Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()), - _ => None, + match &self.kind { + AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()), + AttrKind::DocComment(..) => None, } } - #[inline] fn doc_str(&self) -> Option { - match &self { - Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment), - Attribute::Unparsed(_) if self.has_name(sym::doc) => self.value_str(), + match &self.kind { + AttrKind::DocComment(.., data) => Some(*data), + AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(), _ => None, } } - #[inline] fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { - match &self { - Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { - Some((*comment, *kind)) - } - Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => { + match &self.kind { + AttrKind::DocComment(kind, data) => Some((*data, *kind)), + AttrKind::Normal(_) if self.name_or_empty() == sym::doc => { self.value_str().map(|s| (s, CommentKind::Line)) } _ => None, } } - #[inline] fn style(&self) -> AttrStyle { - match &self { - Attribute::Unparsed(u) => u.style, - Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style, - _ => panic!(), - } + self.style } } // FIXME(fn_delegation): use function delegation instead of manually forwarding impl Attribute { - #[inline] pub fn id(&self) -> AttrId { AttributeExt::id(self) } - #[inline] pub fn name_or_empty(&self) -> Symbol { AttributeExt::name_or_empty(self) } - #[inline] pub fn meta_item_list(&self) -> Option> { AttributeExt::meta_item_list(self) } - #[inline] pub fn value_str(&self) -> Option { AttributeExt::value_str(self) } - #[inline] pub fn value_span(&self) -> Option { AttributeExt::value_span(self) } - #[inline] pub fn ident(&self) -> Option { AttributeExt::ident(self) } - #[inline] pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) } - #[inline] pub fn is_doc_comment(&self) -> bool { AttributeExt::is_doc_comment(self) } @@ -1262,42 +1186,34 @@ impl Attribute { AttributeExt::has_name(self, name) } - #[inline] pub fn span(&self) -> Span { AttributeExt::span(self) } - #[inline] pub fn is_word(&self) -> bool { AttributeExt::is_word(self) } - #[inline] pub fn path(&self) -> SmallVec<[Symbol; 1]> { AttributeExt::path(self) } - #[inline] pub fn ident_path(&self) -> Option> { AttributeExt::ident_path(self) } - #[inline] pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) } - #[inline] pub fn is_proc_macro_attr(&self) -> bool { AttributeExt::is_proc_macro_attr(self) } - #[inline] pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { AttributeExt::doc_str_and_comment_kind(self) } - #[inline] pub fn style(&self) -> AttrStyle { AttributeExt::style(self) } diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 2709a826549c5..d7c8a3d5c0a5f 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,21 +1,17 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_span::def_id::DefPathHash; -use crate::HashIgnoredAttrId; use crate::hir::{ - AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, + Attribute, AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, + TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: - rustc_attr_data_structures::HashStableContext - + rustc_ast::HashStableContext - + rustc_abi::HashStableContext -{ - fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher); +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext { + fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher); } impl ToStableHashKey for HirId { @@ -118,8 +114,8 @@ impl HashStable for Crate<'_> { } } -impl HashStable for HashIgnoredAttrId { +impl HashStable for Attribute { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_attr_id(self, hasher) + hcx.hash_attr(self, hasher) } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 09320b8687836..3236e0a3644d9 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,8 +2,6 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::FieldIdx; -use rustc_attr_parsing::AttributeKind; -use rustc_attr_parsing::ReprAttr::ReprPacked; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; @@ -1116,7 +1114,7 @@ fn check_impl_items_against_trait<'tcx>( if let Some(missing_items) = must_implement_one_of { let attr_span = tcx .get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of) - .map(|attr| attr.span()); + .map(|attr| attr.span); missing_items_must_implement_one_of_err( tcx, @@ -1205,13 +1203,11 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - if let Some(reprs) = - attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r) - { - for (r, _) in reprs { - if let ReprPacked(pack) = r + for attr in tcx.get_attrs(def.did(), sym::repr) { + for r in attr::parse_repr_attr(tcx.sess, attr) { + if let attr::ReprPacked(pack) = r && let Some(repr_pack) = repr.pack - && pack != &repr_pack + && pack != repr_pack { struct_span_code_err!( tcx.dcx(), @@ -1423,19 +1419,16 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - attr::find_attr!( - tcx.get_all_attrs(def_id), - AttributeKind::Repr(rs) => { - struct_span_code_err!( - tcx.dcx(), - rs.first().unwrap().1, - E0084, - "unsupported representation for zero-variant enum" - ) - .with_span_label(tcx.def_span(def_id), "zero-variant enum") - .emit(); - } - ); + if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { + struct_span_code_err!( + tcx.dcx(), + attr.span, + E0084, + "unsupported representation for zero-variant enum" + ) + .with_span_label(tcx.def_span(def_id), "zero-variant enum") + .emit(); + } } let repr_type_ty = def.repr().discr_type().to_ty(tcx); diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 3bad36da99909..25c2f8554b7f4 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -99,7 +99,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } for attr in tcx.get_attrs(main_def_id, sym::track_caller) { - tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span }); + tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span }); error = true; } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2a2879c657747..dd91d70b004bb 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1202,7 +1202,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { // and that they are all identifiers .and_then(|attr| match attr.meta_item_list() { Some(items) if items.len() < 2 => { - tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() }); + tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span }); None } @@ -1214,7 +1214,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span }); }) .ok() - .zip(Some(attr.span())), + .zip(Some(attr.span)), // Error is reported by `rustc_attr!` None => None, }) diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 4debd3977f50a..63c445fa6a3d4 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -111,14 +111,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity(); if trait_ref.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` must be applied to non-generic impl", ); continue; } if !tcx.is_dyn_compatible(trait_ref.def_id) { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` must be applied to dyn-compatible trait", ); continue; @@ -127,7 +127,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref) else { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` applied to impl header that cannot be normalized", ); continue; @@ -138,7 +138,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let ty = tcx.type_of(def_id).instantiate_identity(); if ty.has_non_region_param() { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` must be applied to non-generic type", ); continue; @@ -147,14 +147,13 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) else { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` applied to type alias that cannot be normalized", ); continue; }; let ty::Dynamic(data, _, _) = *ty.kind() else { - tcx.dcx() - .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type"); + tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type"); continue; }; if let Some(principal) = data.principal() { @@ -167,7 +166,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { } _ => { tcx.dcx().span_err( - attr.span(), + attr.span, "`rustc_dump_vtable` only applies to impl, or type alias of dyn type", ); continue; diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 86989d1e55b4d..f5d7dbd3f96e4 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c7426d76b31c..167bed5f65029 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -11,12 +11,11 @@ use std::vec; use rustc_abi::ExternAbi; use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity}; -use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs}; +use rustc_ast::{DUMMY_NODE_ID, DelimArgs}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; -use rustc_attr_parsing::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, @@ -81,48 +80,65 @@ impl<'a> State<'a> { (self.attrs)(id) } - fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) { - self.print_either_attributes(attrs, ast::AttrStyle::Inner) + fn print_inner_attributes(&mut self, attrs: &[hir::Attribute]) -> bool { + self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } - fn print_attrs_as_outer(&mut self, attrs: &[hir::Attribute]) { - self.print_either_attributes(attrs, ast::AttrStyle::Outer) + fn print_outer_attributes(&mut self, attrs: &[hir::Attribute]) -> bool { + self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) } - fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) { - if attrs.is_empty() { - return; - } - + fn print_either_attributes( + &mut self, + attrs: &[hir::Attribute], + kind: ast::AttrStyle, + is_inline: bool, + trailing_hardbreak: bool, + ) -> bool { + let mut printed = false; for attr in attrs { - self.print_attribute_inline(attr, style); + if attr.style == kind { + self.print_attribute_inline(attr, is_inline); + if is_inline { + self.nbsp(); + } + printed = true; + } } - self.hardbreak_if_not_bol(); + if printed && trailing_hardbreak && !is_inline { + self.hardbreak_if_not_bol(); + } + printed } - fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) { - match &attr { - hir::Attribute::Unparsed(unparsed) => { - self.maybe_print_comment(unparsed.span.lo()); - match style { + fn print_attribute_inline(&mut self, attr: &hir::Attribute, is_inline: bool) { + if !is_inline { + self.hardbreak_if_not_bol(); + } + self.maybe_print_comment(attr.span.lo()); + match &attr.kind { + hir::AttrKind::Normal(normal) => { + match attr.style { ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.print_attr_item(&unparsed, unparsed.span); + if normal.unsafety == hir::Safety::Unsafe { + self.word("unsafe("); + } + self.print_attr_item(&normal, attr.span); + if normal.unsafety == hir::Safety::Unsafe { + self.word(")"); + } self.word("]"); } - hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { + hir::AttrKind::DocComment(comment_kind, data) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( - *kind, *style, *comment, + *comment_kind, + attr.style, + *data, )); self.hardbreak() } - hir::Attribute::Parsed(pa) => { - self.word("#[attr=\""); - pa.print_attribute(self); - self.word("\")]"); - self.hardbreak() - } } } @@ -146,7 +162,7 @@ impl<'a> State<'a> { false, None, *delim, - &tokens, + tokens, true, span, ), @@ -291,7 +307,7 @@ where } pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String { - to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer)) + to_string(ann, |s| s.print_attribute_inline(attr, false)) } pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String { @@ -354,7 +370,7 @@ impl<'a> State<'a> { } fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) { - self.print_attrs_as_inner(attrs); + self.print_inner_attributes(attrs); for &item_id in _mod.item_ids { self.ann.nested(self, Nested::Item(item_id)); } @@ -471,7 +487,7 @@ impl<'a> State<'a> { fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); - self.print_attrs_as_outer(self.attrs(item.hir_id())); + self.print_outer_attributes(self.attrs(item.hir_id())); match item.kind { hir::ForeignItemKind::Fn(sig, arg_names, generics) => { self.head(""); @@ -575,7 +591,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); - self.print_attrs_as_outer(attrs); + self.print_outer_attributes(attrs); self.ann.pre(self, AnnNode::Item(item)); match item.kind { hir::ItemKind::ExternCrate(orig_name) => { @@ -671,7 +687,7 @@ impl<'a> State<'a> { self.head("extern"); self.word_nbsp(abi.to_string()); self.bopen(); - self.print_attrs_as_inner(self.attrs(item.hir_id())); + self.print_inner_attributes(self.attrs(item.hir_id())); for item in items { self.ann.nested(self, Nested::ForeignItem(item.id)); } @@ -739,7 +755,7 @@ impl<'a> State<'a> { self.space(); self.bopen(); - self.print_attrs_as_inner(attrs); + self.print_inner_attributes(attrs); for impl_item in items { self.ann.nested(self, Nested::ImplItem(impl_item.id)); } @@ -831,7 +847,7 @@ impl<'a> State<'a> { for v in variants { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); - self.print_attrs_as_outer(self.attrs(v.hir_id)); + self.print_outer_attributes(self.attrs(v.hir_id)); self.ibox(INDENT_UNIT); self.print_variant(v); self.word(","); @@ -864,7 +880,7 @@ impl<'a> State<'a> { self.popen(); self.commasep(Inconsistent, struct_def.fields(), |s, field| { s.maybe_print_comment(field.span.lo()); - s.print_attrs_as_outer(s.attrs(field.hir_id)); + s.print_outer_attributes(s.attrs(field.hir_id)); s.print_type(field.ty); }); self.pclose(); @@ -891,7 +907,7 @@ impl<'a> State<'a> { for field in fields { self.hardbreak_if_not_bol(); self.maybe_print_comment(field.span.lo()); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_outer_attributes(self.attrs(field.hir_id)); self.print_ident(field.ident); self.word_nbsp(":"); self.print_type(field.ty); @@ -927,7 +943,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ti.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); - self.print_attrs_as_outer(self.attrs(ti.hir_id())); + self.print_outer_attributes(self.attrs(ti.hir_id())); match ti.kind { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); @@ -955,7 +971,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ii.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ii.span.lo()); - self.print_attrs_as_outer(self.attrs(ii.hir_id())); + self.print_outer_attributes(self.attrs(ii.hir_id())); match ii.kind { hir::ImplItemKind::Const(ty, expr) => { @@ -1058,7 +1074,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Block(blk)); self.bopen(); - self.print_attrs_as_inner(attrs); + self.print_inner_attributes(attrs); for st in blk.stmts { self.print_stmt(st); @@ -1248,7 +1264,7 @@ impl<'a> State<'a> { self.space(); } self.cbox(INDENT_UNIT); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_outer_attributes(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_space(":"); @@ -1445,7 +1461,7 @@ impl<'a> State<'a> { fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.maybe_print_comment(expr.span.lo()); - self.print_attrs_as_outer(self.attrs(expr.hir_id)); + self.print_outer_attributes(self.attrs(expr.hir_id)); self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { @@ -1661,8 +1677,8 @@ impl<'a> State<'a> { } hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => { match kind { - ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("), - ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("), + hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("), + hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("), } self.print_expr(expr); if let Some(ty) = ty { @@ -2057,7 +2073,7 @@ impl<'a> State<'a> { self.space(); } self.cbox(INDENT_UNIT); - self.print_attrs_as_outer(self.attrs(field.hir_id)); + self.print_outer_attributes(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_nbsp(":"); @@ -2067,7 +2083,7 @@ impl<'a> State<'a> { } fn print_param(&mut self, arg: &hir::Param<'_>) { - self.print_attrs_as_outer(self.attrs(arg.hir_id)); + self.print_outer_attributes(self.attrs(arg.hir_id)); self.print_pat(arg.pat); } @@ -2102,7 +2118,7 @@ impl<'a> State<'a> { self.cbox(INDENT_UNIT); self.ann.pre(self, AnnNode::Arm(arm)); self.ibox(0); - self.print_attrs_as_outer(self.attrs(arm.hir_id)); + self.print_outer_attributes(self.attrs(arm.hir_id)); self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4815627a0ce0b..0c71ef4655c5c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1656,13 +1656,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_unsafe_binder_cast( &self, span: Span, - kind: ast::UnsafeBinderCastKind, + kind: hir::UnsafeBinderCastKind, inner_expr: &'tcx hir::Expr<'tcx>, hir_ty: Option<&'tcx hir::Ty<'tcx>>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { match kind { - ast::UnsafeBinderCastKind::Wrap => { + hir::UnsafeBinderCastKind::Wrap => { let ascribed_ty = hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty)); let expected_ty = expected.only_has_type(self); @@ -1706,7 +1706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { binder_ty } - ast::UnsafeBinderCastKind::Unwrap => { + hir::UnsafeBinderCastKind::Unwrap => { let ascribed_ty = hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty)); let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span)); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 18218a7a0a641..8438a92219eae 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; -use rustc_attr_parsing::{AttributeKind, find_attr}; +use rustc_attr_parsing::parse_confusables; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; @@ -1884,7 +1884,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { - if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) + if let Some(attr) = + self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables) + && let Some(candidates) = parse_confusables(attr) && candidates.contains(&item_name.name) && let ty::AssocKind::Fn = inherent_method.kind { diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 8f2ca6babea88..d4407559202f0 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -137,13 +137,13 @@ impl<'tcx> IfThisChanged<'tcx> { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span(), + span: attr.span, name: n, }), } } }; - self.if_this_changed.push((attr.span(), def_id.to_def_id(), dep_node)); + self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node)); } else if attr.has_name(sym::rustc_then_this_would_need) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { @@ -151,17 +151,17 @@ impl<'tcx> IfThisChanged<'tcx> { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span(), + span: attr.span, name: n, }), } } None => { - self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span() }); + self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span }); } }; self.then_this_would_need.push(( - attr.span(), + attr.span, dep_node_interned.unwrap(), hir_id, dep_node, diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index d40a0d514f6f9..56858679af663 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -199,7 +199,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let loaded_from_disk = self.loaded_from_disk(attr); for e in except.items().into_sorted_stable_ord() { if !auto.remove(e) { - self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span(), name, e }); + self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span, name, e }); } } Assertion { clean: auto, dirty: except, loaded_from_disk } @@ -282,7 +282,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL), _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirtyItem { - span: attr.span(), + span: attr.span, kind: format!("{:?}", item.kind), }), } @@ -298,7 +298,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), }, _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirty { - span: attr.span(), + span: attr.span, kind: format!("{node:?}"), }), }; @@ -375,7 +375,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let Some(assertion) = self.assertion_maybe(item_id, attr) else { continue; }; - self.checked_attrs.insert(attr.id()); + self.checked_attrs.insert(attr.id); for label in assertion.clean.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, label, def_path_hash).unwrap(); self.assert_clean(item_span, dep_node); @@ -405,13 +405,12 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { - tcx.dcx() - .emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() }); + tcx.dcx().emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() }); } } match cfg { - None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span() }), + None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span }), Some(c) => c, } } @@ -445,9 +444,9 @@ impl<'tcx> FindAllAttrs<'tcx> { fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet) { for attr in &self.found_attrs { - if !checked_attrs.contains(&attr.id()) { - self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span() }); - checked_attrs.insert(attr.id()); + if !checked_attrs.contains(&attr.id) { + self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span }); + checked_attrs.insert(attr.id); } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index f7be37dc4a2c3..5e44583b2976b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1011,7 +1011,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() }, + BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }, ); break; } @@ -1226,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { { cx.emit_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span(), + attr.span, BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess }, ); } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 9ca148e1f2549..ef79f1301e5f6 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -38,8 +38,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { } LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok. - let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id(); - + let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id; (attr_id, lint_index) } _ => panic!("fulfilled expectations must have a lint index"), diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 6175415c31f98..49c34d0edcc2a 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -182,7 +182,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span()) + (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 49f9ad39780a3..bc35e2f0538d0 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,14 +1,13 @@ use rustc_abi::ExternAbi; -use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; +use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind}; use rustc_middle::ty; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{BytePos, Ident, Span, sym}; -use {rustc_ast as ast, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; use crate::lints::{ NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, @@ -162,10 +161,10 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { - let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true), - Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) - ); + let has_repr_c = it + .attrs + .iter() + .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC)); if has_repr_c { return; @@ -344,7 +343,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } 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 + if let AttrKind::Normal(n) = &attr.kind && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } = n.as_ref() && let ast::LitKind::Str(name, ..) = lit.kind diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index e564235c41a5e..ff3dae08ffc96 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -251,23 +251,19 @@ impl Level { /// Converts an `Attribute` to a level. pub fn from_attr(attr: &impl AttributeExt) -> Option { - Self::from_symbol(attr.name_or_empty(), || Some(attr.id())) + Self::from_symbol(attr.name_or_empty(), Some(attr.id())) } /// Converts a `Symbol` to a level. - pub fn from_symbol(s: Symbol, id: impl FnOnce() -> Option) -> Option { - match s { - sym::allow => Some(Level::Allow), - sym::expect => { - if let Some(attr_id) = id() { - Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None })) - } else { - None - } + pub fn from_symbol(s: Symbol, id: Option) -> Option { + match (s, id) { + (sym::allow, _) => Some(Level::Allow), + (sym::expect, Some(attr_id)) => { + Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None })) } - sym::warn => Some(Level::Warn), - sym::deny => Some(Level::Deny), - sym::forbid => Some(Level::Forbid), + (sym::warn, _) => Some(Level::Warn), + (sym::deny, _) => Some(Level::Deny), + (sym::forbid, _) => Some(Level::Forbid), _ => None, } } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 34fc0f00320c0..0df674eb4c909 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -17,7 +17,6 @@ mod diagnostics; mod extension; mod hash_stable; mod lift; -mod print_attribute; mod query; mod serialize; mod symbols; @@ -176,11 +175,3 @@ decl_derive! { /// The error type is `u32`. try_from::try_from_u32 } -decl_derive! { - [PrintAttribute] => - /// Derives `PrintAttribute` for `AttributeKind`. - /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in - /// other places. It's deriving something close to `Debug` without printing some extraenous - /// things like spans. - print_attribute::print_attribute -} diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs deleted file mode 100644 index 3c6e30b851bf7..0000000000000 --- a/compiler/rustc_macros/src/print_attribute.rs +++ /dev/null @@ -1,145 +0,0 @@ -use proc_macro2::TokenStream; -use quote::{format_ident, quote, quote_spanned}; -use syn::spanned::Spanned; -use syn::{Data, Fields, Ident}; -use synstructure::Structure; - -fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) { - let string_name = name.to_string(); - let mut disps = vec![quote! {let mut __printed_anything = false;}]; - - match fields { - Fields::Named(fields_named) => { - let mut field_names = Vec::new(); - - for field in &fields_named.named { - let name = field.ident.as_ref().unwrap(); - let string_name = name.to_string(); - disps.push(quote! { - if __printed_anything && #name.print_something() { - __p.word_space(","); - __printed_anything = true; - } - __p.word(#string_name); - __p.word_space(":"); - #name.print_attribute(__p); - }); - field_names.push(name); - } - - ( - quote! { {#(#field_names),*} }, - quote! { - __p.word(#string_name); - if true #(&& !#field_names.print_something())* { - return; - } - - __p.word("{"); - #(#disps)* - __p.word("}"); - }, - quote! { true }, - ) - } - Fields::Unnamed(fields_unnamed) => { - let mut field_names = Vec::new(); - - for idx in 0..fields_unnamed.unnamed.len() { - let name = format_ident!("f{idx}"); - disps.push(quote! { - if __printed_anything && #name.print_something() { - __p.word_space(","); - __printed_anything = true; - } - #name.print_attribute(__p); - }); - field_names.push(name); - } - - ( - quote! { (#(#field_names),*) }, - quote! { - __p.word(#string_name); - - if true #(&& !#field_names.print_something())* { - return; - } - - __p.word("("); - #(#disps)* - __p.word(")"); - }, - quote! { true }, - ) - } - Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }), - } -} - -pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { - let span_error = |span, message: &str| { - quote_spanned! { span => const _: () = ::core::compile_error!(#message); } - }; - - // Must be applied to an enum type. - let (code, printed) = match &input.ast().data { - Data::Enum(e) => { - let (arms, printed) = e - .variants - .iter() - .map(|x| { - let ident = &x.ident; - let (pat, code, printed) = print_fields(ident, &x.fields); - - ( - quote! { - Self::#ident #pat => {#code} - }, - quote! { - Self::#ident #pat => {#printed} - }, - ) - }) - .unzip::<_, _, Vec<_>, Vec<_>>(); - - ( - quote! { - match self { - #(#arms)* - } - }, - quote! { - match self { - #(#printed)* - } - }, - ) - } - Data::Struct(s) => { - let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields); - ( - quote! { - let Self #pat = self; - #code - }, - quote! { - let Self #pat = self; - #printed - }, - ) - } - Data::Union(u) => { - return span_error(u.union_token.span(), "can't derive PrintAttribute on unions"); - } - }; - - #[allow(keyword_idents_2024)] - input.gen_impl(quote! { - #[allow(unused)] - gen impl PrintAttribute for @Self { - fn print_something(&self) -> bool { #printed } - fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } - } - }) -} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index e2d043f47c0ef..2a1e4b261e737 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -450,7 +450,7 @@ impl<'tcx> Collector<'tcx> { (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule)); } let Some((name, name_span)) = name else { - sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() }); + sess.dcx().emit_err(errors::LinkRequiresName { span: m.span }); continue; }; @@ -485,7 +485,7 @@ impl<'tcx> Collector<'tcx> { let link_ordinal_attr = self.tcx.get_attr(child_item, sym::link_ordinal).unwrap(); sess.dcx().emit_err(errors::LinkOrdinalRawDylib { - span: link_ordinal_attr.span(), + span: link_ordinal_attr.span, }); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 16149198303a2..591c8ed50d57a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1071,6 +1071,7 @@ impl<'a> CrateMetadataRef<'a> { let attrs: Vec<_> = self.get_item_attrs(id, sess).collect(); SyntaxExtension::new( sess, + tcx.features(), kind, self.get_span(id, sess), helper_attrs, diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 9ce5373b03118..ed7c98ee0e011 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -75,7 +75,7 @@ impl OverlapMode { tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id)) }) .find(|attr| attr.has_name(sym::rustc_strict_coherence)) - .map(|attr| attr.span()); + .map(|attr| attr.span); tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence { span: tcx.def_span(trait_id), attr_span, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 62a384af12f28..238ba127e2ecf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1542,7 +1542,7 @@ impl<'tcx> TyCtxt<'tcx> { Bound::Included(a.get()) } else { self.dcx().span_delayed_bug( - attr.span(), + attr.span, "invalid rustc_layout_scalar_valid_range attribute", ); Bound::Unbounded diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9208c2a65a124..dbbbdc606bbb4 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,6 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -use rustc_attr_parsing::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -1496,10 +1495,9 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) - { - for (r, _) in reprs { - flags.insert(match *r { + for attr in self.get_attrs(did, sym::repr) { + for r in attr::parse_repr_attr(self.sess, attr) { + flags.insert(match r { attr::ReprRust => ReprFlags::empty(), attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { @@ -1537,10 +1535,6 @@ impl<'tcx> TyCtxt<'tcx> { max_align = max_align.max(Some(align)); ReprFlags::empty() } - attr::ReprEmpty => { - /* skip these, they're just for diagnostics */ - ReprFlags::empty() - } }); } } @@ -1762,22 +1756,14 @@ impl<'tcx> TyCtxt<'tcx> { self, did: impl Into, attr: Symbol, - ) -> impl Iterator { - self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr)) - } - - /// Gets all attributes. - /// - /// To see if an item has a specific attribute, you should use [`rustc_attr_parsing::find_attr!`] so you can use matching. - pub fn get_all_attrs( - self, - did: impl Into, ) -> impl Iterator { let did: DefId = did.into(); + let filter_fn = move |a: &&hir::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.local_def_id_to_hir_id(did)).iter() + self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else { - self.attrs_for_def(did).iter() + debug_assert!(rustc_feature::encode_cross_crate(attr)); + self.attrs_for_def(did).iter().filter(filter_fn) } } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index ccf76dc710874..58461be01f175 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -65,7 +65,7 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { Some(_) | None => { // Other possibilities should have been rejected by `rustc_parse::validate_attr`. // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). - tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute"); + tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute"); } } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index bc43580a7f00d..978cb7af2427f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -311,6 +311,9 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_empty_confusables = + expected at least one confusable name + passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static @@ -362,6 +365,9 @@ passes_incorrect_do_not_recommend_args = passes_incorrect_do_not_recommend_location = `#[diagnostic::do_not_recommend]` can only be placed on trait implementations +passes_incorrect_meta_item = expected a quoted string literal +passes_incorrect_meta_item_suggestion = consider surrounding this with quotes + passes_incorrect_target = `{$name}` lang item must be applied to a {$kind} with {$at_least -> [true] at least {$num} @@ -635,12 +641,13 @@ passes_repr_align_greater_than_target_max = passes_repr_conflicting = conflicting representation hints +passes_repr_ident = + meta item in `repr` must be an identifier + passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` -passes_rustc_const_stable_indirect_pairing = - `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled @@ -767,6 +774,10 @@ passes_unreachable_due_to_uninhabited = unreachable {$descr} passes_unrecognized_field = unrecognized field name `{$name}` +passes_unrecognized_repr_hint = + unrecognized representation hint + .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + passes_unstable_attr_for_already_stable_feature = can't mark as unstable using an already stable feature .label = this feature is already stable diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9be868122872d..9a4db612cfed8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1,4 +1,3 @@ -// FIXME(jdonszelmann): should become rustc_attr_validation //! This module implements some validity checks for attributes. //! In particular it verifies that `#[inline]` and `#[repr]` attributes are //! attached to items that actually support them and if there are @@ -8,17 +7,16 @@ use std::cell::Cell; use std::collections::hash_map::Entry; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::{ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, self, AssocItemKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, - HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, + self as hir, self, AssocItemKind, AttrKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, + ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -115,201 +113,190 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { - match attr { - Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { - self.check_confusables(*first_span, target); - } - Attribute::Parsed( - AttributeKind::Stability { span, .. } - | AttributeKind::ConstStability { span, .. }, - ) => self.check_stability_promotable(*span, target), - Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self - .check_allow_internal_unstable( - hir_id, - syms.first().unwrap().1, - span, - target, - attrs, - ), - _ => { - match attr.path().as_slice() { - [sym::diagnostic, sym::do_not_recommend, ..] => { - self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) - } - [sym::diagnostic, sym::on_unimplemented, ..] => { - self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) - } - [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), - [sym::coverage, ..] => self.check_coverage(attr, span, target), - [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), - [sym::no_sanitize, ..] => { - self.check_no_sanitize(attr, span, target) - } - [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item), - [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), - [sym::target_feature, ..] => { - self.check_target_feature(hir_id, attr, span, target, attrs) - } - [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::track_caller, ..] => { - self.check_track_caller(hir_id, attr.span(), attrs, span, target) - } - [sym::doc, ..] => self.check_doc_attrs( - attr, - hir_id, - target, - &mut specified_inline, - &mut doc_aliases, - ), - [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start, ..] - | [sym::rustc_layout_scalar_valid_range_end, ..] => { - self.check_rustc_layout_scalar_valid_range(attr, span, target) - } - [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), - [sym::rustc_allow_const_fn_unstable, ..] => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) - } - [sym::rustc_std_internal_symbol, ..] => { - self.check_rustc_std_internal_symbol(attr, span, target) - } - [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), - [sym::rustc_as_ptr, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_never_returns_null_ptr, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_legacy_const_generics, ..] => { - self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) - } - [sym::rustc_lint_query_instability, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_untracked_query_information, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_diagnostics, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), - [sym::rustc_lint_opt_deny_field_access, ..] => { - self.check_rustc_lint_opt_deny_field_access(attr, span, target) - } - [sym::rustc_clean, ..] - | [sym::rustc_dirty, ..] - | [sym::rustc_if_this_changed, ..] - | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::rustc_coinductive, ..] - | [sym::rustc_must_implement_one_of, ..] - | [sym::rustc_deny_explicit_impl, ..] - | [sym::rustc_do_not_implement_via_object, ..] - | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), - [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), - [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), - [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), - [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), - [sym::rustc_allow_incoherent_impl, ..] => { - self.check_allow_incoherent_impl(attr, span, target) - } - [sym::rustc_has_incoherent_inherent_impls, ..] => { - self.check_has_incoherent_inherent_impls(attr, span, target) - } - [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target), - [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), - [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), - [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), - [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), - [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), - [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), - [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), - [sym::macro_use, ..] | [sym::macro_escape, ..] => { - self.check_macro_use(hir_id, attr, target) - } - [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod), - [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), - [sym::ignore, ..] | [sym::should_panic, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Fn) - } - [sym::automatically_derived, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Impl) - } - [sym::no_implicit_prelude, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Mod) - } - [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), - [sym::proc_macro, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) - } - [sym::proc_macro_attribute, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); - } - [sym::proc_macro_derive, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Fn); - self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) - } - [sym::autodiff, ..] => { - self.check_autodiff(hir_id, attr, span, target) - } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } - [sym::linkage, ..] => self.check_linkage(attr, span, target), - [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span(), span, attrs), - [ - // ok - sym::allow - | sym::expect - | sym::warn - | sym::deny - | sym::forbid - | sym::cfg - | sym::cfg_attr - // need to be fixed - | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_coerce_pointee) - | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) - | sym::used // handled elsewhere to restrict to static items - | sym::repr // handled elsewhere to restrict to type decls items - | sym::instruction_set // broken on stable!!! - | sym::windows_subsystem // broken on stable!!! - | sym::patchable_function_entry // FIXME(patchable_function_entry) - | sym::deprecated_safe // FIXME(deprecated_safe) - // internal - | sym::prelude_import - | sym::panic_handler - | sym::allow_internal_unsafe - | sym::fundamental - | sym::lang - | sym::needs_allocator - | sym::default_lib_allocator - | sym::custom_mir, - .. - ] => {} - [name, ..] => { - match BUILTIN_ATTRIBUTE_MAP.get(name) { - // checked below - Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} - Some(_) => { - // FIXME: differentiate between unstable and internal attributes just - // like we do with features instead of just accepting `rustc_` - // attributes by name. That should allow trimming the above list, too. - if !name.as_str().starts_with("rustc_") { - span_bug!( - attr.span(), - "builtin attribute {name:?} not handled by `CheckAttrVisitor`" - ) - } - } - None => (), + match attr.path().as_slice() { + [sym::diagnostic, sym::do_not_recommend, ..] => { + self.check_do_not_recommend(attr.span, hir_id, target, attr, item) + } + [sym::diagnostic, sym::on_unimplemented, ..] => { + self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) + } + [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), + [sym::coverage, ..] => self.check_coverage(attr, span, target), + [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), + [sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target), + [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item), + [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), + [sym::target_feature, ..] => { + self.check_target_feature(hir_id, attr, span, target, attrs) + } + [sym::thread_local, ..] => self.check_thread_local(attr, span, target), + [sym::track_caller, ..] => { + self.check_track_caller(hir_id, attr.span, attrs, span, target) + } + [sym::doc, ..] => self.check_doc_attrs( + attr, + hir_id, + target, + &mut specified_inline, + &mut doc_aliases, + ), + [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), + [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), + [sym::rustc_layout_scalar_valid_range_start, ..] + | [sym::rustc_layout_scalar_valid_range_end, ..] => { + self.check_rustc_layout_scalar_valid_range(attr, span, target) + } + [sym::allow_internal_unstable, ..] => { + self.check_allow_internal_unstable(hir_id, attr, span, target, attrs) + } + [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), + [sym::rustc_allow_const_fn_unstable, ..] => { + self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + } + [sym::rustc_std_internal_symbol, ..] => { + self.check_rustc_std_internal_symbol(attr, span, target) + } + [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_as_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_never_returns_null_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_legacy_const_generics, ..] => { + self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) + } + [sym::rustc_lint_query_instability, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_untracked_query_information, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_diagnostics, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), + [sym::rustc_lint_opt_deny_field_access, ..] => { + self.check_rustc_lint_opt_deny_field_access(attr, span, target) + } + [sym::rustc_clean, ..] + | [sym::rustc_dirty, ..] + | [sym::rustc_if_this_changed, ..] + | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), + [sym::rustc_coinductive, ..] + | [sym::rustc_must_implement_one_of, ..] + | [sym::rustc_deny_explicit_impl, ..] + | [sym::rustc_do_not_implement_via_object, ..] + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), + [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), + [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), + [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), + [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), + [sym::rustc_allow_incoherent_impl, ..] => { + self.check_allow_incoherent_impl(attr, span, target) + } + [sym::rustc_has_incoherent_inherent_impls, ..] => { + self.check_has_incoherent_inherent_impls(attr, span, target) + } + [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target), + [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target), + [sym::rustc_const_unstable, ..] + | [sym::rustc_const_stable, ..] + | [sym::unstable, ..] + | [sym::stable, ..] + | [sym::rustc_allowed_through_unstable_modules, ..] + | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target), + [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), + [sym::rustc_confusables, ..] => self.check_confusables(attr, target), + [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), + [sym::link, ..] => self.check_link(hir_id, attr, span, target), + [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), + [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), + [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), + [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), + [sym::macro_use, ..] | [sym::macro_escape, ..] => { + self.check_macro_use(hir_id, attr, target) + } + [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod), + [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), + [sym::ignore, ..] | [sym::should_panic, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Fn) + } + [sym::automatically_derived, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Impl) + } + [sym::no_implicit_prelude, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Mod) + } + [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), + [sym::proc_macro, ..] => { + self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) + } + [sym::proc_macro_attribute, ..] => { + self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); + } + [sym::proc_macro_derive, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Fn); + self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) + } + [sym::autodiff, ..] => { + self.check_autodiff(hir_id, attr, span, target) + } + [sym::coroutine, ..] => { + self.check_coroutine(attr, target); + } + [sym::linkage, ..] => self.check_linkage(attr, span, target), + [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs), + [ + // ok + sym::allow + | sym::expect + | sym::warn + | sym::deny + | sym::forbid + | sym::cfg + | sym::cfg_attr + // need to be fixed + | sym::cfi_encoding // FIXME(cfi_encoding) + | sym::pointee // FIXME(derive_coerce_pointee) + | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) + | sym::used // handled elsewhere to restrict to static items + | sym::repr // handled elsewhere to restrict to type decls items + | sym::instruction_set // broken on stable!!! + | sym::windows_subsystem // broken on stable!!! + | sym::patchable_function_entry // FIXME(patchable_function_entry) + | sym::deprecated_safe // FIXME(deprecated_safe) + // internal + | sym::prelude_import + | sym::panic_handler + | sym::allow_internal_unsafe + | sym::fundamental + | sym::lang + | sym::needs_allocator + | sym::default_lib_allocator + | sym::custom_mir, + .. + ] => {} + [name, ..] => { + match BUILTIN_ATTRIBUTE_MAP.get(name) { + // checked below + Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} + Some(_) => { + // FIXME: differentiate between unstable and internal attributes just + // like we do with features instead of just accepting `rustc_` + // attributes by name. That should allow trimming the above list, too. + if !name.as_str().starts_with("rustc_") { + span_bug!( + attr.span, + "builtin attribute {name:?} not handled by `CheckAttrVisitor`" + ) } } - [] => unreachable!(), + None => (), } } + [] => unreachable!(), } let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); @@ -318,17 +305,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { - match attr.style() { + match attr.style { ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::OuterCrateLevelAttr, ), ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::InnerCrateLevelAttr, ), } @@ -351,16 +338,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::IgnoredAttrWithMacro { sym }, ); } - fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { + fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr_span, + attr.span, errors::IgnoredAttr { sym }, ); } @@ -420,7 +407,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::IgnoredInlineAttrFnProto, ) } @@ -431,7 +418,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::AssocConst => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::IgnoredInlineAttrConstants, ), // FIXME(#80564): Same for fields, arms, and macro defs @@ -440,7 +427,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::InlineNotFnOrClosure { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -472,7 +459,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.dcx().emit_err(errors::CoverageAttributeNotAllowed { - attr_span: attr.span(), + attr_span: attr.span, not_fn_impl_mod, no_body, help: (), @@ -490,7 +477,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); if !is_valid { self.dcx().emit_err(errors::OptimizeInvalidTarget { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -541,7 +528,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::OnlyHasEffectOn { attr_name: attr.name_or_empty(), target_name: allowed_target.name().replace(' ', "_"), @@ -581,7 +568,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::warn, sym::deny, sym::forbid, - // FIXME(jdonszelmann): not used, because already a new-style attr (ugh) sym::deprecated, sym::must_use, // abi, linking and FFI @@ -609,21 +595,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } - // FIXME(jdonszelmann): once naked uses new-style parsing, - // this check can be part of the parser and be removed here - match other_attr { - Attribute::Parsed( - AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. }, - ) => { - continue; - } - _ => {} - } - if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { - span: other_attr.span(), - naked_span: attr.span(), + span: other_attr.span, + naked_span: attr.span, attr: other_attr.name_or_empty(), }); @@ -640,7 +615,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -673,10 +648,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::MacroDef => {} _ => { - self.tcx.dcx().emit_err(errors::CollapseDebuginfo { - attr_span: attr.span(), - defn_span: span, - }); + self.tcx + .dcx() + .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span }); } } } @@ -746,7 +720,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && fields.iter().any(|f| f.default.is_some()) { self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -761,7 +735,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::NonExhaustiveWrongLocation { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -781,7 +755,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -810,7 +784,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); self.dcx().emit_err(errors::LangItemWithTargetFeature { - attr_span: attr.span(), + attr_span: attr.span, name: lang_item, sig_span: sig.span, }); @@ -822,7 +796,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::TargetFeatureOnStatement, ); } @@ -835,7 +809,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -849,7 +823,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::ForeignStatic | Target::Static => {} _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -1119,7 +1093,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocInlineOnlyUse { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) + item_span: (attr.style == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1141,7 +1115,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedOnlyExternCrate { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) + item_span: (attr.style == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1155,7 +1129,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedNotExternCrateSelf { attr_span: meta.span(), - item_span: (attr.style() == AttrStyle::Outer) + item_span: (attr.style == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1185,11 +1159,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { if hir_id != CRATE_HIR_ID { // insert a bang between `#` and `[...` - let bang_span = attr.span().lo() + BytePos(1); - let sugg = (attr.style() == AttrStyle::Outer + let bang_span = attr.span.lo() + BytePos(1); + let sugg = (attr.style == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) .then_some(errors::AttrCrateLevelOnlySugg { - attr: attr.span().with_lo(bang_span).with_hi(bang_span), + attr: attr.span.with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1363,11 +1337,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::DocTestUnknownInclude { path, value: value.to_string(), - inner: match attr.style() { + inner: match attr.style { AttrStyle::Inner => "!", AttrStyle::Outer => "", }, - sugg: (attr.span(), applicability), + sugg: (attr.span, applicability), }, ); } else if i_meta.has_name(sym::passes) @@ -1413,7 +1387,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Enum | Target::TyAlias => {} _ => { - self.dcx().emit_err(errors::PassByValue { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span }); } } } @@ -1422,7 +1396,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Method(MethodKind::Inherent) => {} _ => { - self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span }); } } } @@ -1433,7 +1407,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span }); + .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span }); } } } @@ -1496,7 +1470,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::MustUseNoEffect { article, target }, ); } @@ -1506,7 +1480,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => {} _ => { - self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span }); } } } @@ -1529,7 +1503,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() }); + self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span }); } /// Checks if `#[cold]` is applied to a non-function. @@ -1549,7 +1523,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID }, ); } @@ -1569,7 +1543,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::Link { span: (target != Target::ForeignMod).then_some(span) }, ); } @@ -1588,19 +1562,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); + let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span); if let Some(s) = attr.value_str() { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::LinkName { span, attr_span, value: s.as_str() }, ); } else { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::LinkName { span, attr_span, value: "..." }, ); }; @@ -1620,7 +1594,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link"); } _ => { - self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span }); } } } @@ -1642,7 +1616,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name"); } _ => { - self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span }); } } } @@ -1650,7 +1624,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { if target != Target::Struct { self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span(), + attr_span: attr.span, span, }); return; @@ -1663,7 +1637,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { self.tcx .dcx() - .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() }); + .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); } } @@ -1679,7 +1653,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_function = matches!(target, Target::Fn); if !is_function { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -1704,7 +1678,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { hir::GenericParamKind::Const { .. } => {} _ => { self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly { - attr_span: attr.span(), + attr_span: attr.span, param_span: param.span, }); return; @@ -1714,7 +1688,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if list.len() != generics.params.len() { self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex { - attr_span: attr.span(), + attr_span: attr.span, generics_span: generics.span, }); return; @@ -1754,7 +1728,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_function = matches!(target, Target::Fn | Target::Method(..)); if !is_function { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -1766,7 +1740,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct => {} _ => { - self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span }); } } } @@ -1778,7 +1752,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span }); + .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span }); } } } @@ -1787,7 +1761,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) { if !self.tcx.sess.opts.unstable_opts.query_dep_graph { - self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() }); + self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span }); } } @@ -1797,7 +1771,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Trait => {} _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span(), + attr_span: attr.span, defn_span: span, }); } @@ -1821,7 +1795,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::LinkSection { span }, ); } @@ -1852,8 +1826,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), - errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind }, + attr.span, + errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind }, ); } _ => { @@ -1862,7 +1836,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::NoMangle { span }, ); } @@ -1883,7 +1857,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // #[repr(foo)] // #[repr(bar, align(8))] // ``` - let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]); + let hints: Vec<_> = attrs + .iter() + .filter(|attr| attr.has_name(sym::repr)) + .filter_map(|attr| attr.meta_item_list()) + .flatten() + .collect(); let mut int_reprs = 0; let mut is_explicit_rust = false; @@ -1891,33 +1870,66 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_simd = false; let mut is_transparent = false; - for (repr, repr_span) in reprs { - match repr { - ReprAttr::ReprRust => { + // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) + if hints.is_empty() && item.is_some() { + for attr in attrs.iter().filter(|attr| attr.has_name(sym::repr)) { + match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) => { + feature_err( + &self.tcx.sess, + sym::fn_align, + attr.span, + fluent::passes_repr_align_function, + ) + .emit(); + } + _ => { + self.dcx().emit_err( + errors::AttrApplication::StructEnumFunctionMethodUnion { + hint_span: attr.span, + span, + }, + ); + } + } + } + + return; + } + + for hint in &hints { + if !hint.is_meta_item() { + self.dcx().emit_err(errors::ReprIdent { span: hint.span() }); + continue; + } + + match hint.name_or_empty() { + sym::Rust => { is_explicit_rust = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } } } - ReprAttr::ReprC => { + sym::C => { is_c = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } } } - ReprAttr::ReprAlign(align) => { + sym::align => { match target { Target::Struct | Target::Union | Target::Enum => {} Target::Fn | Target::Method(_) => { @@ -1925,7 +1937,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { feature_err( &self.tcx.sess, sym::fn_align, - *repr_span, + hint.span(), fluent::passes_repr_align_function, ) .emit(); @@ -1934,97 +1946,83 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.dcx().emit_err( errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: *repr_span, + hint_span: hint.span(), span, }, ); } } - self.check_align_value(*align, *repr_span); + self.check_align_value(hint); } - ReprAttr::ReprPacked(_) => { + sym::packed => { if target != Target::Struct && target != Target::Union { self.dcx().emit_err(errors::AttrApplication::StructUnion { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } else { continue; } } - ReprAttr::ReprSimd => { + sym::simd => { is_simd = true; if target != Target::Struct { self.dcx().emit_err(errors::AttrApplication::Struct { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } else { continue; } } - ReprAttr::ReprTransparent => { + sym::transparent => { is_transparent = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } } } - ReprAttr::ReprInt(_) => { + sym::i8 + | sym::u8 + | sym::i16 + | sym::u16 + | sym::i32 + | sym::u32 + | sym::i64 + | sym::u64 + | sym::i128 + | sym::u128 + | sym::isize + | sym::usize => { int_reprs += 1; if target != Target::Enum { self.dcx().emit_err(errors::AttrApplication::Enum { - hint_span: *repr_span, + hint_span: hint.span(), span, }); } else { continue; } } - // FIXME(jdonszelmann): move the diagnostic for unused repr attrs here, I think - // it's a better place for it. - ReprAttr::ReprEmpty => { - // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) - if item.is_some() { - match target { - Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) => { - feature_err( - &self.tcx.sess, - sym::fn_align, - *repr_span, - fluent::passes_repr_align_function, - ) - .emit(); - } - _ => { - self.dcx().emit_err( - errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: *repr_span, - span, - }, - ); - } - } - } - - return; + _ => { + self.dcx().emit_err(errors::UnrecognizedReprHint { span: hint.span() }); + continue; } }; } // Just point at all repr hints if there are any incompatibilities. // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. - let hint_spans = reprs.iter().map(|(_, span)| *span); + let hint_spans = hints.iter().map(|hint| hint.span()); // Error on repr(transparent, ). - if is_transparent && reprs.len() > 1 { + if is_transparent && hints.len() > 1 { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::TransparentIncompatible { hint_spans, @@ -2053,21 +2051,41 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align_value(&self, align: Align, span: Span) { - if align.bytes() > 2_u64.pow(29) { - // for values greater than 2^29, a different error will be emitted, make sure that happens - self.dcx().span_delayed_bug( - span, - "alignment greater than 2^29 should be errored on elsewhere", - ); - } else { - // only do this check when <= 2^29 to prevent duplicate errors: - // alignment greater than 2^29 not supported - // alignment is too large for the current target + fn check_align_value(&self, item: &MetaItemInner) { + match item.singleton_lit_list() { + Some(( + _, + MetaItemLit { + kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), .. + }, + )) => { + let val = literal.get() as u64; + if val > 2_u64.pow(29) { + // for values greater than 2^29, a different error will be emitted, make sure that happens + self.dcx().span_delayed_bug( + item.span(), + "alignment greater than 2^29 should be errored on elsewhere", + ); + } else { + // only do this check when <= 2^29 to prevent duplicate errors: + // alignment greater than 2^29 not supported + // alignment is too large for the current target + + let max = + Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; + if val > max { + self.dcx().emit_err(errors::InvalidReprAlignForTarget { + span: item.span(), + size: max, + }); + } + } + } - let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; - if align.bytes() > max { - self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max }); + // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None + // but an error will have already been emitted, so this code should just skip such attributes + Some((_, _)) | None => { + self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))"); } } } @@ -2078,7 +2096,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { self.dcx().emit_err(errors::UsedStatic { - attr_span: attr.span(), + attr_span: attr.span, span: target_span, target: target.name(), }); @@ -2087,12 +2105,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match inner.as_deref() { Some([item]) if item.has_name(sym::linker) => { if used_linker_span.is_none() { - used_linker_span = Some(attr.span()); + used_linker_span = Some(attr.span); } } Some([item]) if item.has_name(sym::compiler) => { if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); + used_compiler_span = Some(attr.span); } } Some(_) => { @@ -2101,7 +2119,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { None => { // Default case (compiler) when arg isn't defined. if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span()); + used_compiler_span = Some(attr.span); } } } @@ -2115,44 +2133,41 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) - // FIXME(jdonszelmann): if possible, move to attr parsing fn check_allow_internal_unstable( &self, hir_id: HirId, - attr_span: Span, + attr: &Attribute, span: Span, target: Target, attrs: &[Attribute], ) { + debug!("Checking target: {:?}", target); match target { Target::Fn => { for attr in attrs { if attr.is_proc_macro_attr() { - // return on proc macros + debug!("Is proc macro attr"); return; } } - // continue out of the match + debug!("Is not proc macro attr"); } - // return on decl macros - Target::MacroDef => return, + Target::MacroDef => {} // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm => { - self.inline_attr_str_error_without_macro_def( - hir_id, - attr_span, - "allow_internal_unstable", - ); - return; + Target::Field | Target::Arm => self.inline_attr_str_error_without_macro_def( + hir_id, + attr, + "allow_internal_unstable", + ), + _ => { + self.tcx + .dcx() + .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span }); } - // otherwise continue out of the match - _ => {} } - - self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span }); } /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. @@ -2164,7 +2179,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Mod => {} _ => { - self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() }); + self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span }); } } } @@ -2191,7 +2206,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span }); + .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span }); } } } @@ -2202,15 +2217,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span(), span }); + .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span }); } } } - fn check_stability_promotable(&self, span: Span, target: Target) { + fn check_stability_promotable(&self, attr: &Attribute, target: Target) { match target { Target::Expression => { - self.dcx().emit_err(errors::StabilityPromotable { attr_span: span }); + self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span }); } _ => {} } @@ -2220,14 +2235,41 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::ForeignFn | Target::ForeignStatic => {} _ => { - self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span() }); + self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span }); } } } - fn check_confusables(&self, span: Span, target: Target) { - if !matches!(target, Target::Method(MethodKind::Inherent)) { - self.dcx().emit_err(errors::Confusables { attr_span: span }); + fn check_confusables(&self, attr: &Attribute, target: Target) { + match target { + Target::Method(MethodKind::Inherent) => { + let Some(metas) = attr.meta_item_list() else { + return; + }; + + let mut candidates = Vec::new(); + + for meta in metas { + let MetaItemInner::Lit(meta_lit) = meta else { + self.dcx().emit_err(errors::IncorrectMetaItem { + span: meta.span(), + suggestion: errors::IncorrectMetaItemSuggestion { + lo: meta.span().shrink_to_lo(), + hi: meta.span().shrink_to_hi(), + }, + }); + return; + }; + candidates.push(meta_lit.symbol); + } + + if candidates.is_empty() { + self.dcx().emit_err(errors::EmptyConfusables { span: attr.span }); + } + } + _ => { + self.dcx().emit_err(errors::Confusables { attr_span: attr.span }); + } } } @@ -2237,7 +2279,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::Deprecated, ); } @@ -2253,7 +2295,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::MacroUse { name }, ); } @@ -2265,7 +2307,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::MacroExport::Normal, ); } else if let Some(meta_item_list) = attr.meta_item_list() @@ -2275,7 +2317,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( INVALID_MACRO_EXPORT_ARGUMENTS, hir_id, - attr.span(), + attr.span, errors::MacroExport::TooManyItems, ); } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros { @@ -2295,7 +2337,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::MacroExport::OnDeclMacro, ); } @@ -2303,32 +2345,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { - // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very - // ugly now but can 100% be removed later. - if let Attribute::Parsed(p) = attr { - match p { - AttributeKind::Repr(reprs) => { - for (r, span) in reprs { - if let ReprAttr::ReprEmpty = r { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - *span, - errors::Unused { - attr_span: *span, - note: errors::UnusedNote::EmptyList { name: sym::repr }, - }, - ); - } - } - return; - } - _ => {} - } - } - // Warn on useless empty attributes. - let note = if (matches!( + let note = if matches!( attr.name_or_empty(), sym::macro_use | sym::allow @@ -2337,8 +2355,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::deny | sym::forbid | sym::feature + | sym::repr | sym::target_feature - ) && attr.meta_item_list().is_some_and(|list| list.is_empty())) + ) && attr.meta_item_list().is_some_and(|list| list.is_empty()) { errors::UnusedNote::EmptyList { name: attr.name_or_empty() } } else if matches!( @@ -2360,17 +2379,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }) { if hir_id != CRATE_HIR_ID { - match attr.style() { + match attr.style { ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::OuterCrateLevelAttr, ), ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr.span, errors::InnerCrateLevelAttr, ), }; @@ -2396,8 +2415,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), - errors::Unused { attr_span: attr.span(), note }, + attr.span, + errors::Unused { attr_span: attr.span, note }, ); } @@ -2513,7 +2532,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span }); } } } @@ -2526,14 +2545,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignStatic | Target::ForeignFn => {} _ => { - self.dcx().emit_err(errors::Linkage { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span }); } } } fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { - if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) - .unwrap_or(false) + if !attrs + .iter() + .filter(|attr| attr.has_name(sym::repr)) + .filter_map(|attr| attr.meta_item_list()) + .flatten() + .any(|nmi| nmi.has_name(sym::transparent)) { self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); } @@ -2565,14 +2588,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && is_coro { self.dcx().emit_err(errors::RustcForceInlineCoro { - attr_span: attr.span(), + attr_span: attr.span, span: parent_span, }); } } (Target::Fn, _) => (), (_, Some(attr)) => { - self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span }); } (_, None) => (), } @@ -2710,6 +2733,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ sym::macro_export, + sym::repr, sym::path, sym::automatically_derived, sym::rustc_main, @@ -2721,46 +2745,47 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { ]; for attr in attrs { - // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day. - let (span, name) = if let Some(a) = - ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check)) - { - (attr.span(), *a) - } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr { - (r.first().unwrap().1, sym::repr) - } else { - continue; - }; - - let item = tcx - .hir_free_items() - .map(|id| tcx.hir_item(id)) - .find(|item| !item.span.is_dummy()) // Skip prelude `use`s - .map(|item| errors::ItemFollowingInnerAttr { - span: item.ident.span, - kind: item.kind.descr(), - }); - let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { - span, - sugg_span: tcx - .sess - .source_map() - .span_to_snippet(span) - .ok() - .filter(|src| src.starts_with("#![")) - .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))), - name, - item, - }); + // This function should only be called with crate attributes + // which are inner attributes always but lets check to make sure + if attr.style == AttrStyle::Inner { + for attr_to_check in ATTRS_TO_CHECK { + if attr.has_name(*attr_to_check) { + let item = tcx + .hir_free_items() + .map(|id| tcx.hir_item(id)) + .find(|item| !item.span.is_dummy()) // Skip prelude `use`s + .map(|item| errors::ItemFollowingInnerAttr { + span: item.ident.span, + kind: item.kind.descr(), + }); + let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { + span: attr.span, + sugg_span: tcx + .sess + .source_map() + .span_to_snippet(attr.span) + .ok() + .filter(|src| src.starts_with("#![")) + .map(|_| { + attr.span + .with_lo(attr.span.lo() + BytePos(1)) + .with_hi(attr.span.lo() + BytePos(2)) + }), + name: *attr_to_check, + item, + }); - if let Attribute::Unparsed(p) = attr { - tcx.dcx().try_steal_replace_and_emit_err( - p.path.span, - StashKey::UndeterminedMacroResolution, - err, - ); - } else { - err.emit(); + if let AttrKind::Normal(ref p) = attr.kind { + tcx.dcx().try_steal_replace_and_emit_err( + p.path.span, + StashKey::UndeterminedMacroResolution, + err, + ); + } else { + err.emit(); + } + } + } } } } @@ -2770,7 +2795,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) for attr in attrs { if attr.has_name(sym::inline) { - tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() }); + tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span }); } } } @@ -2808,10 +2833,10 @@ fn check_duplicates( match seen.entry(attr.name_or_empty()) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, FutureWarnPreceding) { - let to_remove = entry.insert(attr.span()); - (to_remove, attr.span()) + let to_remove = entry.insert(attr.span); + (to_remove, attr.span) } else { - (attr.span(), *entry.get()) + (attr.span, *entry.get()) }; tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -2828,17 +2853,17 @@ fn check_duplicates( ); } Entry::Vacant(entry) => { - entry.insert(attr.span()); + entry.insert(attr.span); } } } ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, ErrorPreceding) { - let to_remove = entry.insert(attr.span()); - (to_remove, attr.span()) + let to_remove = entry.insert(attr.span); + (to_remove, attr.span) } else { - (attr.span(), *entry.get()) + (attr.span, *entry.get()) }; tcx.dcx().emit_err(errors::UnusedMultiple { this, @@ -2847,7 +2872,7 @@ fn check_duplicates( }); } Entry::Vacant(entry) => { - entry.insert(attr.span()); + entry.insert(attr.span); } }, } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 25e679a84601e..c2225ea1e642d 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -46,7 +46,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option { let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - attr::find_by_name(attrs, sym).map(|attr| attr.span()) + attr::find_by_name(attrs, sym).map(|attr| attr.span) } fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5f686f38babda..9bcdd2385470c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -582,6 +582,13 @@ pub(crate) struct NoMangle { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_repr_ident, code = E0565)] +pub(crate) struct ReprIdent { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflicting { @@ -729,6 +736,31 @@ pub(crate) struct Linkage { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_empty_confusables)] +pub(crate) struct EmptyConfusables { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_incorrect_meta_item, code = E0539)] +pub(crate) struct IncorrectMetaItem { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub suggestion: IncorrectMetaItemSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_incorrect_meta_item_suggestion, applicability = "maybe-incorrect")] +pub(crate) struct IncorrectMetaItemSuggestion { + #[suggestion_part(code = "\"")] + pub lo: Span, + #[suggestion_part(code = "\"")] + pub hi: Span, +} + #[derive(Diagnostic)] #[diag(passes_stability_promotable)] pub(crate) struct StabilityPromotable { @@ -1443,6 +1475,14 @@ pub(crate) struct ObjectLifetimeErr { pub repr: String, } +#[derive(Diagnostic)] +#[diag(passes_unrecognized_repr_hint, code = E0552)] +#[help] +pub(crate) struct UnrecognizedReprHint { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] pub(crate) enum AttrApplication { #[diag(passes_attr_application_enum, code = E0517)] @@ -1862,11 +1902,3 @@ pub(crate) struct NoSanitize<'a> { pub accepted_kind: &'a str, pub attr_str: &'a str, } - -// FIXME(jdonszelmann): move back to rustc_attr -#[derive(Diagnostic)] -#[diag(passes_rustc_const_stable_indirect_pairing)] -pub(crate) struct RustcConstStableIndirectPairing { - #[primary_span] - pub span: Span, -} diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 7353c1ead5a78..e123fbac1bee6 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,7 +4,7 @@ //! but are not declared in one single location (unlike lang features), which means we need to //! collect them instead. -use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince}; +use rustc_attr_parsing::VERSION_PLACEHOLDER; use rustc_hir::Attribute; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; @@ -26,29 +26,62 @@ impl<'tcx> LibFeatureCollector<'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> { - let (feature, level, span) = match attr { - Attribute::Parsed(AttributeKind::Stability { stability, span }) => { - (stability.feature, stability.level, *span) - } - Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => { - (stability.feature, stability.level, *span) - } - Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => { - (stability.feature, stability.level, *span) + let stab_attrs = [ + sym::stable, + sym::unstable, + sym::rustc_const_stable, + sym::rustc_const_unstable, + sym::rustc_default_body_unstable, + ]; + + // Find a stability attribute: one of #[stable(…)], #[unstable(…)], + // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable]. + if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { + if let Some(metas) = attr.meta_item_list() { + let mut feature = None; + let mut since = None; + for meta in metas { + if let Some(mi) = meta.meta_item() { + // Find the `feature = ".."` meta-item. + match (mi.name_or_empty(), mi.value_str()) { + (sym::feature, val) => feature = val, + (sym::since, val) => since = val, + _ => {} + } + } + } + + if let Some(s) = since + && s.as_str() == VERSION_PLACEHOLDER + { + since = Some(sym::env_CFG_RELEASE); + } + + if let Some(feature) = feature { + // This additional check for stability is to make sure we + // don't emit additional, irrelevant errors for malformed + // attributes. + let is_unstable = matches!( + *stab_attr, + sym::unstable + | sym::rustc_const_unstable + | sym::rustc_default_body_unstable + ); + if is_unstable { + return Some((feature, FeatureStability::Unstable, attr.span)); + } + if let Some(since) = since { + return Some((feature, FeatureStability::AcceptedSince(since), attr.span)); + } + } + // We need to iterate over the other attributes, because + // `rustc_const_unstable` is not mutually exclusive with + // the other stability attributes, so we can't just `break` + // here. } - _ => return None, - }; - - let feature_stability = match level { - StabilityLevel::Unstable { .. } => FeatureStability::Unstable, - StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { - StableSince::Version(v) => Symbol::intern(&v.to_string()), - StableSince::Current => sym::env_CFG_RELEASE, - StableSince::Err => return None, - }), - }; - - Some((feature, feature_stability, span)) + } + + None } fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 8a4bdf3875c4b..d92edf959aff4 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_parsing::{ - self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability, - StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, + UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -121,9 +121,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); - let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); - + let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs); let mut is_deprecated = false; if let Some((depr, span)) = &depr { is_deprecated = true; @@ -156,10 +154,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if inherit_deprecation.yes() && stab.is_unstable() { self.index.stab_map.insert(def_id, stab); if fn_sig.is_some_and(|s| s.header.is_const()) { - self.index.const_stab_map.insert( - def_id, - ConstStability::unmarked(const_stability_indirect, stab), - ); + let const_stab = + attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab); + self.index.const_stab_map.insert(def_id, const_stab); } } } @@ -174,9 +171,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // # Regular and body stability - let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); - let body_stab = - attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); + + let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); + let body_stab = attr::find_body_stability(self.tcx.sess, attrs); if let Some((depr, span)) = &depr && depr.is_since_rustc_version() @@ -185,7 +182,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span }); } - if let Some(body_stab) = body_stab { + if let Some((body_stab, _span)) = body_stab { // FIXME: check that this item can have body stability self.index.default_body_stab_map.insert(def_id, body_stab); @@ -263,10 +260,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp); // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const or the parent impl block is const. + // implied), check if the function/method is const. if let Some(fn_sig) = fn_sig && !fn_sig.header.is_const() && const_stab.is_some() @@ -288,7 +285,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Stable *language* features shouldn't be used as unstable library features. // (Not doing this for stable library features is checked by tidy.) if let Some(( - PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, + ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, const_span, )) = const_stab { @@ -300,17 +297,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Some((stab, span)) = &const_stab - && stab.is_const_stable() - && const_stability_indirect - { - self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span }); - } - // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. - let mut const_stab = const_stab - .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect)); + let mut const_stab = const_stab.map(|(stab, _span)| stab); // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && @@ -796,10 +785,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir().attrs(item.hir_id()); - let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); - - // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem - let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let stab = attr::find_stability(self.tcx.sess, attrs, item.span); + let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because @@ -830,7 +817,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // needs to have an error emitted. if features.const_trait_impl() && self.tcx.is_const_trait_impl(item.owner_id.to_def_id()) - && const_stab.is_some_and(|stab| stab.is_const_stable()) + && const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) { self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span }); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5271d03a6f617..41725d0c6a4f9 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -22,7 +22,6 @@ use errors::{ }; use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; -use rustc_attr_parsing::AttributeKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{MultiSpan, listify}; @@ -494,11 +493,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { // Non-opaque macros cannot make other items more accessible than they already are. let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir().attrs(hir_id); - - if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) - .unwrap_or(Transparency::fallback(md.macro_rules)) - != Transparency::Opaque - { + if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { return; } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index c85156e059e5a..d89e1355ca671 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start measureme = "11" -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 3e8ccb51021e1..839465f9273bb 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -9,7 +9,6 @@ parking_lot = "0.12" rustc-rayon-core = { version = "0.5.0" } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index e1b6adc6cc17d..cf50e61e72ba1 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -129,4 +129,3 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} -impl<'a> rustc_attr_data_structures::HashStableContext for StableHashingContext<'a> {} diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 1dcd5d9058f4e..7d508b8201bdf 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -2,7 +2,7 @@ //! from various crates in no particular order. use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir::{self as hir, HashIgnoredAttrId}; +use rustc_hir as hir; use rustc_span::SourceFile; use smallvec::SmallVec; @@ -23,7 +23,6 @@ impl<'a> HashStable> for [hir::Attribute] { .iter() .filter(|attr| { !attr.is_doc_comment() - // FIXME(jdonszelmann) have a better way to handle ignored attrs && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name)) }) .collect(); @@ -36,8 +35,19 @@ impl<'a> HashStable> for [hir::Attribute] { } impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { - fn hash_attr_id(&mut self, _id: &HashIgnoredAttrId, _hasher: &mut StableHasher) { - /* we don't hash HashIgnoredAttrId, we ignore them */ + fn hash_attr(&mut self, attr: &hir::Attribute, hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name))); + debug_assert!(!attr.is_doc_comment()); + + let hir::Attribute { kind, id: _, style, span } = attr; + if let hir::AttrKind::Normal(item) = kind { + item.hash_stable(self, hasher); + style.hash_stable(self, hasher); + span.hash_stable(self, hasher); + } else { + unreachable!(); + } } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 75972a71c8e57..5eb8e420fa4ed 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -3,7 +3,6 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -133,24 +132,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(def) => { let edition = i.span.edition(); - - // FIXME(jdonszelmann) make one of these in the resolver? - // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. - // Does that prevents errors from happening? maybe - let parser = AttributeParser::new( - &self.resolver.tcx.sess, - self.resolver.tcx.features(), - Vec::new(), - ); - let attrs = parser.parse_attribute_list( - &i.attrs, - i.span, - OmitDoc::Skip, - std::convert::identity, - ); - let macro_data = - self.resolver.compile_macro(def, i.ident, &attrs, i.span, i.id, edition); + self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition); let macro_kind = macro_data.ext.macro_kind(); opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 55db336d85f35..5db6f83f3ee51 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1806,7 +1806,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !def_id.is_local() && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) { - non_exhaustive = Some(attr.span()); + non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; err.subdiagnostic(label); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 984dfff3ea56e..a70def2f6c93c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,6 +5,7 @@ use std::cell::Cell; use std::mem; use std::sync::Arc; +use rustc_ast::attr::AttributeExt; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; @@ -1111,7 +1112,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, macro_def: &ast::MacroDef, ident: Ident, - attrs: &[rustc_hir::Attribute], + attrs: &[impl AttributeExt], span: Span, node_id: NodeId, edition: Edition, diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 900cd4243b13c..66488bc962594 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -8,7 +8,6 @@ bitflags = "2.5.0" tracing = "0.1" twox-hash = "1.6.3" rustc_abi = { path = "../rustc_abi" } -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index e088417d72e35..5f0c1afdf6420 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -468,7 +468,7 @@ pub(crate) fn encode_ty<'tcx>( )] tcx.dcx() .struct_span_err( - cfi_encoding.span(), + cfi_encoding.span, format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); @@ -519,7 +519,7 @@ pub(crate) fn encode_ty<'tcx>( )] tcx.dcx() .struct_span_err( - cfi_encoding.span(), + cfi_encoding.span, format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index acd3b75835105..71e7b9c04ca16 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::iter; use rustc_abi::HasDataLayout; -use rustc_hir::{Attribute, LangItem}; +use rustc_hir::LangItem; use rustc_middle::ty::layout::{ FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers, }; @@ -243,7 +243,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn tool_attrs( + fn get_attrs_by_path( &self, def_id: stable_mir::DefId, attr: &[stable_mir::Symbol], @@ -253,40 +253,30 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let did = tables[def_id]; let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect(); tcx.get_attrs_by_path(did, &attr_name) - .filter_map(|attribute| { - if let Attribute::Unparsed(u) = attribute { - let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); - Some(stable_mir::crate_def::Attribute::new( - attr_str, - u.span.stable(&mut *tables), - )) - } else { - None - } + .map(|attribute| { + let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) }) .collect() } - fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec { + fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let did = tables[def_id]; + let filter_fn = + move |a: &&rustc_hir::Attribute| matches!(a.kind, rustc_hir::AttrKind::Normal(_)); let attrs_iter = if let Some(did) = did.as_local() { - tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter() + tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else { - tcx.attrs_for_def(did).iter() + tcx.attrs_for_def(did).iter().filter(filter_fn) }; attrs_iter - .filter_map(|attribute| { - if let Attribute::Unparsed(u) = attribute { - let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); - Some(stable_mir::crate_def::Attribute::new( - attr_str, - u.span.stable(&mut *tables), - )) - } else { - None - } + .map(|attribute| { + let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); + let span = attribute.span; + stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) }) .collect() } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 84e89ff4b7dab..9bf1d305e5413 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -175,12 +175,6 @@ pub enum Transparency { Opaque, } -impl Transparency { - pub fn fallback(macro_rules: bool) -> Self { - if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque } - } -} - impl LocalExpnId { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. pub const ROOT: LocalExpnId = LocalExpnId::ZERO; diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 90ddf4c8a0403..12fe6b719f9b8 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -9,7 +9,6 @@ punycode = "0.4.0" rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index ddeeadff13d17..7fda81126c443 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -62,18 +62,18 @@ impl SymbolNamesTest<'_> { ); let mangled = tcx.symbol_name(instance); tcx.dcx().emit_err(TestOutput { - span: attr.span(), + span: attr.span, kind: Kind::SymbolName, content: format!("{mangled}"), }); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { tcx.dcx().emit_err(TestOutput { - span: attr.span(), + span: attr.span, kind: Kind::Demangling, content: format!("{demangling}"), }); tcx.dcx().emit_err(TestOutput { - span: attr.span(), + span: attr.span, kind: Kind::DemanglingAlt, content: format!("{demangling:#}"), }); @@ -82,7 +82,7 @@ impl SymbolNamesTest<'_> { for attr in tcx.get_attrs(def_id, DEF_PATH) { tcx.dcx().emit_err(TestOutput { - span: attr.span(), + span: attr.span, kind: Kind::DefPath, content: with_no_trimmed_paths!(tcx.def_path_str(def_id)), }); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 514615735a507..36726cc6cae0d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -522,8 +522,7 @@ impl Trait for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = - tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span()); + let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index f0c6e51f2a4c4..518323f6526a6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AttrArgs, Attribute}; +use rustc_hir::{AttrArgs, AttrKind, Attribute}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -622,14 +622,7 @@ impl<'tcx> OnUnimplementedDirective { item_def_id: DefId, ) -> Result, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { - Self::parse( - tcx, - item_def_id, - &items, - attr.span(), - true, - is_diagnostic_namespace_variant, - ) + Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) } else if let Some(value) = attr.value_str() { if !is_diagnostic_namespace_variant { Ok(Some(OnUnimplementedDirective { @@ -640,7 +633,7 @@ impl<'tcx> OnUnimplementedDirective { tcx, item_def_id, value, - attr.span(), + attr.span, is_diagnostic_namespace_variant, )?), notes: Vec::new(), @@ -666,14 +659,14 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } } else if is_diagnostic_namespace_variant { - match attr { - Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => { + match &attr.kind { + AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span(), - MalformedOnUnimplementedAttrLint::new(attr.span()), + attr.span, + MalformedOnUnimplementedAttrLint::new(attr.span), ); } } @@ -682,7 +675,7 @@ impl<'tcx> OnUnimplementedDirective { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span(), + attr.span, MissingOptionsForOnUnimplementedAttr, ) } diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index e82c957c34ea6..a6f7c254583e2 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -62,17 +62,14 @@ pub trait Context { /// Returns the name of given `DefId` fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; - /// Return registered tool attributes with the given attribute name. + /// Return attributes with the given attribute name. /// - /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool - /// attributes will simply return an empty list. - /// - /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec; + fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec; - /// Get all tool attributes of a definition. - fn all_tool_attrs(&self, def_id: DefId) -> Vec; + /// Get all attributes of a definition. + fn get_all_attrs(&self, def_id: DefId) -> Vec; /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index 8c6fd99f98a1c..cf29176dbbdda 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -53,22 +53,19 @@ pub trait CrateDef { with(|cx| cx.span_of_an_item(def_id)) } - /// Return registered tool attributes with the given attribute name. + /// Return attributes with the given attribute name. /// - /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool - /// attributes will simply return an empty list. - /// - /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. + /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn tool_attrs(&self, attr: &[Symbol]) -> Vec { + fn attrs_by_path(&self, attr: &[Symbol]) -> Vec { let def_id = self.def_id(); - with(|cx| cx.tool_attrs(def_id, attr)) + with(|cx| cx.get_attrs_by_path(def_id, attr)) } - /// Return all tool attributes of this definition. - fn all_tool_attrs(&self) -> Vec { + /// Return all attributes of this definition. + fn all_attrs(&self) -> Vec { let def_id = self.def_id(); - with(|cx| cx.all_tool_attrs(def_id)) + with(|cx| cx.get_all_attrs(def_id)) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ceffe5e5ce04e..dcc5fd12d81bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2737,13 +2737,13 @@ fn add_without_unwanted_attributes<'hir>( import_parent: Option, ) { for attr in new_attrs { - if attr.is_doc_comment() { + if matches!(attr.kind, hir::AttrKind::DocComment(..)) { attrs.push((Cow::Borrowed(attr), import_parent)); continue; } let mut attr = attr.clone(); - match attr { - hir::Attribute::Unparsed(ref mut normal) => { + match attr.kind { + hir::AttrKind::Normal(ref mut normal) => { if let [ident] = &*normal.path.segments { let ident = ident.name; if ident == sym::doc { @@ -2755,11 +2755,7 @@ fn add_without_unwanted_attributes<'hir>( } } } - hir::Attribute::Parsed(..) => { - if is_inline { - attrs.push((Cow::Owned(attr), import_parent)); - } - } + _ => unreachable!(), } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 178b6a60b41f7..fc7c4b42047db 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -265,7 +265,7 @@ impl ExternalCrate { let attr_value = attr.value_str().expect("syntax should already be validated"); let Some(prim) = PrimitiveType::from_symbol(attr_value) else { span_bug!( - attr.span(), + attr.span, "primitive `{attr_value}` is not a member of `PrimitiveType`" ); }; diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 3ac7abd0aa5d0..1ac3c040b5918 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -123,7 +123,7 @@ impl HirCollector<'_> { .iter() .find(|attr| attr.doc_str().is_some()) .map(|attr| { - attr.span().ctxt().outer_expn().expansion_cause().unwrap_or(attr.span()) + attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span) }) .unwrap_or(DUMMY_SP) }; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 8f6496e9626c8..a92f3ded77466 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 40; +pub const FORMAT_VERSION: u32 = 39; /// The root of the emitted JSON blob. /// @@ -120,9 +120,7 @@ pub struct Item { pub docs: Option, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: HashMap, - /// Stringified versions of parsed attributes on this item. - /// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`). - /// Equivalent to the hir pretty-printing of attributes. + /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, diff --git a/src/tools/cargo b/src/tools/cargo index ce948f4616e3d..1d1d646c06a84 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ce948f4616e3d4277e30c75c8bb01e094910df39 +Subproject commit 1d1d646c06a84c1aa53967b394b7f1218f85db82 diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index cb63fadb4e21c..2325f914b0b0c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att span_lint( cx, INLINE_ALWAYS, - attr.span(), + attr.span, format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs index 6cc47596bbb61..6d1ab46aa0c1f 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs @@ -1,7 +1,6 @@ -use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr}; use rustc_hir::Attribute; use rustc_lint::LateContext; -use rustc_span::Span; +use rustc_span::{Span, sym}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs; @@ -15,21 +14,30 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], } fn check_packed(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { - if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) { - let packed_span = reprs.iter().find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))).map(|(_, s)| *s); - - if let Some(packed_span) = packed_span && !reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC || *x == ReprAttr::ReprRust) { - span_lint_and_then( - cx, - REPR_PACKED_WITHOUT_ABI, - item_span, - "item uses `packed` representation without ABI-qualification", - |diag| { - diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI") - .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") - .span_label(packed_span, "`packed` representation set here"); - }, - ); + if let Some(items) = attrs.iter().find_map(|attr| { + if attr.ident().is_some_and(|ident| matches!(ident.name, sym::repr)) { + attr.meta_item_list() + } else { + None } + }) && let Some(packed) = items + .iter() + .find(|item| item.ident().is_some_and(|ident| matches!(ident.name, sym::packed))) + && !items.iter().any(|item| { + item.ident() + .is_some_and(|ident| matches!(ident.name, sym::C | sym::Rust)) + }) + { + span_lint_and_then( + cx, + REPR_PACKED_WITHOUT_ABI, + item_span, + "item uses `packed` representation without ABI-qualification", + |diag| { + diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI") + .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") + .span_label(packed.span(), "`packed` representation set here"); + }, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 6ee3290fa761d..478ba7a187be5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -15,7 +15,7 @@ pub(super) fn check( ) { if cfg_attr.has_name(sym::clippy) && let Some(ident) = behind_cfg_attr.ident() - && Level::from_symbol(ident.name, || Some(attr.id)).is_some() + && Level::from_symbol(ident.name, Some(attr.id)).is_some() && let Some(items) = behind_cfg_attr.meta_item_list() { let nb_items = items.len(); diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 0e650e4939252..a667649f73435 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -17,7 +17,7 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool { } pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { - Level::from_symbol(symbol, || Some(attr_id)).is_some() + Level::from_symbol(symbol, Some(attr_id)).is_some() } pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 6e6d81db11c04..9f020d3081c40 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; -use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr}; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, FieldDef}; use rustc_session::declare_lint_pass; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -97,7 +97,16 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR } fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - let attrs = cx.tcx.hir().attrs(hir_id); - - find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC)) + cx.tcx.hir().attrs(hir_id).iter().any(|attr| { + if attr.has_name(sym::repr) { + if let Some(items) = attr.meta_item_list() { + for item in items { + if item.is_word() && matches!(item.name_or_empty(), sym::C) { + return true; + } + } + } + } + false + }) } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 6de16e306c9ae..4e8853821c3ef 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -1,4 +1,3 @@ - use clippy_config::Conf; use clippy_config::types::create_disallowed_map; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs index aa29705cf9386..4b40fc0b1ee2c 100644 --- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,17 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use rustc_ast::AttrStyle; use rustc_errors::Applicability; -use rustc_lint::EarlyContext; -use rustc_ast::{Attribute, AttrKind, AttrArgs, AttrStyle}; +use rustc_hir::{AttrArgs, AttrKind, Attribute}; +use rustc_lint::LateContext; use super::DOC_INCLUDE_WITHOUT_CFG; -pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { for attr in attrs { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrArgs::Eq { expr: meta, .. } = &item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 42192801af7c4..713d62a8801d8 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_resolve::rustdoc::{ @@ -577,13 +577,6 @@ impl_lint_pass!(Documentation => [ DOC_INCLUDE_WITHOUT_CFG, ]); - -impl EarlyLintPass for Documentation { - fn check_attributes(&mut self, cx: &EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) { - include_in_doc_without_cfg::check(cx, attrs); - } -} - impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { @@ -711,13 +704,14 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } + include_in_doc_without_cfg::check(cx, attrs); if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) { return None; } let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { - if !attr.doc_str_and_comment_kind().is_some() || attr.span().in_external_macro(cx.sess().source_map()) { + if attr.span.in_external_macro(cx.sess().source_map()) { None } else { Some((attr, None)) diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index bfc36deea7b29..84393213e6f06 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -3,7 +3,6 @@ use rustc_ast::AttrStyle; use rustc_ast::token::CommentKind; use rustc_errors::Applicability; use rustc_hir::Attribute; -use rustc_attr_parsing::AttributeKind; use rustc_lint::LateContext; use rustc_span::Span; @@ -37,14 +36,15 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { attrs .iter() .filter_map(|attr| { - if let Attribute::Parsed(AttributeKind::DocComment{ style: AttrStyle::Outer, kind, comment, ..}) = attr - && let Some(com) = comment.as_str().strip_prefix('!') + if let Some((sym, com_kind)) = attr.doc_str_and_comment_kind() + && let AttrStyle::Outer = attr.style + && let Some(com) = sym.as_str().strip_prefix('!') { - let sugg = match kind { + let sugg = match com_kind { CommentKind::Line => format!("//!{com}"), CommentKind::Block => format!("/*!{com}*/"), }; - Some((attr.span(), sugg)) + Some((attr.span, sugg)) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index 1eda73a96727d..1f89cab91480e 100644 --- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -1,6 +1,5 @@ use rustc_errors::Applicability; use rustc_hir::{Attribute, Item, ItemKind}; -use rustc_attr_parsing::AttributeKind; use rustc_lint::LateContext; use clippy_utils::diagnostics::span_lint_and_then; @@ -44,9 +43,9 @@ pub(super) fn check( let mut should_suggest_empty_doc = false; for attr in attrs { - if let Attribute::Parsed(AttributeKind::DocComment {span, comment, ..}) = attr { - spans.push(span); - let doc = comment.as_str(); + if let Some(doc) = attr.doc_str() { + spans.push(attr.span); + let doc = doc.as_str(); let doc = doc.trim(); if spans.len() == 1 { // We make this suggestion only if the first doc line ends with a punctuation @@ -79,7 +78,7 @@ pub(super) fn check( && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && let Some(snippet) = snippet_opt(cx, new_span) { - let Some(first) = snippet_opt(cx, *first_span) else { + let Some(first) = snippet_opt(cx, first_span) else { return; }; let Some(comment_form) = first.get(..3) else { diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs index 0bdb99d7b9a4d..0599e08e6c0af 100644 --- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs +++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs @@ -46,8 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes { .hir() .attrs(item.hir_id()) .iter() - .filter(|i| i.is_doc_comment()) - .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span())); + .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span)); let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 0ed4426d6e92f..e6e3ea59a9f67 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -95,7 +95,6 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr } } -// FIXME: needs to be an EARLY LINT. all attribute lints should be #[allow(clippy::too_many_arguments)] fn check_needless_must_use( cx: &LateContext<'_>, @@ -118,22 +117,38 @@ fn check_needless_must_use( fn_header_span, "this unit-returning function has a `#[must_use]` attribute", |diag| { - diag.span_suggestion(attr.span(), "remove the attribute", "", Applicability::MachineApplicable); + diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); }, ); } else { // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see // issue #12320. - // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile, - // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this could be - // re-added. - span_lint_and_help( + span_lint_and_then( cx, - DOUBLE_MUST_USE, + MUST_USE_UNIT, fn_header_span, "this unit-returning function has a `#[must_use]` attribute", - Some(attr.span()), - "remove `must_use`", + |diag| { + let mut attrs_without_must_use = attrs.to_vec(); + attrs_without_must_use.retain(|a| a.id != attr.id); + let sugg_str = attrs_without_must_use + .iter() + .map(|a| { + if a.value_str().is_none() { + return a.name_or_empty().to_string(); + } + format!("{} = \"{}\"", a.name_or_empty(), a.value_str().unwrap()) + }) + .collect::>() + .join(", "); + + diag.span_suggestion( + attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()), + "change these attributes to", + sugg_str, + Applicability::MachineApplicable, + ); + }, ); } } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 5b58113169b1e..39ff3c13bcce9 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -183,7 +183,7 @@ fn suggestion<'tcx>( fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span { if let Some(attr) = tcx.hir().attrs(field.hir_id).first() { - field.span.with_lo(attr.span().lo()) + field.span.with_lo(attr.span.lo()) } else { field.span } diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 9b4a3b3f9c84c..1b900f6be8e85 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -42,10 +42,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { span_lint_and_then( cx, INLINE_FN_WITHOUT_BODY, - attr.span(), + attr.span, format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), |diag| { - diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable); + diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index 53dc070833b52..f3d62b513e840 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -3,11 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_opt; use rustc_ast::LitKind; -use rustc_hir::{Expr, ExprKind}; -use rustc_ast::{Attribute, AttrArgs, AttrKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; +use rustc_hir::{AttrArgs, AttrKind, Attribute, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -53,6 +52,24 @@ impl LargeIncludeFile { impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); +impl LargeIncludeFile { + fn emit_lint(&self, cx: &LateContext<'_>, span: Span) { + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + LARGE_INCLUDE_FILE, + span, + "attempted to include a large file", + |diag| { + diag.note(format!( + "the configuration allows a maximum size of {} bytes", + self.max_file_size + )); + }, + ); + } +} + impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { if let ExprKind::Lit(lit) = &expr.kind @@ -68,32 +85,18 @@ impl LateLintPass<'_> for LargeIncludeFile { && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - LARGE_INCLUDE_FILE, - expr.span.source_callsite(), - "attempted to include a large file", - |diag| { - diag.note(format!( - "the configuration allows a maximum size of {} bytes", - self.max_file_size - )); - }, - ); + self.emit_lint(cx, expr.span.source_callsite()); } } -} -impl EarlyLintPass for LargeIncludeFile { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) { if !attr.span.from_expansion() // Currently, rustc limits the usage of macro at the top-level of attributes, // so we don't need to recurse into each level. && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.item.args + && let AttrArgs::Eq { expr: meta, .. } = &item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. @@ -110,19 +113,7 @@ impl EarlyLintPass for LargeIncludeFile { && let sub_snippet = sub_snippet.trim() && (sub_snippet.starts_with("include_str!") || sub_snippet.starts_with("include_bytes!")) { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - LARGE_INCLUDE_FILE, - attr.span, - "attempted to include a large file", - |diag| { - diag.note(format!( - "the configuration allows a maximum size of {} bytes", - self.max_file_size - )); - }, - ); + self.emit_lint(cx, attr.span); } } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 177f83921cd54..13218331a67b2 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -407,9 +407,9 @@ mod zombie_processes; use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; -use utils::attr_collector::{AttrCollector, AttrStorage}; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; +use utils::attr_collector::{AttrCollector, AttrStorage}; /// Register all pre expansion lints /// @@ -717,7 +717,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf))); store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf))); store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf))); - store.register_early_pass(move || Box::new(doc::Documentation::new(conf))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); @@ -861,7 +860,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf))); - store.register_early_pass(move || Box::new(large_include_file::LargeIncludeFile::new(conf))); store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::::default()); diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 165e8c2ea05aa..3741286653929 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -94,7 +94,7 @@ impl LateLintPass<'_> for MacroUseImports { { for kid in cx.tcx.module_children(id) { if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { - let span = mac_attr.span(); + let span = mac_attr.span; let def_path = cx.tcx.def_path_str(mac_id); self.imports.push((def_path, span, hir_id)); } @@ -104,8 +104,8 @@ impl LateLintPass<'_> for MacroUseImports { } } fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) { - if attr.span().from_expansion() { - self.push_unique_macro(cx, attr.span()); + if attr.span.from_expansion() { + self.push_unique_macro(cx, attr.span); } } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 83d8a50939069..00800231fe46e 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { if let Some(non_exhaustive) = attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) { - diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive"); + diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive"); } else { let indent = snippet_indent(cx, item.span).unwrap_or_default(); diag.span_suggestion_verbose( diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index 6eca3f12cf252..b73b9083a9919 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); - let attr_snippet = snippet(cx, attr.span(), ".."); + let attr_snippet = snippet(cx, attr.span, ".."); span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 16916e3aaad57..93abf95e35773 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -432,7 +432,7 @@ fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Spa .hir() .attrs(hir_id) .iter() - .fold(span, |acc, attr| acc.to(attr.span()))) + .fold(span, |acc, attr| acc.to(attr.span))) } enum HasSafetyComment { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7fc25e3617d07..40ddd75b7fad1 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -93,7 +93,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; -use rustc_attr_parsing::{find_attr, AttributeKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; @@ -1950,7 +1949,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool { } pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - find_attr!(cx.tcx.hir().attrs(hir_id), AttributeKind::Repr(..)) + has_attr(cx.tcx.hir().attrs(hir_id), sym::repr) } pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool { diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr index c9f0e661dbd18..82b926cc53ba2 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr @@ -1,26 +1,26 @@ error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:19:1 + --> tests/ui-toml/large_include_file/large_include_file.rs:14:43 | -LL | #[doc = include_str!("too_big.txt")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes = note: `-D clippy::large-include-file` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]` error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:14:43 + --> tests/ui-toml/large_include_file/large_include_file.rs:16:35 | -LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:16:35 + --> tests/ui-toml/large_include_file/large_include_file.rs:19:1 | -LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc = include_str!("too_big.txt")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index 7e2a72960492c..b92d9379c904b 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -24,3 +24,8 @@ fn main() { ); } +#[cfg_attr(all(), deprecated)] +fn issue_12320() {} + +#[cfg_attr(all(), deprecated, doc = "foo")] +fn issue_12320_2() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs index f41b1a7c80051..c77e728275048 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.rs +++ b/src/tools/clippy/tests/ui/must_use_unit.rs @@ -27,3 +27,8 @@ fn main() { ); } +#[cfg_attr(all(), must_use, deprecated)] +fn issue_12320() {} + +#[cfg_attr(all(), deprecated, doc = "foo", must_use)] +fn issue_12320_2() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr index c2ee2edda7dc5..b435568deeab8 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.stderr +++ b/src/tools/clippy/tests/ui/must_use_unit.stderr @@ -25,5 +25,21 @@ LL | #[must_use = "With note"] LL | pub fn must_use_with_note() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit.rs:31:1 + | +LL | #[cfg_attr(all(), must_use, deprecated)] + | -------------------- help: change these attributes to: `deprecated` +LL | fn issue_12320() {} + | ^^^^^^^^^^^^^^^^ + +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit.rs:34:1 + | +LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)] + | --------------------------------- help: change these attributes to: `deprecated, doc = "foo"` +LL | fn issue_12320_2() {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/must_use_unit_12320.rs b/src/tools/clippy/tests/ui/must_use_unit_12320.rs deleted file mode 100644 index 39dcafdb38b5e..0000000000000 --- a/src/tools/clippy/tests/ui/must_use_unit_12320.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@aux-build:proc_macros.rs -//@no-rustfix - -#![warn(clippy::must_use_unit)] -#![allow(clippy::unused_unit)] - -#[cfg_attr(all(), must_use, deprecated)] -fn issue_12320() {} - -#[cfg_attr(all(), deprecated, doc = "foo", must_use)] -fn issue_12320_2() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit_12320.stderr b/src/tools/clippy/tests/ui/must_use_unit_12320.stderr deleted file mode 100644 index b3e1cbc045765..0000000000000 --- a/src/tools/clippy/tests/ui/must_use_unit_12320.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit_12320.rs:8:1 - | -LL | fn issue_12320() {} - | ^^^^^^^^^^^^^^^^ - | -help: remove `must_use` - --> tests/ui/must_use_unit_12320.rs:7:19 - | -LL | #[cfg_attr(all(), must_use, deprecated)] - | ^^^^^^^^ - = note: `-D clippy::double-must-use` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` - -error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit_12320.rs:11:1 - | -LL | fn issue_12320_2() {} - | ^^^^^^^^^^^^^^^^^^ - | -help: remove `must_use` - --> tests/ui/must_use_unit_12320.rs:10:44 - | -LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)] - | ^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp deleted file mode 100644 index 586810b004662..0000000000000 --- a/tests/pretty/hir-pretty-attr.pp +++ /dev/null @@ -1,11 +0,0 @@ -#[prelude_import] -use ::std::prelude::rust_2015::*; -#[macro_use] -extern crate std; -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:hir-pretty-attr.pp - -#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")] -struct Example { -} diff --git a/tests/pretty/hir-pretty-attr.rs b/tests/pretty/hir-pretty-attr.rs deleted file mode 100644 index eb5a677024a8e..0000000000000 --- a/tests/pretty/hir-pretty-attr.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:hir-pretty-attr.pp - -#[repr(C, packed(4))] -#[repr(transparent)] -struct Example {} diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index 24d5f5b08c203..0ac40cda73388 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength #[repr(i32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(SignedInt(I32))])\")]\n"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' pub enum Foo { //@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index a50ae8b9189f6..fbff5aacd6741 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength #[repr(u32)] -//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(UnsignedInt(U32))])\")]\n"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' pub enum Foo { //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index de5ba15f6ea4e..11cb63f3f8a58 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -27,23 +27,63 @@ fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); + test_builtins(&items); + test_derive(&items); test_tool(&items); + test_all_attrs(&items); ControlFlow::Continue(()) } +// Test built-in attributes. +fn test_builtins(items: &CrateItems) { + let target_fn = *get_item(&items, "builtins_fn").unwrap(); + let allow_attrs = target_fn.attrs_by_path(&["allow".to_string()]); + assert_eq!(allow_attrs[0].as_str(), "#![allow(unused_variables)]"); + + let inline_attrs = target_fn.attrs_by_path(&["inline".to_string()]); + assert_eq!(inline_attrs[0].as_str(), "#[inline]"); + + let deprecated_attrs = target_fn.attrs_by_path(&["deprecated".to_string()]); + assert_eq!(deprecated_attrs[0].as_str(), "#[deprecated(since = \"5.2.0\")]"); +} + +// Test derive attribute. +fn test_derive(items: &CrateItems) { + let target_struct = *get_item(&items, "Foo").unwrap(); + let attrs = target_struct.attrs_by_path(&["derive".to_string()]); + // No `derive` attribute since it's expanded before MIR. + assert_eq!(attrs.len(), 0); + + // Check derived trait method's attributes. + let derived_fmt = *get_item(&items, "::fmt").unwrap(); + // The Rust reference lies about this attribute. It doesn't show up in `clone` or `fmt` impl. + let _fmt_attrs = derived_fmt.attrs_by_path(&["automatically_derived".to_string()]); +} + // Test tool attributes. fn test_tool(items: &CrateItems) { let rustfmt_fn = *get_item(&items, "do_not_format").unwrap(); - let rustfmt_attrs = rustfmt_fn.tool_attrs(&["rustfmt".to_string(), "skip".to_string()]); + let rustfmt_attrs = rustfmt_fn.attrs_by_path(&["rustfmt".to_string(), "skip".to_string()]); assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]"); let clippy_fn = *get_item(&items, "complex_fn").unwrap(); - let clippy_attrs = clippy_fn.tool_attrs(&["clippy".to_string(), + let clippy_attrs = clippy_fn.attrs_by_path(&["clippy".to_string(), "cyclomatic_complexity".to_string()]); assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]"); } +fn test_all_attrs(items: &CrateItems) { + let target_fn = *get_item(&items, "many_attrs").unwrap(); + let all_attrs = target_fn.all_attrs(); + assert_eq!(all_attrs[0].as_str(), "#[inline]"); + assert_eq!(all_attrs[1].as_str(), "#[allow(unused_variables)]"); + assert_eq!(all_attrs[2].as_str(), "#[allow(dead_code)]"); + assert_eq!(all_attrs[3].as_str(), "#[allow(unused_imports)]"); + assert_eq!(all_attrs[4].as_str(), "#![allow(clippy::filter_map)]"); +} + + fn get_item<'a>( items: &'a CrateItems, name: &str, diff --git a/tests/ui/attributes/arg-error-issue-121425.stderr b/tests/ui/attributes/arg-error-issue-121425.stderr index 6e71f15fdc872..1beb99b1703cf 100644 --- a/tests/ui/attributes/arg-error-issue-121425.stderr +++ b/tests/ui/attributes/arg-error-issue-121425.stderr @@ -1,9 +1,3 @@ -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/arg-error-issue-121425.rs:16:8 - | -LL | #[repr(align())] - | ^^^^^^^ - error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument --> $DIR/arg-error-issue-121425.rs:4:14 | @@ -22,6 +16,12 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer LL | #[repr(align("str"))] | ^^^^^ +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/arg-error-issue-121425.rs:16:8 + | +LL | #[repr(align())] + | ^^^^^^^ + error[E0552]: incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument --> $DIR/arg-error-issue-121425.rs:21:15 | diff --git a/tests/ui/attributes/issue-100631.stderr b/tests/ui/attributes/issue-100631.stderr index b2bd0a9632513..6e8e4f3b418fb 100644 --- a/tests/ui/attributes/issue-100631.stderr +++ b/tests/ui/attributes/issue-100631.stderr @@ -1,8 +1,8 @@ error[E0084]: unsupported representation for zero-variant enum - --> $DIR/issue-100631.rs:4:8 + --> $DIR/issue-100631.rs:4:1 | LL | #[repr(C)] - | ^ + | ^^^^^^^^^^ LL | #[repr(C)] LL | enum Foo {} | -------- zero-variant enum diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs deleted file mode 100644 index 4aaad01b7235e..0000000000000 --- a/tests/ui/attributes/malformed-fn-align.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(fn_align)] -#![crate_type = "lib"] - -trait MyTrait { - #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument - fn myfun(); -} diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr deleted file mode 100644 index 57913c48ef787..0000000000000 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/malformed-fn-align.rs:5:12 - | -LL | #[repr(align)] - | ^^^^^ help: supply an argument here: `align(...)` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed index d8b5235c52fbe..7224d4289e3fa 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed @@ -3,7 +3,7 @@ //@ check-pass #![warn(unused_attributes)] -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "foo"] pub fn bar() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs index 83a673a7d1328..149a7904e1ea5 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs @@ -4,7 +4,7 @@ #![warn(unused_attributes)] #[no_mangle] -//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] #[export_name = "foo"] pub fn bar() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr index c760d27db2513..ba63127ba2db8 100644 --- a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr @@ -1,8 +1,8 @@ -warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` +warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]` --> $DIR/mixed_export_name_and_no_mangle.rs:6:1 | LL | #[no_mangle] - | ^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | ^^^^^^^^^^^^ `#[no_mangle]` is ignored | note: `#[export_name]` takes precedence --> $DIR/mixed_export_name_and_no_mangle.rs:8:1 @@ -14,7 +14,7 @@ note: the lint level is defined here | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -help: remove the `#[unsafe(no_mangle)]` attribute +help: remove the `#[no_mangle]` attribute | LL - #[no_mangle] | diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 5ea30bb8627b4..1b2e92a31703c 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -6,7 +6,6 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] //~^ ERROR expected unsuffixed literal, found `n!()` - //~^^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] struct S; }; } @@ -16,5 +15,6 @@ macro_rules! n { } pass_nonterminal!(n!()); +//~^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] fn main() {} diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index cce5c453d5203..b640575d17dc7 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -10,15 +10,10 @@ LL | pass_nonterminal!(n!()); = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument - --> $DIR/nonterminal-expansion.rs:7:22 + --> $DIR/nonterminal-expansion.rs:17:19 | -LL | #[repr(align($n))] - | ^^ -... LL | pass_nonterminal!(n!()); - | ----------------------- in this macro invocation - | - = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^ error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/repr-align-in-trait-issue-132391.rs b/tests/ui/attributes/repr-align-in-trait-issue-132391.rs deleted file mode 100644 index b3b79e93e9bd8..0000000000000 --- a/tests/ui/attributes/repr-align-in-trait-issue-132391.rs +++ /dev/null @@ -1,6 +0,0 @@ -trait MyTrait { - #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument - fn myfun(); -} - -pub fn main() {} diff --git a/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr b/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr deleted file mode 100644 index 4208b018f52f0..0000000000000 --- a/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/repr-align-in-trait-issue-132391.rs:2:12 - | -LL | #[repr(align)] - | ^^^^^ help: supply an argument here: `align(...)` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index 55c9219a08a84..dc71d974daf56 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -4,6 +4,12 @@ error: malformed `rustc_confusables` attribute input LL | #[rustc_confusables] | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` +error: attribute should be applied to an inherent method + --> $DIR/rustc_confusables.rs:45:1 + | +LL | #[rustc_confusables("blah")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: expected at least one confusable name --> $DIR/rustc_confusables.rs:30:5 | @@ -21,12 +27,6 @@ help: consider surrounding this with quotes LL | #[rustc_confusables("invalid_meta_item")] | + + -error: attribute should be applied to an inherent method - --> $DIR/rustc_confusables.rs:45:1 - | -LL | #[rustc_confusables("blah")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0599]: no method named `inser` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope --> $DIR/rustc_confusables.rs:12:7 | diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index d5b149b18ed6a..9ea75b68f81ce 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -4,16 +4,16 @@ mod bogus_attribute_types_1 { #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' fn f1() { } - #[deprecated(since = "a", note)] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note)] //~ ERROR incorrect meta item fn f2() { } - #[deprecated(since, note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since, note = "a")] //~ ERROR incorrect meta item fn f3() { } - #[deprecated(since = "a", note(b))] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note(b))] //~ ERROR incorrect meta item fn f5() { } - #[deprecated(since(b), note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since(b), note = "a")] //~ ERROR incorrect meta item fn f6() { } #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 53047d40cb2ff..383212ad9b4b8 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -1,28 +1,40 @@ +error: multiple `deprecated` attributes + --> $DIR/deprecation-sanity.rs:27:1 + | +LL | #[deprecated(since = "a", note = "b")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/deprecation-sanity.rs:26:1 + | +LL | #[deprecated(since = "a", note = "b")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0541]: unknown meta item 'reason' --> $DIR/deprecation-sanity.rs:4:43 | LL | #[deprecated(since = "a", note = "a", reason)] | ^^^^^^ expected one of `since`, `note` -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/deprecation-sanity.rs:7:31 | LL | #[deprecated(since = "a", note)] | ^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/deprecation-sanity.rs:10:18 | LL | #[deprecated(since, note = "a")] | ^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/deprecation-sanity.rs:13:31 | LL | #[deprecated(since = "a", note(b))] | ^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/deprecation-sanity.rs:16:18 | LL | #[deprecated(since(b), note = "a")] @@ -42,18 +54,6 @@ error[E0565]: item in `deprecated` must be a key/value pair LL | #[deprecated("test")] | ^^^^^^ -error: multiple `deprecated` attributes - --> $DIR/deprecation-sanity.rs:27:1 - | -LL | #[deprecated(since = "a", note = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/deprecation-sanity.rs:26:1 - | -LL | #[deprecated(since = "a", note = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0538]: multiple 'since' items --> $DIR/deprecation-sanity.rs:30:27 | diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs index c5433151a8fd2..6653bd15ddd2b 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs @@ -3,7 +3,7 @@ // was a well-formed `MetaItem`. fn main() { - foo() //~ WARNING use of deprecated function `foo` + foo() } #[deprecated(note = test)] diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr index 2ff8534b276c4..a030da5068c2d 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -9,13 +9,5 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[deprecated(note = "test")] | + + -warning: use of deprecated function `foo` - --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:6:5 - | -LL | foo() - | ^^^ - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0084.stderr b/tests/ui/error-codes/E0084.stderr index 3df2e4a322b2c..f1fbe6c2532b1 100644 --- a/tests/ui/error-codes/E0084.stderr +++ b/tests/ui/error-codes/E0084.stderr @@ -1,8 +1,8 @@ error[E0084]: unsupported representation for zero-variant enum - --> $DIR/E0084.rs:1:8 + --> $DIR/E0084.rs:1:1 | LL | #[repr(i32)] - | ^^^ + | ^^^^^^^^^^^^ LL | enum Foo {} | -------- zero-variant enum diff --git a/tests/ui/error-codes/E0565.stderr b/tests/ui/error-codes/E0565.stderr index 6e56600133d73..68f4a37dcff38 100644 --- a/tests/ui/error-codes/E0565.stderr +++ b/tests/ui/error-codes/E0565.stderr @@ -1,8 +1,8 @@ error[E0565]: meta item in `repr` must be an identifier - --> $DIR/E0565.rs:2:1 + --> $DIR/E0565.rs:2:8 | LL | #[repr("C")] - | ^^^^^^^^^^^^ + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs index 4a55e1743158d..08471e1b3f3e9 100644 --- a/tests/ui/error-codes/E0789.rs +++ b/tests/ui/error-codes/E0789.rs @@ -8,3 +8,5 @@ // #[stable(feature = "foo", since = "1.0")] struct Foo; //~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +//~^^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute +// FIXME: we shouldn't have two errors here, only occurs when using `-Zdeduplicate-diagnostics=no` diff --git a/tests/ui/error-codes/E0789.stderr b/tests/ui/error-codes/E0789.stderr index 23631ee1b03c3..6df9daafec76d 100644 --- a/tests/ui/error-codes/E0789.stderr +++ b/tests/ui/error-codes/E0789.stderr @@ -4,6 +4,14 @@ error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired LL | struct Foo; | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute + --> $DIR/E0789.rs:9:1 + | +LL | struct Foo; + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0789`. diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs index 81b7fe3db2ba8..8b13f1bf2788e 100644 --- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs +++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs @@ -1,9 +1,7 @@ // checks that this attribute is caught on non-macro items. // this needs a different test since this is done after expansion -// FIXME(jdonszelmann): empty attributes are currently ignored, since when its empty no actual -// change is applied. This should be fixed when later moving this check to attribute parsing. -#[allow_internal_unstable(something)] //~ ERROR allow_internal_unstable side-steps +#[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps //~| ERROR attribute should struct S; diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr index 076f2df28e3f3..28f1a0d6ed5ab 100644 --- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr +++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr @@ -1,17 +1,17 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks - --> $DIR/feature-gate-allow-internal-unstable-struct.rs:6:1 + --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1 | -LL | #[allow_internal_unstable(something)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[allow_internal_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(allow_internal_unstable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: attribute should be applied to a macro - --> $DIR/feature-gate-allow-internal-unstable-struct.rs:6:1 + --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1 | -LL | #[allow_internal_unstable(something)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[allow_internal_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct S; | --------- not a macro diff --git a/tests/ui/feature-gates/feature-gate-fn_align.rs b/tests/ui/feature-gates/feature-gate-fn_align.rs index 744877704dd11..06784a45d76c8 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.rs +++ b/tests/ui/feature-gates/feature-gate-fn_align.rs @@ -4,6 +4,6 @@ fn requires_alignment() {} trait MyTrait { - #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument + #[repr(align)] //~ ERROR `repr(align)` attributes on functions are unstable fn myfun(); } diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr index ff17c29fe0296..cd9900c605117 100644 --- a/tests/ui/feature-gates/feature-gate-fn_align.stderr +++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr @@ -1,9 +1,3 @@ -error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/feature-gate-fn_align.rs:7:12 - | -LL | #[repr(align)] - | ^^^^^ help: supply an argument here: `align(...)` - error[E0658]: `repr(align)` attributes on functions are unstable --> $DIR/feature-gate-fn_align.rs:3:8 | @@ -14,7 +8,16 @@ LL | #[repr(align(16))] = help: add `#![feature(fn_align)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: `repr(align)` attributes on functions are unstable + --> $DIR/feature-gate-fn_align.rs:7:12 + | +LL | #[repr(align)] + | ^^^^^ + | + = note: see issue #82232 for more information + = help: add `#![feature(fn_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error: aborting due to 2 previous errors -Some errors have detailed explanations: E0589, E0658. -For more information about an error, try `rustc --explain E0589`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 5c2a3ae699c03..648bafe646094 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -130,6 +130,21 @@ LL - #![rustc_main] LL + #[rustc_main] | +error: `repr` attribute cannot be used at crate level + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 + | +LL | #![repr()] + | ^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module + | +help: perhaps you meant to use an outer attribute + | +LL - #![repr()] +LL + #[repr()] + | + error: `path` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | @@ -160,21 +175,6 @@ LL - #![automatically_derived] LL + #[automatically_derived] | -error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 - | -LL | #![repr()] - | ^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![repr()] -LL + #[repr()] - | - error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17 | diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs index 381c1337148c9..35a2941633a48 100644 --- a/tests/ui/internal/internal-unstable.rs +++ b/tests/ui/internal/internal-unstable.rs @@ -7,7 +7,7 @@ extern crate internal_unstable; struct Baz { - #[allow_internal_unstable] //~ ERROR `allow_internal_unstable` expects a list of feature names + #[allow_internal_unstable] baz: u8, } @@ -56,7 +56,7 @@ fn main() { bar!(internal_unstable::unstable()); //~ ERROR use of unstable match true { - #[allow_internal_unstable] //~ ERROR `allow_internal_unstable` expects a list of feature names + #[allow_internal_unstable] _ => {} } diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr index bbf589d3f9268..ea74175f09b29 100644 --- a/tests/ui/internal/internal-unstable.stderr +++ b/tests/ui/internal/internal-unstable.stderr @@ -1,15 +1,3 @@ -error: `allow_internal_unstable` expects a list of feature names - --> $DIR/internal-unstable.rs:10:5 - | -LL | #[allow_internal_unstable] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `allow_internal_unstable` expects a list of feature names - --> $DIR/internal-unstable.rs:59:9 - | -LL | #[allow_internal_unstable] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0658]: use of unstable library feature `function` --> $DIR/internal-unstable.rs:48:25 | @@ -59,6 +47,6 @@ LL | bar!(internal_unstable::unstable()); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this error originates in the macro `foo` which comes from the expansion of the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index d629f199b223d..7bbb8ed2ca94c 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -10,22 +10,6 @@ error: malformed `repr` attribute input LL | let _z = #[repr] 1; | ^^^^^^^ help: must be of the form: `#[repr(C)]` -error[E0552]: unrecognized representation hint - --> $DIR/issue-43988.rs:14:12 - | -LL | #[repr(nothing)] - | ^^^^^^^ - | - = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` - -error[E0552]: unrecognized representation hint - --> $DIR/issue-43988.rs:18:12 - | -LL | #[repr(something_not_real)] - | ^^^^^^^^^^^^^^^^^^ - | - = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` - error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 | @@ -42,6 +26,22 @@ LL | #[inline(XYZ)] LL | let _b = 4; | ----------- not a function or closure +error[E0552]: unrecognized representation hint + --> $DIR/issue-43988.rs:14:12 + | +LL | #[repr(nothing)] + | ^^^^^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0552]: unrecognized representation hint + --> $DIR/issue-43988.rs:18:12 + | +LL | #[repr(something_not_real)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:30:5 | diff --git a/tests/ui/repr/invalid_repr_list_help.stderr b/tests/ui/repr/invalid_repr_list_help.stderr index 763ad9c27958f..e87cbd37a9930 100644 --- a/tests/ui/repr/invalid_repr_list_help.stderr +++ b/tests/ui/repr/invalid_repr_list_help.stderr @@ -30,14 +30,6 @@ LL | #[repr(uwu, u8)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` -error[E0552]: unrecognized representation hint - --> $DIR/invalid_repr_list_help.rs:19:8 - | -LL | #[repr(uwu)] - | ^^^ - | - = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` - error: unknown `doc` attribute `owo` --> $DIR/invalid_repr_list_help.rs:20:7 | @@ -46,6 +38,14 @@ LL | #[doc(owo)] | = note: `#[deny(invalid_doc_attributes)]` on by default +error[E0552]: unrecognized representation hint + --> $DIR/invalid_repr_list_help.rs:19:8 + | +LL | #[repr(uwu)] + | ^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0552`. diff --git a/tests/ui/repr/issue-83505-repr-simd.stderr b/tests/ui/repr/issue-83505-repr-simd.stderr index 57cfbeb95de87..44e154b4bb613 100644 --- a/tests/ui/repr/issue-83505-repr-simd.stderr +++ b/tests/ui/repr/issue-83505-repr-simd.stderr @@ -26,10 +26,10 @@ LL | enum Es {} | ---------- not a struct error[E0084]: unsupported representation for zero-variant enum - --> $DIR/issue-83505-repr-simd.rs:5:8 + --> $DIR/issue-83505-repr-simd.rs:5:1 | LL | #[repr(simd)] - | ^^^^ + | ^^^^^^^^^^^^^ ... LL | enum Es {} | ------- zero-variant enum diff --git a/tests/ui/repr/malformed-repr-hints.stderr b/tests/ui/repr/malformed-repr-hints.stderr index 7a6e9ccc73eb1..6fb927557619f 100644 --- a/tests/ui/repr/malformed-repr-hints.stderr +++ b/tests/ui/repr/malformed-repr-hints.stderr @@ -1,15 +1,3 @@ -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/malformed-repr-hints.rs:14:8 - | -LL | #[repr(align(2, 4))] - | ^^^^^^^^^^^ - -error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/malformed-repr-hints.rs:18:8 - | -LL | #[repr(align())] - | ^^^^^^^ - error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all --> $DIR/malformed-repr-hints.rs:6:8 | @@ -22,6 +10,18 @@ error[E0589]: invalid `repr(align)` attribute: `align` needs an argument LL | #[repr(align)] | ^^^^^ help: supply an argument here: `align(...)` +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/malformed-repr-hints.rs:14:8 + | +LL | #[repr(align(2, 4))] + | ^^^^^^^^^^^ + +error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses + --> $DIR/malformed-repr-hints.rs:18:8 + | +LL | #[repr(align())] + | ^^^^^^^ + error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list --> $DIR/malformed-repr-hints.rs:23:8 | diff --git a/tests/ui/repr/repr-align-assign.fixed b/tests/ui/repr/repr-align-assign.fixed index 96f9866611bc1..d40fcadf57b1b 100644 --- a/tests/ui/repr/repr-align-assign.fixed +++ b/tests/ui/repr/repr-align-assign.fixed @@ -3,9 +3,11 @@ #![allow(dead_code)] #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format + //~| ERROR incorrect `repr(align)` attribute format struct A(u64); #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format + //~| ERROR incorrect `repr(align)` attribute format struct B(u64); fn main() {} diff --git a/tests/ui/repr/repr-align-assign.rs b/tests/ui/repr/repr-align-assign.rs index 0b30ee6566461..3aff84a91f714 100644 --- a/tests/ui/repr/repr-align-assign.rs +++ b/tests/ui/repr/repr-align-assign.rs @@ -3,9 +3,11 @@ #![allow(dead_code)] #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format + //~| ERROR incorrect `repr(align)` attribute format struct A(u64); #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format + //~| ERROR incorrect `repr(align)` attribute format struct B(u64); fn main() {} diff --git a/tests/ui/repr/repr-align-assign.stderr b/tests/ui/repr/repr-align-assign.stderr index cc046e04de542..3606d02210ba0 100644 --- a/tests/ui/repr/repr-align-assign.stderr +++ b/tests/ui/repr/repr-align-assign.stderr @@ -5,11 +5,27 @@ LL | #[repr(align=8)] | ^^^^^^^ help: use parentheses instead: `align(8)` error[E0693]: incorrect `repr(align)` attribute format - --> $DIR/repr-align-assign.rs:8:8 + --> $DIR/repr-align-assign.rs:9:8 | LL | #[repr(align="8")] | ^^^^^^^^^ help: use parentheses instead: `align(8)` -error: aborting due to 2 previous errors +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:5:8 + | +LL | #[repr(align=8)] + | ^^^^^^^ help: use parentheses instead: `align(8)` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:9:8 + | +LL | #[repr(align="8")] + | ^^^^^^^^^ help: use parentheses instead: `align(8)` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0693`. diff --git a/tests/ui/repr/repr-align.rs b/tests/ui/repr/repr-align.rs index 6b60a765461ab..33aa727d4bd0e 100644 --- a/tests/ui/repr/repr-align.rs +++ b/tests/ui/repr/repr-align.rs @@ -1,33 +1,41 @@ #![allow(dead_code)] #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer + //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer struct S0(i32); #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two struct S1(i32); #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 + //~| ERROR: invalid `repr(align)` attribute: larger than 2^29 struct S2(i32); #[repr(align(536870912))] // ok: this is the largest accepted alignment struct S3(i32); #[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two struct S4(i32); #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer + //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer enum E0 { A, B } #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two enum E1 { A, B } #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29 + //~| ERROR: invalid `repr(align)` attribute: larger than 2^29 enum E2 { A, B } #[repr(align(536870912))] // ok: this is the largest accepted alignment enum E3 { A, B } #[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two + //~| ERROR: invalid `repr(align)` attribute: not a power of two enum E4 { A, B } fn main() {} diff --git a/tests/ui/repr/repr-align.stderr b/tests/ui/repr/repr-align.stderr index fe919e30b1534..660247840c48a 100644 --- a/tests/ui/repr/repr-align.stderr +++ b/tests/ui/repr/repr-align.stderr @@ -5,47 +5,111 @@ LL | #[repr(align(16.0))] | ^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:6:14 + --> $DIR/repr-align.rs:7:14 | LL | #[repr(align(15))] | ^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:9:14 + --> $DIR/repr-align.rs:11:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:15:14 + --> $DIR/repr-align.rs:18:14 | LL | #[repr(align(0))] | ^ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer - --> $DIR/repr-align.rs:18:14 + --> $DIR/repr-align.rs:22:14 | LL | #[repr(align(16.0))] | ^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two - --> $DIR/repr-align.rs:21:14 + --> $DIR/repr-align.rs:26:14 | LL | #[repr(align(15))] | ^^ error[E0589]: invalid `repr(align)` attribute: larger than 2^29 - --> $DIR/repr-align.rs:24:14 + --> $DIR/repr-align.rs:30:14 | LL | #[repr(align(4294967296))] | ^^^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:37:14 + | +LL | #[repr(align(0))] + | ^ + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:3:14 + | +LL | #[repr(align(16.0))] + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:7:14 + | +LL | #[repr(align(15))] + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 + --> $DIR/repr-align.rs:11:14 + | +LL | #[repr(align(4294967296))] + | ^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:18:14 + | +LL | #[repr(align(0))] + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/repr-align.rs:22:14 + | +LL | #[repr(align(16.0))] + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:26:14 + | +LL | #[repr(align(15))] + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: larger than 2^29 --> $DIR/repr-align.rs:30:14 | +LL | #[repr(align(4294967296))] + | ^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0589]: invalid `repr(align)` attribute: not a power of two + --> $DIR/repr-align.rs:37:14 + | LL | #[repr(align(0))] | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 8 previous errors +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0589`. diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr index 2cafb989bce5e..d0c78a8418a09 100644 --- a/tests/ui/repr/repr-transparent.stderr +++ b/tests/ui/repr/repr-transparent.stderr @@ -35,10 +35,10 @@ LL | struct GenericAlign(ZstAlign32, u32); | needs at most one field with non-trivial size or alignment, but has 2 error[E0084]: unsupported representation for zero-variant enum - --> $DIR/repr-transparent.rs:47:8 + --> $DIR/repr-transparent.rs:47:1 | LL | #[repr(transparent)] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ LL | enum Void {} | --------- zero-variant enum diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index f46e35e1a72af..7857a0603bd45 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -8,16 +8,16 @@ mod bogus_attribute_types_1 { #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541] fn f1() { } - #[stable(feature = "a", since)] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539] fn f2() { } - #[stable(feature, since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature, since = "3.3.3")] //~ ERROR incorrect meta item [E0539] fn f3() { } - #[stable(feature = "a", since(b))] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539] fn f5() { } - #[stable(feature(b), since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature(b), since = "3.3.3")] //~ ERROR incorrect meta item [E0539] fn f6() { } } diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 2e2b5b509c896..c614fc2b9f7fa 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -1,28 +1,40 @@ +error: multiple `deprecated` attributes + --> $DIR/stability-attribute-sanity.rs:62:1 + | +LL | #[deprecated(since = "5.5.5", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/stability-attribute-sanity.rs:61:1 + | +LL | #[deprecated(since = "5.5.5", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0541]: unknown meta item 'reason' --> $DIR/stability-attribute-sanity.rs:8:46 | LL | #[stable(feature = "a", since = "4.4.4", reason)] | ^^^^^^ expected one of `feature`, `since` -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:11:29 | LL | #[stable(feature = "a", since)] | ^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:14:14 | LL | #[stable(feature, since = "3.3.3")] | ^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:17:29 | LL | #[stable(feature = "a", since(b))] | ^^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:20:14 | LL | #[stable(feature(b), since = "3.3.3")] @@ -88,18 +100,6 @@ error: 'since' must be a Rust version number, such as "1.31.0" LL | #[stable(feature = "e", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: multiple `deprecated` attributes - --> $DIR/stability-attribute-sanity.rs:62:1 - | -LL | #[deprecated(since = "5.5.5", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/stability-attribute-sanity.rs:61:1 - | -LL | #[deprecated(since = "5.5.5", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:64:1 |