| use std::cell::RefCell; | |
| use std::collections::BTreeMap; | |
| use std::collections::btree_map::Entry; | |
| use std::ops::{Deref, DerefMut}; | |
| use std::sync::LazyLock; | |
| use private::Sealed; | |
| use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; | |
| use rustc_errors::{Diag, Diagnostic, Level}; | |
| use rustc_feature::{AttrSuggestionStyle, AttributeTemplate}; | |
| use rustc_hir::attrs::AttributeKind; | |
| use rustc_hir::lints::AttributeLintKind; | |
| use rustc_hir::{AttrPath, HirId}; | |
| use rustc_parse::parser::Recovery; | |
| use rustc_session::Session; | |
| use rustc_session::lint::{Lint, LintId}; | |
| use rustc_span::{ErrorGuaranteed, Span, Symbol}; | |
| use crate::AttributeParser; | |
| // Glob imports to avoid big, bitrotty import lists | |
| use crate::attributes::allow_unstable::*; | |
| use crate::attributes::autodiff::*; | |
| use crate::attributes::body::*; | |
| use crate::attributes::cfi_encoding::*; | |
| use crate::attributes::codegen_attrs::*; | |
| use crate::attributes::confusables::*; | |
| use crate::attributes::crate_level::*; | |
| use crate::attributes::debugger::*; | |
| use crate::attributes::deprecation::*; | |
| use crate::attributes::diagnostic::do_not_recommend::*; | |
| use crate::attributes::diagnostic::on_const::*; | |
| use crate::attributes::diagnostic::on_move::*; | |
| use crate::attributes::diagnostic::on_unimplemented::*; | |
| use crate::attributes::doc::*; | |
| use crate::attributes::dummy::*; | |
| use crate::attributes::inline::*; | |
| use crate::attributes::instruction_set::*; | |
| use crate::attributes::link_attrs::*; | |
| use crate::attributes::lint_helpers::*; | |
| use crate::attributes::loop_match::*; | |
| use crate::attributes::macro_attrs::*; | |
| use crate::attributes::must_not_suspend::*; | |
| use crate::attributes::must_use::*; | |
| use crate::attributes::no_implicit_prelude::*; | |
| use crate::attributes::no_link::*; | |
| use crate::attributes::non_exhaustive::*; | |
| use crate::attributes::path::PathParser as PathAttributeParser; | |
| use crate::attributes::pin_v2::*; | |
| use crate::attributes::proc_macro_attrs::*; | |
| use crate::attributes::prototype::*; | |
| use crate::attributes::repr::*; | |
| use crate::attributes::rustc_allocator::*; | |
| use crate::attributes::rustc_dump::*; | |
| use crate::attributes::rustc_internal::*; | |
| use crate::attributes::semantics::*; | |
| use crate::attributes::stability::*; | |
| use crate::attributes::test_attrs::*; | |
| use crate::attributes::traits::*; | |
| use crate::attributes::transparency::*; | |
| use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; | |
| use crate::parser::{ArgParser, RefPathParser}; | |
| use crate::session_diagnostics::{ | |
| AttributeParseError, AttributeParseErrorReason, ParsedDescription, | |
| }; | |
| use crate::target_checking::AllowedTargets; | |
| type GroupType<S> = LazyLock<GroupTypeInner<S>>; | |
| pub(super) struct GroupTypeInner<S: Stage> { | |
| pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept<S>>, | |
| } | |
| pub(super) struct GroupTypeInnerAccept<S: Stage> { | |
| pub(super) template: AttributeTemplate, | |
| pub(super) accept_fn: AcceptFn<S>, | |
| pub(super) allowed_targets: AllowedTargets, | |
| pub(super) finalizer: FinalizeFn<S>, | |
| } | |
| pub(crate) type AcceptFn<S> = | |
| Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>; | |
| pub(crate) type FinalizeFn<S> = | |
| Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>; | |
| macro_rules! attribute_parsers { | |
| ( | |
| pub(crate) static $name: ident = [$($names: ty),* $(,)?]; | |
| ) => { | |
| mod early { | |
| use super::*; | |
| type Combine<T> = super::Combine<T, Early>; | |
| type Single<T> = super::Single<T, Early>; | |
| type WithoutArgs<T> = super::WithoutArgs<T, Early>; | |
| attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];); | |
| } | |
| mod late { | |
| use super::*; | |
| type Combine<T> = super::Combine<T, Late>; | |
| type Single<T> = super::Single<T, Late>; | |
| type WithoutArgs<T> = super::WithoutArgs<T, Late>; | |
| attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];); | |
| } | |
| }; | |
| ( | |
| @[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; | |
| ) => { | |
| pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| { | |
| let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new(); | |
| $( | |
| { | |
| thread_local! { | |
| static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default()); | |
| }; | |
| for (path, template, accept_fn) in <$names>::ATTRIBUTES { | |
| match accepters.entry(*path) { | |
| Entry::Vacant(e) => { | |
| e.insert(GroupTypeInnerAccept { | |
| template: *template, | |
| accept_fn: Box::new(|cx, args| { | |
| STATE_OBJECT.with_borrow_mut(|s| { | |
| accept_fn(s, cx, args) | |
| }) | |
| }), | |
| allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, | |
| finalizer: Box::new(|cx| { | |
| let state = STATE_OBJECT.take(); | |
| state.finalize(cx) | |
| }) | |
| }); | |
| } | |
| Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"), | |
| } | |
| } | |
| } | |
| )* | |
| GroupTypeInner { accepters } | |
| }); | |
| }; | |
| } | |
| attribute_parsers!( | |
| pub(crate) static ATTRIBUTE_PARSERS = [ | |
| // tidy-alphabetical-start | |
| BodyStabilityParser, | |
| ConfusablesParser, | |
| ConstStabilityParser, | |
| DocParser, | |
| MacroUseParser, | |
| NakedParser, | |
| OnConstParser, | |
| OnMoveParser, | |
| OnUnimplementedParser, | |
| RustcAlignParser, | |
| RustcAlignStaticParser, | |
| RustcCguTestAttributeParser, | |
| StabilityParser, | |
| UsedParser, | |
| // tidy-alphabetical-end | |
| // tidy-alphabetical-start | |
| Combine<AllowInternalUnstableParser>, | |
| Combine<CrateTypeParser>, | |
| Combine<DebuggerViualizerParser>, | |
| Combine<FeatureParser>, | |
| Combine<ForceTargetFeatureParser>, | |
| Combine<LinkParser>, | |
| Combine<RegisterToolParser>, | |
| Combine<ReprParser>, | |
| Combine<RustcAllowConstFnUnstableParser>, | |
| Combine<RustcCleanParser>, | |
| Combine<RustcLayoutParser>, | |
| Combine<RustcMirParser>, | |
| Combine<RustcThenThisWouldNeedParser>, | |
| Combine<TargetFeatureParser>, | |
| Combine<UnstableFeatureBoundParser>, | |
| // tidy-alphabetical-end | |
| // tidy-alphabetical-start | |
| Single<CfiEncodingParser>, | |
| Single<CollapseDebugInfoParser>, | |
| Single<CoverageParser>, | |
| Single<CrateNameParser>, | |
| Single<CustomMirParser>, | |
| Single<DeprecatedParser>, | |
| Single<DoNotRecommendParser>, | |
| Single<ExportNameParser>, | |
| Single<IgnoreParser>, | |
| Single<InlineParser>, | |
| Single<InstructionSetParser>, | |
| Single<LangParser>, | |
| Single<LinkNameParser>, | |
| Single<LinkOrdinalParser>, | |
| Single<LinkSectionParser>, | |
| Single<LinkageParser>, | |
| Single<MacroExportParser>, | |
| Single<MoveSizeLimitParser>, | |
| Single<MustNotSuspendParser>, | |
| Single<MustUseParser>, | |
| Single<OptimizeParser>, | |
| Single<PatchableFunctionEntryParser>, | |
| Single<PathAttributeParser>, | |
| Single<PatternComplexityLimitParser>, | |
| Single<ProcMacroDeriveParser>, | |
| Single<RecursionLimitParser>, | |
| Single<ReexportTestHarnessMainParser>, | |
| Single<RustcAbiParser>, | |
| Single<RustcAllocatorZeroedVariantParser>, | |
| Single<RustcAutodiffParser>, | |
| Single<RustcBuiltinMacroParser>, | |
| Single<RustcDefPathParser>, | |
| Single<RustcDeprecatedSafe2024Parser>, | |
| Single<RustcDiagnosticItemParser>, | |
| Single<RustcDocPrimitiveParser>, | |
| Single<RustcDummyParser>, | |
| Single<RustcForceInlineParser>, | |
| Single<RustcIfThisChangedParser>, | |
| Single<RustcLayoutScalarValidRangeEndParser>, | |
| Single<RustcLayoutScalarValidRangeStartParser>, | |
| Single<RustcLegacyConstGenericsParser>, | |
| Single<RustcLintOptDenyFieldAccessParser>, | |
| Single<RustcMacroTransparencyParser>, | |
| Single<RustcMustImplementOneOfParser>, | |
| Single<RustcNeverTypeOptionsParser>, | |
| Single<RustcObjcClassParser>, | |
| Single<RustcObjcSelectorParser>, | |
| Single<RustcReservationImplParser>, | |
| Single<RustcScalableVectorParser>, | |
| Single<RustcSimdMonomorphizeLaneLimitParser>, | |
| Single<RustcSkipDuringMethodDispatchParser>, | |
| Single<RustcSymbolNameParser>, | |
| Single<RustcTestMarkerParser>, | |
| Single<SanitizeParser>, | |
| Single<ShouldPanicParser>, | |
| Single<TestRunnerParser>, | |
| Single<TypeLengthLimitParser>, | |
| Single<WindowsSubsystemParser>, | |
| Single<WithoutArgs<AllowInternalUnsafeParser>>, | |
| Single<WithoutArgs<AutomaticallyDerivedParser>>, | |
| Single<WithoutArgs<ColdParser>>, | |
| Single<WithoutArgs<CompilerBuiltinsParser>>, | |
| Single<WithoutArgs<ConstContinueParser>>, | |
| Single<WithoutArgs<CoroutineParser>>, | |
| Single<WithoutArgs<DefaultLibAllocatorParser>>, | |
| Single<WithoutArgs<ExportStableParser>>, | |
| Single<WithoutArgs<FfiConstParser>>, | |
| Single<WithoutArgs<FfiPureParser>>, | |
| Single<WithoutArgs<FundamentalParser>>, | |
| Single<WithoutArgs<LoopMatchParser>>, | |
| Single<WithoutArgs<MacroEscapeParser>>, | |
| Single<WithoutArgs<MarkerParser>>, | |
| Single<WithoutArgs<MayDangleParser>>, | |
| Single<WithoutArgs<NeedsAllocatorParser>>, | |
| Single<WithoutArgs<NeedsPanicRuntimeParser>>, | |
| Single<WithoutArgs<NoBuiltinsParser>>, | |
| Single<WithoutArgs<NoCoreParser>>, | |
| Single<WithoutArgs<NoImplicitPreludeParser>>, | |
| Single<WithoutArgs<NoLinkParser>>, | |
| Single<WithoutArgs<NoMainParser>>, | |
| Single<WithoutArgs<NoMangleParser>>, | |
| Single<WithoutArgs<NoStdParser>>, | |
| Single<WithoutArgs<NonExhaustiveParser>>, | |
| Single<WithoutArgs<PanicHandlerParser>>, | |
| Single<WithoutArgs<PanicRuntimeParser>>, | |
| Single<WithoutArgs<PinV2Parser>>, | |
| Single<WithoutArgs<PointeeParser>>, | |
| Single<WithoutArgs<PreludeImportParser>>, | |
| Single<WithoutArgs<ProcMacroAttributeParser>>, | |
| Single<WithoutArgs<ProcMacroParser>>, | |
| Single<WithoutArgs<ProfilerRuntimeParser>>, | |
| Single<WithoutArgs<RustcAllocatorParser>>, | |
| Single<WithoutArgs<RustcAllocatorZeroedParser>>, | |
| Single<WithoutArgs<RustcAllowIncoherentImplParser>>, | |
| Single<WithoutArgs<RustcAsPtrParser>>, | |
| Single<WithoutArgs<RustcCaptureAnalysisParser>>, | |
| Single<WithoutArgs<RustcCoherenceIsCoreParser>>, | |
| Single<WithoutArgs<RustcCoinductiveParser>>, | |
| Single<WithoutArgs<RustcConstStableIndirectParser>>, | |
| Single<WithoutArgs<RustcConversionSuggestionParser>>, | |
| Single<WithoutArgs<RustcDeallocatorParser>>, | |
| Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>, | |
| Single<WithoutArgs<RustcDenyExplicitImplParser>>, | |
| Single<WithoutArgs<RustcDoNotConstCheckParser>>, | |
| Single<WithoutArgs<RustcDumpDefParentsParser>>, | |
| Single<WithoutArgs<RustcDumpInferredOutlivesParser>>, | |
| Single<WithoutArgs<RustcDumpItemBoundsParser>>, | |
| Single<WithoutArgs<RustcDumpObjectLifetimeDefaultsParser>>, | |
| Single<WithoutArgs<RustcDumpPredicatesParser>>, | |
| Single<WithoutArgs<RustcDumpUserArgsParser>>, | |
| Single<WithoutArgs<RustcDumpVariancesOfOpaquesParser>>, | |
| Single<WithoutArgs<RustcDumpVariancesParser>>, | |
| Single<WithoutArgs<RustcDumpVtableParser>>, | |
| Single<WithoutArgs<RustcDynIncompatibleTraitParser>>, | |
| Single<WithoutArgs<RustcEffectiveVisibilityParser>>, | |
| Single<WithoutArgs<RustcEiiForeignItemParser>>, | |
| Single<WithoutArgs<RustcEvaluateWhereClausesParser>>, | |
| Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>, | |
| Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>, | |
| Single<WithoutArgs<RustcInheritOverflowChecksParser>>, | |
| Single<WithoutArgs<RustcInsignificantDtorParser>>, | |
| Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>, | |
| Single<WithoutArgs<RustcIntrinsicParser>>, | |
| Single<WithoutArgs<RustcLintOptTyParser>>, | |
| Single<WithoutArgs<RustcLintQueryInstabilityParser>>, | |
| Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>, | |
| Single<WithoutArgs<RustcMainParser>>, | |
| Single<WithoutArgs<RustcNeverReturnsNullPtrParser>>, | |
| Single<WithoutArgs<RustcNoImplicitAutorefsParser>>, | |
| Single<WithoutArgs<RustcNoImplicitBoundsParser>>, | |
| Single<WithoutArgs<RustcNoMirInlineParser>>, | |
| Single<WithoutArgs<RustcNonConstTraitMethodParser>>, | |
| Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>, | |
| Single<WithoutArgs<RustcNounwindParser>>, | |
| Single<WithoutArgs<RustcOffloadKernelParser>>, | |
| Single<WithoutArgs<RustcParenSugarParser>>, | |
| Single<WithoutArgs<RustcPassByValueParser>>, | |
| Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>, | |
| Single<WithoutArgs<RustcPreserveUbChecksParser>>, | |
| Single<WithoutArgs<RustcProcMacroDeclsParser>>, | |
| Single<WithoutArgs<RustcPubTransparentParser>>, | |
| Single<WithoutArgs<RustcReallocatorParser>>, | |
| Single<WithoutArgs<RustcRegionsParser>>, | |
| Single<WithoutArgs<RustcShouldNotBeCalledOnConstItemsParser>>, | |
| Single<WithoutArgs<RustcSpecializationTraitParser>>, | |
| Single<WithoutArgs<RustcStdInternalSymbolParser>>, | |
| Single<WithoutArgs<RustcStrictCoherenceParser>>, | |
| Single<WithoutArgs<RustcTrivialFieldReadsParser>>, | |
| Single<WithoutArgs<RustcUnsafeSpecializationMarkerParser>>, | |
| Single<WithoutArgs<ThreadLocalParser>>, | |
| Single<WithoutArgs<TrackCallerParser>>, | |
| // tidy-alphabetical-end | |
| ]; | |
| ); | |
| mod private { | |
| pub trait Sealed {} | |
| impl Sealed for super::Early {} | |
| impl Sealed for super::Late {} | |
| } | |
| // allow because it's a sealed trait | |
| #[allow(private_interfaces)] | |
| pub trait Stage: Sized + 'static + Sealed { | |
| type Id: Copy; | |
| fn parsers() -> &'static GroupType<Self>; | |
| fn emit_err<'sess>( | |
| &self, | |
| sess: &'sess Session, | |
| diag: impl for<'x> Diagnostic<'x>, | |
| ) -> ErrorGuaranteed; | |
| fn should_emit(&self) -> ShouldEmit; | |
| } | |
| // allow because it's a sealed trait | |
| #[allow(private_interfaces)] | |
| impl Stage for Early { | |
| type Id = NodeId; | |
| fn parsers() -> &'static GroupType<Self> { | |
| &early::ATTRIBUTE_PARSERS | |
| } | |
| fn emit_err<'sess>( | |
| &self, | |
| sess: &'sess Session, | |
| diag: impl for<'x> Diagnostic<'x>, | |
| ) -> ErrorGuaranteed { | |
| self.should_emit().emit_err(sess.dcx().create_err(diag)) | |
| } | |
| fn should_emit(&self) -> ShouldEmit { | |
| self.emit_errors | |
| } | |
| } | |
| // allow because it's a sealed trait | |
| #[allow(private_interfaces)] | |
| impl Stage for Late { | |
| type Id = HirId; | |
| fn parsers() -> &'static GroupType<Self> { | |
| &late::ATTRIBUTE_PARSERS | |
| } | |
| fn emit_err<'sess>( | |
| &self, | |
| tcx: &'sess Session, | |
| diag: impl for<'x> Diagnostic<'x>, | |
| ) -> ErrorGuaranteed { | |
| tcx.dcx().emit_err(diag) | |
| } | |
| fn should_emit(&self) -> ShouldEmit { | |
| ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed } | |
| } | |
| } | |
| /// used when parsing attributes for miscellaneous things *before* ast lowering | |
| 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 struct AcceptContext<'f, 'sess, S: Stage> { | |
| pub(crate) shared: SharedContext<'f, 'sess, S>, | |
| /// The outer span of the attribute currently being parsed | |
| /// #[attribute(...)] | |
| /// ^^^^^^^^^^^^^^^^^ outer span | |
| /// For attributes in `cfg_attr`, the outer span and inner spans are equal. | |
| pub(crate) attr_span: Span, | |
| /// The inner span of the attribute currently being parsed | |
| /// #[attribute(...)] | |
| /// ^^^^^^^^^^^^^^ inner span | |
| pub(crate) inner_span: Span, | |
| /// Whether it is an inner or outer attribute | |
| pub(crate) attr_style: AttrStyle, | |
| /// A description of the thing we are parsing using this attribute parser | |
| /// We are not only using these parsers for attributes, but also for macros such as the `cfg!()` macro. | |
| pub(crate) parsed_description: ParsedDescription, | |
| /// The expected structure of the attribute. | |
| /// | |
| /// Used in reporting errors to give a hint to users what the attribute *should* look like. | |
| pub(crate) template: &'f AttributeTemplate, | |
| /// The name of the attribute we're currently accepting. | |
| pub(crate) attr_path: AttrPath, | |
| } | |
| impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { | |
| pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { | |
| self.stage.emit_err(&self.sess, diag) | |
| } | |
| /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing | |
| /// must be delayed until after HIR is built. This method will take care of the details of | |
| /// that. | |
| pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) { | |
| if !matches!( | |
| self.stage.should_emit(), | |
| ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true } | |
| ) { | |
| return; | |
| } | |
| (self.emit_lint)(LintId::of(lint), span, kind); | |
| } | |
| pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { | |
| self.emit_lint( | |
| rustc_session::lint::builtin::UNUSED_ATTRIBUTES, | |
| AttributeLintKind::UnusedDuplicate { | |
| this: unused_span, | |
| other: used_span, | |
| warning: false, | |
| }, | |
| unused_span, | |
| ) | |
| } | |
| pub(crate) fn warn_unused_duplicate_future_error( | |
| &mut self, | |
| used_span: Span, | |
| unused_span: Span, | |
| ) { | |
| self.emit_lint( | |
| rustc_session::lint::builtin::UNUSED_ATTRIBUTES, | |
| AttributeLintKind::UnusedDuplicate { | |
| this: unused_span, | |
| other: used_span, | |
| warning: true, | |
| }, | |
| unused_span, | |
| ) | |
| } | |
| } | |
| impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { | |
| fn emit_parse_error( | |
| &self, | |
| span: Span, | |
| reason: AttributeParseErrorReason<'_>, | |
| ) -> ErrorGuaranteed { | |
| self.emit_err(AttributeParseError { | |
| span, | |
| attr_span: self.attr_span, | |
| template: self.template.clone(), | |
| path: self.attr_path.clone(), | |
| description: self.parsed_description, | |
| reason, | |
| suggestions: self.suggestions(), | |
| }) | |
| } | |
| /// error that a string literal was expected. | |
| /// You can optionally give the literal you did find (which you found not to be a string literal) | |
| /// which can make better errors. For example, if the literal was a byte string it will suggest | |
| /// removing the `b` prefix. | |
| pub(crate) fn expected_string_literal( | |
| &self, | |
| span: Span, | |
| actual_literal: Option<&MetaItemLit>, | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedStringLiteral { | |
| byte_string: actual_literal.and_then(|i| { | |
| i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) | |
| }), | |
| }, | |
| ) | |
| } | |
| /// Error that a filename string literal was expected. | |
| pub(crate) fn expected_filename_literal(&self, span: Span) { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedFilenameLiteral); | |
| } | |
| pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral) | |
| } | |
| pub(crate) fn expected_integer_literal_in_range( | |
| &self, | |
| span: Span, | |
| lower_bound: isize, | |
| upper_bound: isize, | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound }, | |
| ) | |
| } | |
| pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed { | |
| let span = match args { | |
| ArgParser::NoArgs => span, | |
| ArgParser::List(list) => list.span, | |
| ArgParser::NameValue(nv) => nv.args_span(), | |
| }; | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList) | |
| } | |
| pub(crate) fn expected_list_with_num_args_or_more( | |
| &self, | |
| args: usize, | |
| span: Span, | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedListWithNumArgsOrMore { args }, | |
| ) | |
| } | |
| pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs) | |
| } | |
| pub(crate) fn expected_nv_or_no_args(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValueOrNoArgs) | |
| } | |
| pub(crate) fn expected_non_empty_string_literal(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNonEmptyStringLiteral) | |
| } | |
| pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNoArgs) | |
| } | |
| /// emit an error that a `name` was expected here | |
| pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIdentifier) | |
| } | |
| /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for | |
| /// a nicer error message talking about the specific name that was found lacking a value. | |
| pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name)) | |
| } | |
| /// emit an error that a `name = value` pair was found where that name was already seen. | |
| pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key)) | |
| } | |
| /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser) | |
| /// was expected *not* to be a literal, but instead a meta item. | |
| pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::UnexpectedLiteral) | |
| } | |
| pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument) | |
| } | |
| pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed { | |
| self.emit_parse_error(span, AttributeParseErrorReason::ExpectedAtLeastOneArgument) | |
| } | |
| /// produces an error along the lines of `expected one of [foo, meow]` | |
| pub(crate) fn expected_specific_argument( | |
| &self, | |
| span: Span, | |
| possibilities: &[Symbol], | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedSpecificArgument { | |
| possibilities, | |
| strings: false, | |
| list: false, | |
| }, | |
| ) | |
| } | |
| /// produces an error along the lines of `expected one of [foo, meow] as an argument`. | |
| /// i.e. slightly different wording to [`expected_specific_argument`](Self::expected_specific_argument). | |
| pub(crate) fn expected_specific_argument_and_list( | |
| &self, | |
| span: Span, | |
| possibilities: &[Symbol], | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedSpecificArgument { | |
| possibilities, | |
| strings: false, | |
| list: true, | |
| }, | |
| ) | |
| } | |
| /// produces an error along the lines of `expected one of ["foo", "meow"]` | |
| pub(crate) fn expected_specific_argument_strings( | |
| &self, | |
| span: Span, | |
| possibilities: &[Symbol], | |
| ) -> ErrorGuaranteed { | |
| self.emit_parse_error( | |
| span, | |
| AttributeParseErrorReason::ExpectedSpecificArgument { | |
| possibilities, | |
| strings: true, | |
| list: false, | |
| }, | |
| ) | |
| } | |
| pub(crate) fn warn_empty_attribute(&mut self, span: Span) { | |
| let attr_path = self.attr_path.clone().to_string(); | |
| let valid_without_list = self.template.word; | |
| self.emit_lint( | |
| rustc_session::lint::builtin::UNUSED_ATTRIBUTES, | |
| AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, | |
| span, | |
| ); | |
| } | |
| pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) { | |
| let suggestions = self.suggestions(); | |
| let span = self.attr_span; | |
| self.emit_lint( | |
| lint, | |
| AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, | |
| span, | |
| ); | |
| } | |
| pub(crate) fn suggestions(&self) -> Vec<String> { | |
| let style = match self.parsed_description { | |
| // If the outer and inner spans are equal, we are parsing an embedded attribute | |
| ParsedDescription::Attribute if self.attr_span == self.inner_span => { | |
| AttrSuggestionStyle::EmbeddedAttribute | |
| } | |
| ParsedDescription::Attribute => AttrSuggestionStyle::Attribute(self.attr_style), | |
| ParsedDescription::Macro => AttrSuggestionStyle::Macro, | |
| }; | |
| self.template.suggestions(style, &self.attr_path) | |
| } | |
| } | |
| impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { | |
| type Target = SharedContext<'f, 'sess, S>; | |
| fn deref(&self) -> &Self::Target { | |
| &self.shared | |
| } | |
| } | |
| impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.shared | |
| } | |
| } | |
| /// Context given to every attribute parser during finalization. | |
| /// | |
| /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create | |
| /// errors, for example. | |
| 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>, | |
| /// The span of the syntactical component this attribute was applied to | |
| pub(crate) target_span: Span, | |
| pub(crate) target: rustc_hir::Target, | |
| /// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S` | |
| /// is `Late` and is the ID of the syntactical component this attribute was applied to. | |
| pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind), | |
| } | |
| /// 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<'p, 'sess, S: Stage> { | |
| pub(crate) shared: SharedContext<'p, 'sess, S>, | |
| /// A list of all attribute on this syntax node. | |
| /// | |
| /// Useful for compatibility checks with other attributes in [`finalize`](crate::attributes::AttributeParser::finalize) | |
| /// | |
| /// Usually, you should use normal attribute parsing logic instead, | |
| /// especially when making a *denylist* of other attributes. | |
| pub(crate) all_attrs: &'p [RefPathParser<'p>], | |
| } | |
| impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { | |
| type Target = SharedContext<'p, 'sess, S>; | |
| fn deref(&self) -> &Self::Target { | |
| &self.shared | |
| } | |
| } | |
| impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.shared | |
| } | |
| } | |
| impl<'p, 'sess: 'p, S: Stage> Deref for SharedContext<'p, 'sess, S> { | |
| type Target = AttributeParser<'sess, S>; | |
| fn deref(&self) -> &Self::Target { | |
| self.cx | |
| } | |
| } | |
| impl<'p, 'sess: 'p, S: Stage> DerefMut for SharedContext<'p, 'sess, S> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| self.cx | |
| } | |
| } | |
| #[derive(PartialEq, Clone, Copy, Debug)] | |
| pub enum OmitDoc { | |
| Lower, | |
| Skip, | |
| } | |
| #[derive(Copy, Clone, Debug)] | |
| pub enum ShouldEmit { | |
| /// The operations will emit errors, and lints, and errors are fatal. | |
| /// | |
| /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`. | |
| /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible. | |
| EarlyFatal { also_emit_lints: bool }, | |
| /// The operation will emit errors and lints. | |
| /// This is usually what you need. | |
| ErrorsAndLints { | |
| /// Whether [`ArgParser`] will attempt to recover from errors. | |
| /// | |
| /// Whether it is allowed to recover from bad input (like an invalid literal). Setting | |
| /// this to `Forbidden` will instead return early, and not raise errors except at the top | |
| /// level (in [`ArgParser::from_attr_args`]). | |
| recovery: Recovery, | |
| }, | |
| /// The operation will *not* emit errors and lints. | |
| /// | |
| /// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be | |
| /// called with `ShouldEmit::ErrorsAndLints`. | |
| Nothing, | |
| } | |
| impl ShouldEmit { | |
| pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed { | |
| match self { | |
| ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(), | |
| ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(), | |
| ShouldEmit::ErrorsAndLints { .. } => diag.emit(), | |
| ShouldEmit::Nothing => diag.delay_as_bug(), | |
| } | |
| } | |
| } |