diff options
Diffstat (limited to 'compiler/rustc_attr_parsing/src/context.rs')
| -rw-r--r-- | compiler/rustc_attr_parsing/src/context.rs | 199 |
1 files changed, 178 insertions, 21 deletions
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 939f4a6fde7..1449680e35b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1,11 +1,10 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; -use rustc_ast::{self as ast, MetaItemLit, NodeId}; +use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId}; use rustc_attr_data_structures::AttributeKind; use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; @@ -14,16 +13,24 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; -use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::allow_unstable::{ + AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, +}; use crate::attributes::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser, - TrackCallerParser, UsedParser, + ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, + OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; -use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser}; -use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser}; +use crate::attributes::link_attrs::{ + ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser, + LinkSectionParser, StdInternalSymbolParser, +}; +use crate::attributes::lint_helpers::{ + AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, +}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; @@ -39,7 +46,12 @@ use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; use crate::attributes::test_attrs::IgnoreParser; -use crate::attributes::traits::SkipDuringMethodDispatchParser; +use crate::attributes::traits::{ + AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, + DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, + ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, + TypeConstParser, UnsafeSpecializationMarkerParser, +}; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; @@ -123,14 +135,17 @@ attribute_parsers!( Combine<AllowInternalUnstableParser>, Combine<ReprParser>, Combine<TargetFeatureParser>, + Combine<UnstableFeatureBoundParser>, // tidy-alphabetical-end // tidy-alphabetical-start Single<DeprecationParser>, + Single<DummyParser>, Single<ExportNameParser>, Single<IgnoreParser>, Single<InlineParser>, Single<LinkNameParser>, + Single<LinkOrdinalParser>, Single<LinkSectionParser>, Single<MustUseParser>, Single<OptimizeParser>, @@ -141,18 +156,37 @@ attribute_parsers!( Single<RustcObjectLifetimeDefaultParser>, Single<SkipDuringMethodDispatchParser>, Single<TransparencyParser>, + Single<WithoutArgs<AllowIncoherentImplParser>>, Single<WithoutArgs<AsPtrParser>>, + Single<WithoutArgs<AutomaticallyDerivedParser>>, + Single<WithoutArgs<CoherenceIsCoreParser>>, + Single<WithoutArgs<CoinductiveParser>>, Single<WithoutArgs<ColdParser>>, Single<WithoutArgs<ConstContinueParser>>, Single<WithoutArgs<ConstStabilityIndirectParser>>, + Single<WithoutArgs<ConstTraitParser>>, + Single<WithoutArgs<DenyExplicitImplParser>>, + Single<WithoutArgs<DoNotImplementViaObjectParser>>, + Single<WithoutArgs<ExportStableParser>>, + Single<WithoutArgs<FfiConstParser>>, + Single<WithoutArgs<FfiPureParser>>, + Single<WithoutArgs<FundamentalParser>>, Single<WithoutArgs<LoopMatchParser>>, + Single<WithoutArgs<MarkerParser>>, Single<WithoutArgs<MayDangleParser>>, Single<WithoutArgs<NoImplicitPreludeParser>>, Single<WithoutArgs<NoMangleParser>>, Single<WithoutArgs<NonExhaustiveParser>>, + Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>, + Single<WithoutArgs<ParenSugarParser>>, Single<WithoutArgs<PassByValueParser>>, + Single<WithoutArgs<PointeeParser>>, Single<WithoutArgs<PubTransparentParser>>, + Single<WithoutArgs<SpecializationTraitParser>>, + Single<WithoutArgs<StdInternalSymbolParser>>, Single<WithoutArgs<TrackCallerParser>>, + Single<WithoutArgs<TypeConstParser>>, + Single<WithoutArgs<UnsafeSpecializationMarkerParser>>, // tidy-alphabetical-end ]; ); @@ -171,7 +205,11 @@ pub trait Stage: Sized + 'static + Sealed { fn parsers() -> &'static group_type!(Self); - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed; + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed; } // allow because it's a sealed trait @@ -183,8 +221,16 @@ impl Stage for Early { fn parsers() -> &'static group_type!(Self) { &early::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - sess.dcx().create_err(diag).delay_as_bug() + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { + if self.emit_errors.should_emit() { + sess.dcx().emit_err(diag) + } else { + sess.dcx().create_err(diag).delay_as_bug() + } } } @@ -197,20 +243,29 @@ impl Stage for Late { fn parsers() -> &'static group_type!(Self) { &late::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + fn emit_err<'sess>( + &self, + tcx: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { tcx.dcx().emit_err(diag) } } /// used when parsing attributes for miscellaneous things *before* ast lowering -pub struct Early; +pub struct Early { + /// Whether to emit errors or delay them as a bug + /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed + /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted + pub emit_errors: ShouldEmit, +} /// used when parsing attributes during ast lowering pub struct Late; /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { +pub struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) shared: SharedContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, @@ -226,7 +281,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - S::emit_err(&self.sess, diag) + self.stage.emit_err(&self.sess, diag) } /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing @@ -441,7 +496,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct SharedContext<'p, 'sess, S: Stage> { +pub struct SharedContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. pub(crate) cx: &'p mut AttributeParser<'sess, S>, @@ -503,13 +558,32 @@ pub enum OmitDoc { Skip, } +#[derive(Copy, Clone)] +pub enum ShouldEmit { + /// The operation will emit errors and lints. + /// This is usually what you need. + ErrorsAndLints, + /// The operation will emit *not* errors and lints. + /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`. + Nothing, +} + +impl ShouldEmit { + pub fn should_emit(&self) -> bool { + match self { + ShouldEmit::ErrorsAndLints => true, + ShouldEmit::Nothing => false, + } + } +} + /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { pub(crate) tools: Vec<Symbol>, features: Option<&'sess Features>, sess: &'sess Session, - stage: PhantomData<S>, + stage: S, /// *Only* parse attributes with this symbol. /// @@ -538,13 +612,14 @@ impl<'sess> AttributeParser<'sess, Early> { sym: Symbol, target_span: Span, target_node_id: NodeId, + features: Option<&'sess Features>, ) -> Option<Attribute> { let mut p = Self { - features: None, + features, tools: Vec::new(), parse_only: Some(sym), sess, - stage: PhantomData, + stage: Early { emit_errors: ShouldEmit::Nothing }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -560,11 +635,55 @@ impl<'sess> AttributeParser<'sess, Early> { parsed.pop() } + + pub fn parse_single<T>( + sess: &'sess Session, + attr: &ast::Attribute, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: ShouldEmit, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, + template: &AttributeTemplate, + ) -> T { + let mut parser = Self { + features, + tools: Vec::new(), + parse_only: None, + sess, + stage: Early { emit_errors }, + }; + let ast::AttrKind::Normal(normal_attr) = &attr.kind else { + panic!("parse_single called on a doc attr") + }; + let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx()); + let path = meta_parser.path(); + let args = meta_parser.args(); + let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { + shared: SharedContext { + cx: &mut parser, + target_span, + target_id: target_node_id, + emit_lint: &mut |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + }, + attr_span: attr.span, + template, + attr_path: path.get_attribute_path(), + }; + parse_fn(&mut cx, args) + } } impl<'sess, S: Stage> AttributeParser<'sess, S> { - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + pub fn new( + sess: &'sess Session, + features: &'sess Features, + tools: Vec<Symbol>, + stage: S, + ) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage } } pub(crate) fn sess(&self) -> &'sess Session { @@ -575,6 +694,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { self.features.expect("features not available at this point in the compiler") } + pub(crate) fn features_option(&self) -> Option<&'sess Features> { + self.features + } + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { self.sess().dcx() } @@ -709,6 +832,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes } + /// Returns whether there is a parser for an attribute with this name + pub fn is_parsed_attribute(path: &[Symbol]) -> bool { + Late::parsers().0.contains_key(path) + } + fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { match args { ast::AttrArgs::Empty => AttrArgs::Empty, @@ -741,3 +869,32 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } } + +/// Parse a single integer. +/// +/// Used by attributes that take a single integer as argument, such as +/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`. +/// `cx` is the context given to the attribute. +/// `args` is the parser for the attribute arguments. +pub(crate) fn parse_single_integer<S: Stage>( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, +) -> Option<u128> { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(lit) = single.lit() else { + cx.expected_integer_literal(single.span()); + return None; + }; + let LitKind::Int(num, _ty) = lit.kind else { + cx.expected_integer_literal(single.span()); + return None; + }; + Some(num.0) +} |
