diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70da024d71bda..c774b3647dbce 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,7 +42,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_attr::AttributeParseContext; +use rustc_attr::{AttributeParseContext, OmitDoc}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; @@ -868,7 +868,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec { - self.attribute_parse_context.parse_attribute_list(attrs, target_span) + self.attribute_parse_context.parse_attribute_list(attrs, target_span, OmitDoc::Lower) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index d81fd53938b89..36827920c41e1 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -209,8 +209,6 @@ ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syn ast_passes_show_span = {$msg} -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 f65056a494ba0..66147bd9fe90f 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -733,13 +733,6 @@ 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 8cdc7133cc070..18efebe29aa35 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -209,18 +209,6 @@ 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/messages.ftl b/compiler/rustc_attr/messages.ftl index 235ab7572c419..786afcb3dcc46 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -6,6 +6,8 @@ attr_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_empty_confusables = + expected at least one confusable name attr_expected_one_cfg_pattern = expected 1 cfg-pattern @@ -21,8 +23,8 @@ attr_expects_feature_list = attr_expects_features = `{$name}` expects feature names -attr_incorrect_meta_item = - incorrect meta item +attr_incorrect_meta_item = expected a quoted string literal +attr_incorrect_meta_item_suggestion = consider surrounding this with quotes attr_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -91,15 +93,14 @@ attr_non_ident_feature = attr_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute -attr_rustc_const_stable_indirect_pairing = - `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied - attr_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute attr_soft_no_args = `soft` should not have any arguments +attr_stability_outside_std = stability attributes may not be used outside of the standard library + attr_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} @@ -122,3 +123,8 @@ attr_unsupported_literal_generic = unsupported literal attr_unsupported_literal_suggestion = consider removing the prefix + +attr_unused_multiple = + multiple `{$name}` attributes + .suggestion = remove this attribute + .note = attribute also specified here diff --git a/compiler/rustc_attr/src/attributes/confusables.rs b/compiler/rustc_attr/src/attributes/confusables.rs index 583d5e5e6704c..7b9e4e70da1d0 100644 --- a/compiler/rustc_attr/src/attributes/confusables.rs +++ b/compiler/rustc_attr/src/attributes/confusables.rs @@ -1,20 +1,21 @@ use rustc_hir::AttributeKind; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use super::{AttributeFilter, AttributeGroup, AttributeMapping}; -use crate::attribute_filter; use crate::context::AttributeGroupContext; use crate::parser::ArgParser; +use crate::{attribute_filter, session_diagnostics}; // TODO: turn into CombineGroup? #[derive(Default)] pub(crate) struct ConfusablesGroup { confusables: ThinVec, + first_span: Option, } impl AttributeGroup for ConfusablesGroup { - const ATTRIBUTES: AttributeMapping = &[(&[sym::rustc_confusables], |this, _cx, args| { + const ATTRIBUTES: AttributeMapping = &[(&[sym::rustc_confusables], |this, cx, args| { let Some(list) = args.list() else { // TODO: error when not a list? Bring validation code here. // NOTE: currently subsequent attributes are silently ignored using @@ -22,18 +23,41 @@ impl AttributeGroup for ConfusablesGroup { return; }; + if list.is_empty() { + cx.dcx().emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); + } + for param in list.mixed() { + let span = param.span(); + let Some(lit) = param.lit() else { - // TODO: error when not a lit? Bring validation code here. - // curently silently ignored. - return; + cx.dcx().emit_err(session_diagnostics::IncorrectMetaItem { + span, + suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { + lo: span.shrink_to_lo(), + hi: span.shrink_to_hi(), + }), + }); + continue; }; this.confusables.push(lit.symbol); } + + this.first_span.get_or_insert(cx.attr_span); })]; fn finalize(self, _cx: &AttributeGroupContext<'_>) -> Option<(AttributeKind, AttributeFilter)> { - Some((AttributeKind::Confusables(self.confusables), attribute_filter!(allow all))) + if self.confusables.is_empty() { + return None; + } + + Some(( + AttributeKind::Confusables { + symbols: self.confusables, + first_span: self.first_span.unwrap(), + }, + attribute_filter!(allow all), + )) } } diff --git a/compiler/rustc_attr/src/attributes/deprecation.rs b/compiler/rustc_attr/src/attributes/deprecation.rs index aa1a3421eb833..7779c5dc343bb 100644 --- a/compiler/rustc_attr/src/attributes/deprecation.rs +++ b/compiler/rustc_attr/src/attributes/deprecation.rs @@ -40,7 +40,11 @@ fn get<'a>( false } } else { - cx.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: param_span }); + // FIXME(jdonszelmann): suggestion? + cx.dcx().emit_err(session_diagnostics::IncorrectMetaItem { + span: param_span, + suggestion: None, + }); false } } @@ -48,12 +52,13 @@ fn get<'a>( impl SingleAttributeGroup for DeprecationGroup { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; - fn on_duplicate( - _cx: &crate::context::AttributeAcceptContext<'_>, - _first_span: rustc_span::Span, - ) { - // TODO: investigate duplicate deprecation attr - todo!() + fn on_duplicate(cx: &crate::context::AttributeAcceptContext<'_>, first_span: rustc_span::Span) { + // FIXME(jdonszelmann): merge with errors from check_attrs.rs + cx.dcx().emit_err(session_diagnostics::UnusedMultiple { + this: cx.attr_span, + other: first_span, + name: sym::deprecated, + }); } fn convert( diff --git a/compiler/rustc_attr/src/attributes/inline.rs b/compiler/rustc_attr/src/attributes/inline.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/compiler/rustc_attr/src/attributes/mod.rs b/compiler/rustc_attr/src/attributes/mod.rs index 309575aa8cb38..2530330c6498d 100644 --- a/compiler/rustc_attr/src/attributes/mod.rs +++ b/compiler/rustc_attr/src/attributes/mod.rs @@ -29,7 +29,6 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; -pub(crate) mod inline; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; diff --git a/compiler/rustc_attr/src/attributes/stability.rs b/compiler/rustc_attr/src/attributes/stability.rs index f34d617791360..9890990d3bb07 100644 --- a/compiler/rustc_attr/src/attributes/stability.rs +++ b/compiler/rustc_attr/src/attributes/stability.rs @@ -1,13 +1,13 @@ use std::num::NonZero; use rustc_hir::{ - AttributeKind, ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, - UnstableReason, VERSION_PLACEHOLDER, + AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, + StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use super::util::parse_version; -use super::{AttributeFilter, AttributeGroup, AttributeMapping}; +use super::{AttributeFilter, AttributeGroup, AttributeMapping, SingleAttributeGroup}; use crate::attribute_filter; use crate::context::{AttributeAcceptContext, AttributeGroupContext}; use crate::parser::{ArgParser, MetaItemParser, NameValueParser}; @@ -67,6 +67,11 @@ impl AttributeGroup for StabilityGroup { } } + // Emit errors for non-staged-api crates. + if !cx.features().staged_api() { + cx.dcx().emit_err(session_diagnostics::StabilityOutsideStd { span }); + } + Some((AttributeKind::Stability { stability, span }, attribute_filter!(allow all))) } } @@ -88,17 +93,38 @@ impl AttributeGroup for BodyStabilityGroup { } })]; - fn finalize(self, _cx: &AttributeGroupContext<'_>) -> Option<(AttributeKind, AttributeFilter)> { + fn finalize(self, cx: &AttributeGroupContext<'_>) -> Option<(AttributeKind, AttributeFilter)> { let (stability, span) = self.stability?; + + // Emit errors for non-staged-api crates. + if !cx.features().staged_api() { + cx.dcx().emit_err(session_diagnostics::StabilityOutsideStd { span }); + } + Some((AttributeKind::BodyStability { stability, span }, attribute_filter!(allow all))) } } +pub(crate) struct ConstStabilityIndirectGroup; +// TODO: single word attribute group +impl SingleAttributeGroup for ConstStabilityIndirectGroup { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; + + // ignore + fn on_duplicate(_cx: &AttributeAcceptContext<'_>, _first_span: Span) {} + + fn convert( + _cx: &AttributeAcceptContext<'_>, + _args: &super::GenericArgParser<'_, rustc_ast::Expr>, + ) -> Option<(AttributeKind, AttributeFilter)> { + Some((AttributeKind::ConstStabilityIndirect, attribute_filter!(allow all))) + } +} + #[derive(Default)] pub(crate) struct ConstStabilityGroup { promotable: bool, - const_stable_indirect: Option, - stability: Option<(ConstStability, Span)>, + stability: Option<(PartialConstStability, Span)>, } impl ConstStabilityGroup { @@ -120,12 +146,7 @@ impl AttributeGroup for ConstStabilityGroup { && let Some((feature, level)) = parse_stability(cx, args) { this.stability = Some(( - ConstStability { - level, - feature, - promotable: false, - const_stable_indirect: false, - }, + PartialConstStability { level, feature, promotable: false }, cx.attr_span, )); } @@ -135,12 +156,7 @@ impl AttributeGroup for ConstStabilityGroup { && let Some((feature, level)) = parse_unstability(cx, args) { this.stability = Some(( - ConstStability { - level, - feature, - promotable: false, - const_stable_indirect: false, - }, + PartialConstStability { level, feature, promotable: false }, cx.attr_span, )); } @@ -148,9 +164,6 @@ impl AttributeGroup for ConstStabilityGroup { (&[sym::rustc_promotable], |this, _, _| { this.promotable = true; }), - (&[sym::rustc_const_stable_indirect], |this, cx, _| { - this.const_stable_indirect = Some(cx.attr_span); - }), ]; fn finalize( @@ -166,47 +179,13 @@ impl AttributeGroup for ConstStabilityGroup { } } - if self.const_stable_indirect.is_some() { - if let Some((ref mut stab, _)) = self.stability { - if stab.is_const_unstable() { - stab.const_stable_indirect = true; - } else { - _ = cx.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing { - span: cx.target_span, - }) - } - } else { - // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by - // the `default_const_unstable` logic. - } + let (stability, span) = self.stability?; + + // Emit errors for non-staged-api crates. + if !cx.features().staged_api() { + cx.dcx().emit_err(session_diagnostics::StabilityOutsideStd { span }); } - // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const - // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const - // stability checks for them. We need to do this because the default for whether an unmarked - // function enforces recursive stability differs between staged-api crates and force-unmarked - // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect` - // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to - // assume the function does not have recursive stability. All functions that *do* have recursive - // stability must explicitly record this, and so that's what we do for all `const fn` in a - // staged_api crate. - // TODO(jdonszelmann): defer this check to when we know what item it is. Possibly engineer - // something in that checks - // if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() { - // let c = ConstStability { - // feature: None, - // const_stable_indirect: const_stable_indirect.is_some(), - // promotable: false, - // level: StabilityLevel::Unstable { - // reason: UnstableReason::Default, - // issue: None, - // is_soft: false, - // implied_by: None, - // }, - // }; - // const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP))); - // } - let (stability, span) = self.stability?; Some((AttributeKind::ConstStability { stability, span }, attribute_filter!(allow all))) } } @@ -232,7 +211,10 @@ fn insert_value_into_option_or_error<'a>( *item = Some(s); Some(()) } else { - cx.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: param.span() }); + cx.dcx().emit_err(session_diagnostics::IncorrectMetaItem { + span: param.span(), + suggestion: None, + }); None } } @@ -284,7 +266,7 @@ pub(crate) fn parse_stability<'a>( if since.as_str() == VERSION_PLACEHOLDER { StableSince::Current } else if let Some(version) = parse_version(since) { - StableSince::Version(version) + StableSince::Version(version, since) } else { cx.dcx().emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); StableSince::Err diff --git a/compiler/rustc_attr/src/context.rs b/compiler/rustc_attr/src/context.rs index 1df7724017a57..2425ec4abaa2e 100644 --- a/compiler/rustc_attr/src/context.rs +++ b/compiler/rustc_attr/src/context.rs @@ -1,4 +1,3 @@ - use std::cell::RefCell; use std::collections::BTreeMap; use std::ops::Deref; @@ -16,7 +15,9 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableGroup, AllowInternal use crate::attributes::confusables::ConfusablesGroup; use crate::attributes::deprecation::DeprecationGroup; use crate::attributes::repr::ReprGroup; -use crate::attributes::stability::{BodyStabilityGroup, ConstStabilityGroup, StabilityGroup}; +use crate::attributes::stability::{ + BodyStabilityGroup, ConstStabilityGroup, ConstStabilityIndirectGroup, StabilityGroup, +}; use crate::attributes::transparency::TransparencyGroup; use crate::attributes::{AttributeFilter, AttributeGroup, Combine, Single}; use crate::parser::{GenericArgParser, GenericMetaItemParser, MetaItemParser}; @@ -59,17 +60,23 @@ macro_rules! attribute_groups { } attribute_groups!( + // TODO: rename to the same as in `AttributeDuplicates` pub(crate) static ATTRIBUTE_GROUP_MAPPING = [ // tidy-alphabetical-start + BodyStabilityGroup, ConfusablesGroup, ConstStabilityGroup, - BodyStabilityGroup, StabilityGroup, + // tidy-alphabetical-end + // tidy-alphabetical-start Combine, Combine, Combine, + // tidy-alphabetical-end + // tidy-alphabetical-start + Single, Single, Single, // tidy-alphabetical-end @@ -112,6 +119,12 @@ impl<'a> Deref for AttributeGroupContext<'a> { } } +#[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 AttributeParseContext<'sess> { @@ -120,6 +133,9 @@ pub struct AttributeParseContext<'sess> { 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, } @@ -141,7 +157,7 @@ impl<'sess> AttributeParseContext<'sess> { target_span: Span, ) -> Option { let mut parsed = Self { sess, features: None, tools: Vec::new(), parse_only: Some(sym) } - .parse_attribute_list(attrs, target_span); + .parse_attribute_list(attrs, target_span, OmitDoc::Skip); assert!(parsed.len() <= 1); @@ -164,10 +180,15 @@ impl<'sess> AttributeParseContext<'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, ) -> Vec { let mut attributes = Vec::new(); @@ -182,8 +203,21 @@ impl<'sess> AttributeParseContext<'sess> { } } + // 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, @@ -191,6 +225,17 @@ impl<'sess> AttributeParseContext<'sess> { 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 = GenericMetaItemParser::from_attr(&n, self.dcx()); let (path, args) = parser.deconstruct(); @@ -214,8 +259,8 @@ impl<'sess> AttributeParseContext<'sess> { const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; assert!( - self.tools.contains(&parts[0]) - || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), + 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", ); diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 0e296579921da..c2f49e6c4b4f4 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -36,7 +36,7 @@ mod session_diagnostics; pub use attributes::cfg::*; pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; -pub use context::AttributeParseContext; +pub use context::{AttributeParseContext, OmitDoc}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr/src/parser.rs b/compiler/rustc_attr/src/parser.rs index f472ea829b44f..9c4d5c932c4cb 100644 --- a/compiler/rustc_attr/src/parser.rs +++ b/compiler/rustc_attr/src/parser.rs @@ -34,7 +34,7 @@ impl<'a> Iterator for SegmentIterator<'a> { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) enum PathParser<'a> { Ast(&'a Path), Attr(AttrPath), @@ -184,13 +184,14 @@ macro_rules! argparser { 'a: 'r, { match &self.args { - Args::Delimited(args) if args.delim == Delimiter::Parenthesis => { + Args::Delimited(args) if args.delim == Delimiter::Parenthesis => Some( MetaItemListParserContext { inside_delimiters: args.tokens.trees().peekable(), dcx: self.dcx, } .parse() - } + .unwrap(), + ), Args::Delimited(_) | Args::Eq { .. } | Args::Empty => None, } } @@ -221,6 +222,7 @@ argparser!(MetaItemLit); /// This enum represents that. /// /// Choose which one you want using the provided methods. +#[derive(Debug)] pub(crate) enum MetaItemOrLitParser<'a, T: Clone> where GenericMetaItemParser<'a, T>: MetaItemParser<'a>, @@ -276,6 +278,15 @@ pub(crate) struct GenericMetaItemParser<'a, T: Clone> { dcx: DiagCtxtHandle<'a>, } +impl<'a, T: Clone + Debug> Debug for GenericMetaItemParser<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GenericMetaItemParser") + .field("path", &self.path) + .field("args", &self.args) + .finish() + } +} + impl<'a> GenericMetaItemParser<'a, Expr> { /// Create a new parser from a [`NormalAttr`], which is stored inside of any /// [`ast::Attribute`](Attribute) @@ -288,7 +299,7 @@ impl<'a> GenericMetaItemParser<'a, Expr> { } } -pub(crate) trait MetaItemParser<'a>: 'a { +pub(crate) trait MetaItemParser<'a>: Debug + 'a { type ArgParser: ArgParser<'a>; fn span(&self) -> Span; @@ -413,7 +424,17 @@ pub(crate) struct GenericNameValueParser<'a, T: Clone> { dcx: DiagCtxtHandle<'a>, } -pub(crate) trait NameValueParser<'a> { +impl<'a, T: Clone + Debug> Debug for GenericNameValueParser<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GenericNameValueParser") + .field("eq_span", &self.eq_span) + .field("value", &self.value) + .field("value_span", &self.value_span) + .finish() + } +} + +pub(crate) trait NameValueParser<'a>: Debug { fn value_span(&self) -> Span; fn value_as_lit(&self) -> MetaItemLit; @@ -540,6 +561,7 @@ impl<'a> MetaItemListParserContext<'a> { 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)); } @@ -617,6 +639,7 @@ impl<'a> MetaItemListParserContext<'a> { } } +#[derive(Debug)] pub(crate) struct MetaItemListParser<'a> { sub_parsers: Vec>, } @@ -627,6 +650,14 @@ impl<'a> MetaItemListParser<'a> { self.sub_parsers.into_iter() } + pub(crate) fn len(&self) -> usize { + self.sub_parsers.len() + } + + pub(crate) 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. diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 3b55133d8ee81..8aae54307d0e6 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -46,6 +46,18 @@ pub(crate) struct MultipleItem { pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, + + #[subdiagnostic] + pub suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(attr_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 @@ -326,13 +338,6 @@ pub(crate) struct RustcPromotablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_rustc_const_stable_indirect_pairing)] -pub(crate) struct RustcConstStableIndirectPairing { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { @@ -412,3 +417,29 @@ 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_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_stability_outside_std, code = E0734)] +pub(crate) struct StabilityOutsideStd { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_empty_confusables)] +pub(crate) struct EmptyConfusables { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index b45c2eb68682a..bd4dccedb7d96 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -105,8 +105,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline - == rustc_hir::InlineAttr::Never) + || tcx.codegen_fn_attrs(instance_def_id).inline == rustc_hir::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index cb49cab5bf9c6..16ceb2b8c3fb4 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -311,8 +311,7 @@ fn exported_symbols_provider_local( } if !tcx.sess.opts.share_generics() { - if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_hir::InlineAttr::Never - { + if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_hir::InlineAttr::Never { // this is OK, we explicitly allow sharing inline(never) across crates even // without share-generics. } else { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 425d029ad5020..65667737ea79d 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -872,9 +872,9 @@ 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) { sess.dcx().emit_err(errors::MacroConstStability { span: sp, diff --git a/compiler/rustc_hir/src/attribute.rs b/compiler/rustc_hir/src/attribute.rs index 50623253877f1..8ab20267ac9f9 100644 --- a/compiler/rustc_hir/src/attribute.rs +++ b/compiler/rustc_hir/src/attribute.rs @@ -1,9 +1,8 @@ -use rustc_ast::{self as ast, MetaItemInner}; use std::fmt::Display; use rustc_ast::attr::AttributeExt; use rustc_ast::token::CommentKind; -use rustc_ast::{AttrId, AttrStyle, DelimArgs, MetaItemLit}; +use rustc_ast::{self as ast, AttrId, AttrStyle, DelimArgs, MetaItemInner, MetaItemLit}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; @@ -14,7 +13,7 @@ use rustc_target::abi::Align; use smallvec::SmallVec; use thin_vec::ThinVec; -use crate::{ConstStability, DefaultBodyStability, ItemLocalId, RustcVersion, Stability}; +use crate::{DefaultBodyStability, ItemLocalId, PartialConstStability, RustcVersion, Stability}; /// 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. @@ -140,9 +139,6 @@ pub enum RustcAttribute { // tidy-alphabetical-startt AllowIncoherentImpl, Coinductive, - Confusables, - ConstStable, - ConstUnstable, DenyExplicitImpl, HasIncoherentImpls, LayoutScalarValidRangeEnd, @@ -186,14 +182,24 @@ pub enum AttributeKind { AllowInternalUnstable(ThinVec), AutoDiff, AutomaticallyDerived, + BodyStability { + stability: DefaultBodyStability, + /// Span of the `#[rustc_default_body_unstable(...)]` attribute + span: Span, + }, Cfg, CfgAttr, CfiEncoding, // FIXME(cfi_encoding) Cold, CollapseDebuginfo, - Confusables(ThinVec), + Confusables { + symbols: ThinVec, + // FIXME(jdonszelmann): remove when target validation code is moved + first_span: Span, + }, + ConstStabilityIndirect, ConstStability { - stability: ConstStability, + stability: PartialConstStability, /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute span: Span, }, @@ -202,18 +208,13 @@ pub enum AttributeKind { Coverage, CustomMir, DebuggerVisualizer, - BodyStability { - stability: DefaultBodyStability, - /// Span of the `#[rustc_default_body_unstable(...)]` attribute - span: Span, - }, DefaultLibAllocator, Deny, + DeprecatedSafe, // FIXME(deprecated_safe) Deprecation { deprecation: Deprecation, span: Span, }, - DeprecatedSafe, // FIXME(deprecated_safe) Diagnostic(DiagnosticAttribute), Doc, /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). @@ -429,7 +430,7 @@ impl AttributeExt for Attribute { } fn is_doc_comment(&self) -> bool { - matches!(self, Attribute::Parsed(AttributeKind::DocComment {..})) + matches!(self, Attribute::Parsed(AttributeKind::DocComment { .. })) } fn span(&self) -> Span { @@ -457,14 +458,16 @@ impl AttributeExt for Attribute { fn doc_str(&self) -> Option { match &self { - Attribute::Parsed(AttributeKind::DocComment{comment, ..}) => Some(*comment), + Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment), Attribute::Unparsed(_) if self.has_name(sym::doc) => self.value_str(), _ => None, } } fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { match &self { - Attribute::Parsed(AttributeKind::DocComment{kind, comment, ..}) => Some((*comment, *kind)), + Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { + Some((*comment, *kind)) + } Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => { self.value_str().map(|s| (s, CommentKind::Line)) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a452c4fec26fe..28571dd308c5a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3,8 +3,8 @@ use std::fmt; use rustc_abi::ExternAbi; use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::{ - self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, - IntTy, Label, LitKind, TraitObjectSyntax, UintTy, + self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitKind, + TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, diff --git a/compiler/rustc_hir/src/stability.rs b/compiler/rustc_hir/src/stability.rs index 6b758c7dbd686..b7d5239908651 100644 --- a/compiler/rustc_hir/src/stability.rs +++ b/compiler/rustc_hir/src/stability.rs @@ -1,4 +1,5 @@ use std::num::NonZero; +use std::ops::Deref; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Symbol, sym}; @@ -42,30 +43,58 @@ impl Stability { pub struct ConstStability { pub level: StabilityLevel, pub feature: Symbol, - /// This is true iff the `const_stable_indirect` attribute is present. - pub const_stable_indirect: bool, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, + /// This is true iff the `const_stable_indirect` attribute is present. + pub const_stable_indirect: bool, } impl ConstStability { - pub fn is_const_unstable(&self) -> bool { - self.level.is_unstable() - } - - pub fn is_const_stable(&self) -> bool { - self.level.is_stable() + pub fn from_partial( + PartialConstStability { level, feature, promotable }: PartialConstStability, + const_stable_indirect: bool, + ) -> Self { + Self { const_stable_indirect, level, feature, promotable } } /// The stability assigned to unmarked items when -Zforce-unstable-if-unmarked is set. pub fn unmarked(const_stable_indirect: bool, regular_stab: Stability) -> Self { - ConstStability { + Self { feature: regular_stab.feature, - const_stable_indirect, promotable: false, level: regular_stab.level, + const_stable_indirect, } } + + pub fn is_const_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_const_stable(&self) -> bool { + self.level.is_stable() + } +} + +/// 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)] +pub struct PartialConstStability { + pub level: StabilityLevel, + pub feature: Symbol, + /// whether the function has a `#[rustc_promotable]` attribute + pub promotable: bool, +} + +impl PartialConstStability { + pub fn is_const_unstable(&self) -> bool { + self.level.is_unstable() + } + + pub fn is_const_stable(&self) -> bool { + self.level.is_stable() + } } /// The available stability levels. @@ -114,7 +143,8 @@ pub enum StabilityLevel { #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] #[derive(HashStable_Generic)] pub enum StableSince { - Version(RustcVersion), + /// also stores the original symbol for printing + Version(RustcVersion, Symbol), /// Stabilized in the upcoming version, whatever number that is. Current, /// Failed to parse a stabilization version. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0919de3d28ab3..d2b362ebc0e33 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -6,7 +6,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; use rustc_hir::def::{CtorKind, DefKind}; -use rustc_hir::{Node, Safety, intravisit, AttributeKind}; +use rustc_hir::{AttributeKind, Node, Safety, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index df4da03f0f59d..a111eae70077b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Float(FloatTy::F128) => Some(InlineAsmType::F128), ty::FnPtr(..) => Some(asm_ty_isize), ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), - ty::Adt(adt, args) if adt.repr().simd() => { + ty::Adt(adt, args) if { adt.repr().simd() } => { let fields = &adt.non_enum_variant().fields; let elem_ty = fields[FieldIdx::ZERO].ty(self.tcx, args); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7931972dc9e84..66d6a4f0b42c4 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -11,7 +11,7 @@ use std::vec; use rustc_abi::ExternAbi; use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity}; -use rustc_ast::{DUMMY_NODE_ID, DelimArgs, AttrStyle}; +use rustc_ast::{AttrStyle, 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; @@ -88,6 +88,10 @@ impl<'a> State<'a> { } fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) { + if attrs.is_empty() { + return; + } + for attr in attrs { self.print_attribute_inline(attr, style); } @@ -105,11 +109,11 @@ impl<'a> State<'a> { self.print_attr_item(&unparsed, unparsed.span); self.word("]"); } - hir::Attribute::Parsed(hir::AttributeKind::DocComment{style, kind, comment, ..}) => { + hir::Attribute::Parsed(hir::AttributeKind::DocComment { + style, kind, comment, .. + }) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( - *kind, - *style, - *comment, + *kind, *style, *comment, )); self.hardbreak() } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index db23acaf1a552..758b39ef06762 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1868,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { - if let Some(candidates) = rustc_attr::find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables(c) => c) + if let Some(candidates) = rustc_attr::find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) && candidates.contains(&item_name.name) && let ty::AssocKind::Fn = inherent_method.kind { diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 96b539e50c879..f9e5192466af2 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -38,12 +38,12 @@ 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(); // TODO: we're only dealling with allow/deny/etc lint attributes. They can have an // ID, while other attributes don't necessarily. however, how do we assert that // nicely? - let attr_id = todo!(); + // let attr_id = todo!(); (attr_id, lint_index) } _ => panic!("fulfilled expectations must have a lint index"), diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7edb1d2ffe885..68393fe0c8b51 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -223,19 +223,23 @@ 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: 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 })) + 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 + } } - (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_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 6bddd8db57e98..d785e3e909179 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -44,7 +44,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, Span}; use rustc_target::spec::PanicStrategy; -use {rustc_ast as ast, rustc_hir as hir, rustc_abi as abi}; +use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1b713c5735c41..2c9de5b47a2d6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -35,7 +35,7 @@ use rustc_data_structures::steal::Steal; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::{LangItem, Safety, AttributeKind}; +use rustc_hir::{AttributeKind, LangItem, Safety}; use rustc_index::IndexVec; use rustc_macros::{ Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, @@ -52,7 +52,7 @@ pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; -use {rustc_ast as ast, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir}; pub use self::closure::{ BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, @@ -1503,49 +1503,48 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - for attr in self.get_attrs(did, sym::repr) { - if let hir::Attribute::Parsed(AttributeKind::Repr(ref r)) = attr { - for r in r { - flags.insert(match *r { - hir::Repr::Rust => ReprFlags::empty(), - hir::Repr::C => ReprFlags::IS_C, - hir::Repr::Packed(pack) => { - min_pack = Some(if let Some(min_pack) = min_pack { - min_pack.min(pack) - } else { - pack - }); - ReprFlags::empty() - } - hir::Repr::Transparent => ReprFlags::IS_TRANSPARENT, - hir::Repr::Simd => ReprFlags::IS_SIMD, - hir::Repr::Int(i) => { - size = Some(match i { - hir::IntType::SignedInt(x) => match x { - ast::IntTy::Isize => IntegerType::Pointer(true), - ast::IntTy::I8 => IntegerType::Fixed(Integer::I8, true), - ast::IntTy::I16 => IntegerType::Fixed(Integer::I16, true), - ast::IntTy::I32 => IntegerType::Fixed(Integer::I32, true), - ast::IntTy::I64 => IntegerType::Fixed(Integer::I64, true), - ast::IntTy::I128 => IntegerType::Fixed(Integer::I128, true), - }, - hir::IntType::UnsignedInt(x) => match x { - ast::UintTy::Usize => IntegerType::Pointer(false), - ast::UintTy::U8 => IntegerType::Fixed(Integer::I8, false), - ast::UintTy::U16 => IntegerType::Fixed(Integer::I16, false), - ast::UintTy::U32 => IntegerType::Fixed(Integer::I32, false), - ast::UintTy::U64 => IntegerType::Fixed(Integer::I64, false), - ast::UintTy::U128 => IntegerType::Fixed(Integer::I128, false), - }, - }); - ReprFlags::empty() - } - hir::Repr::Align(align) => { - max_align = max_align.max(Some(align)); - ReprFlags::empty() - } - }); - } + if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) + { + for r in reprs { + flags.insert(match *r { + hir::Repr::Rust => ReprFlags::empty(), + hir::Repr::C => ReprFlags::IS_C, + hir::Repr::Packed(pack) => { + min_pack = Some(if let Some(min_pack) = min_pack { + min_pack.min(pack) + } else { + pack + }); + ReprFlags::empty() + } + hir::Repr::Transparent => ReprFlags::IS_TRANSPARENT, + hir::Repr::Simd => ReprFlags::IS_SIMD, + hir::Repr::Int(i) => { + size = Some(match i { + hir::IntType::SignedInt(x) => match x { + ast::IntTy::Isize => IntegerType::Pointer(true), + ast::IntTy::I8 => IntegerType::Fixed(Integer::I8, true), + ast::IntTy::I16 => IntegerType::Fixed(Integer::I16, true), + ast::IntTy::I32 => IntegerType::Fixed(Integer::I32, true), + ast::IntTy::I64 => IntegerType::Fixed(Integer::I64, true), + ast::IntTy::I128 => IntegerType::Fixed(Integer::I128, true), + }, + hir::IntType::UnsignedInt(x) => match x { + ast::UintTy::Usize => IntegerType::Pointer(false), + ast::UintTy::U8 => IntegerType::Fixed(Integer::I8, false), + ast::UintTy::U16 => IntegerType::Fixed(Integer::I16, false), + ast::UintTy::U32 => IntegerType::Fixed(Integer::I32, false), + ast::UintTy::U64 => IntegerType::Fixed(Integer::I64, false), + ast::UintTy::U128 => IntegerType::Fixed(Integer::I128, false), + }, + }); + ReprFlags::empty() + } + hir::Repr::Align(align) => { + max_align = max_align.max(Some(align)); + ReprFlags::empty() + } + }); } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 7a0a518bb513a..fb0b8f05db5bc 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -308,9 +308,6 @@ 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 @@ -359,9 +356,6 @@ passes_implied_feature_not_exist = 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} @@ -643,6 +637,8 @@ 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 diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 587a63c7faf8c..935d414667aa2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,14 +8,15 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; +use rustc_attr as 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, Attribute, AttributeKind, CRATE_HIR_ID, CRATE_OWNER_ID, + FnSig, ForeignItem, HirId, Item, ItemKind, MethodKind, Repr, Safety, Target, TraitItem, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -114,190 +115,198 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { - match attr.path().as_slice() { - [sym::diagnostic, sym::do_not_recommend, ..] => { - self.check_do_not_recommend(attr.span(), hir_id, target) + match attr { + Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { + self.check_confusables(*first_span, target); } - [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), - [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::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::start - | 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`" - ) + _ => { + match attr.path().as_slice() { + [sym::diagnostic, sym::do_not_recommend, ..] => { + self.check_do_not_recommend(attr.span(), hir_id, target) + } + [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), + [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::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::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::start + | 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 => (), } } - None => (), + [] => unreachable!(), } } - [] => unreachable!(), } let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); @@ -2138,36 +2147,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - 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() }); - } + fn check_confusables(&self, span: Span, target: Target) { + if !matches!(target, Target::Method(MethodKind::Inherent)) { + self.dcx().emit_err(errors::Confusables { attr_span: span }); } } @@ -2410,12 +2392,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { - 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)) + if !attr::find_attr!(attrs, AttributeKind::Repr(r) => r.contains(&Repr::Transparent)) + .unwrap_or(false) { self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); } @@ -2566,46 +2544,42 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { ]; for attr in attrs { - // 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() - .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, + for attr_to_check in ATTRS_TO_CHECK { + if attr.has_name(*attr_to_check) { + let item = tcx + .hir() + .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(ref p) = attr { - tcx.dcx().try_steal_replace_and_emit_err( - p.path.span, - StashKey::UndeterminedMacroResolution, - err, - ); - } else { - err.emit(); - } + if let Attribute::Unparsed(ref p) = attr { + tcx.dcx().try_steal_replace_and_emit_err( + p.path.span, + StashKey::UndeterminedMacroResolution, + err, + ); + } else { + err.emit(); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index fdc7e1bba2f0e..93fb00ce73c8d 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -696,31 +696,6 @@ 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 { @@ -1850,3 +1825,11 @@ pub(crate) struct NoSanitize<'a> { pub accepted_kind: &'a str, pub attr_str: &'a str, } + +// TODO: 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 91aadfc9bb08b..b86a9f3b71b71 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -5,7 +5,7 @@ //! collect them instead. use rustc_hir::intravisit::Visitor; -use rustc_hir::{Attribute, VERSION_PLACEHOLDER}; +use rustc_hir::{Attribute, AttributeKind, StabilityLevel, StableSince}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::query::{LocalCrate, Providers}; @@ -26,66 +26,29 @@ impl<'tcx> LibFeatureCollector<'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, 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. + let (feature, level, span) = match attr { + Attribute::Parsed(AttributeKind::Stability { stability, span }) => { + (stability.feature, stability.level, *span) } - } - - None + Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => { + (stability.feature, stability.level, *span) + } + Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => { + (stability.feature, stability.level, *span) + } + _ => return None, + }; + + let feature_stability = match level { + StabilityLevel::Unstable { .. } => FeatureStability::Unstable, + StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { + StableSince::Version(_, v) => v, + StableSince::Current => sym::env_CFG_RELEASE, + StableSince::Err => return None, + }), + }; + + Some((feature, feature_stability, span)) } 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 e995d483182fe..9e4f1aa39d5e7 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -14,8 +14,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ self as hir, AttributeKind, ConstStability, DeprecatedSince, FieldDef, Item, ItemKind, - Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason, - VERSION_PLACEHOLDER, Variant, + PartialConstStability, Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, + UnstableReason, VERSION_PLACEHOLDER, Variant, }; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; @@ -118,6 +118,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { 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 mut is_deprecated = false; if let Some((depr, span)) = &depr { @@ -151,10 +152,10 @@ 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( - find_attr!(attrs, AttributeKind::ConstStability { stability, .. } => stability.const_stable_indirect).unwrap_or_default(), - stab - )); + self.index.const_stab_map.insert( + def_id, + ConstStability::unmarked(const_stability_indirect, stab), + ); } } } @@ -210,7 +211,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { .dcx() .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } - StableSince::Version(stab_since) => { + StableSince::Version(stab_since, _) => { if dep_since < stab_since { self.tcx .dcx() @@ -269,7 +270,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); } - // TODO: fn_sig.is_some_and(|s| s.header.is_const()), // If this is marked const *stable*, it must also be regular-stable. if let Some((const_stab, const_span)) = const_stab && let Some(fn_sig) = fn_sig @@ -284,9 +284,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(( - ConstStability { - level: StabilityLevel::Unstable { .. }, feature, .. - }, + PartialConstStability { level: StabilityLevel::Stable { .. }, feature, .. }, const_span, )) = const_stab { @@ -298,9 +296,17 @@ 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)| stab); + let mut const_stab = const_stab + .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect)); // 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() && @@ -786,8 +792,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); - // TODO: matches!(constness, Constness::Const), - let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => stability); + // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem + let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 846bf6bd526a6..b477bdf7aed8b 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -3,6 +3,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_ast_pretty::pprust; +use rustc_attr::OmitDoc; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -139,7 +140,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.resolver.tcx.features(), Vec::new(), ); - let attrs = parser.parse_attribute_list(&i.attrs, i.span); + let attrs = parser.parse_attribute_list(&i.attrs, i.span, OmitDoc::Skip); let macro_data = self.resolver.compile_macro(def, i.ident, &attrs, i.span, i.id, edition); diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index f20674f0715d4..dcf86d1a4089f 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -29,8 +29,6 @@ pub mod output; pub use getopts; -mod version; - rustc_fluent_macro::fluent_messages! { "../messages.ftl" } /// Requirements for a `StableHashingContext` to be used in this crate. diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs deleted file mode 100644 index 8b137891791fe..0000000000000 --- a/compiler/rustc_session/src/version.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 209a2a393273b..ca5d0be20473e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -6,12 +6,11 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_hir::{ConstStability, Deprecation, Stability, StableSince}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{BodyId, Mutability}; +use rustc_hir::{BodyId, ConstStability, Deprecation, Mutability, Stability, StableSince}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; use rustc_metadata::rendered_const; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index de8182b3f6fc7..d4a55b14b0e6c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,12 +15,12 @@ use std::iter::{self, once}; use itertools::Itertools; use rustc_abi::ExternAbi; -use rustc_hir::{ConstStability, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::{ConstStability, StabilityLevel, StableSince}; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::symbol::kw; diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index 9e37d5f50837d..8e84d8f3284df 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -4,12 +4,6 @@ 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 | @@ -27,6 +21,12 @@ 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 |