797 lines
30 KiB
Rust
797 lines
30 KiB
Rust
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::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::do_not_recommend::*;
|
|
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
|
|
AlignParser,
|
|
AlignStaticParser,
|
|
BodyStabilityParser,
|
|
ConfusablesParser,
|
|
ConstStabilityParser,
|
|
DocParser,
|
|
MacroUseParser,
|
|
NakedParser,
|
|
RustcCguTestAttributeParser,
|
|
StabilityParser,
|
|
UsedParser,
|
|
// tidy-alphabetical-end
|
|
|
|
// tidy-alphabetical-start
|
|
Combine<AllowConstFnUnstableParser>,
|
|
Combine<AllowInternalUnstableParser>,
|
|
Combine<CrateTypeParser>,
|
|
Combine<DebuggerViualizerParser>,
|
|
Combine<ForceTargetFeatureParser>,
|
|
Combine<LinkParser>,
|
|
Combine<ReprParser>,
|
|
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<DeprecationParser>,
|
|
Single<DoNotRecommendParser>,
|
|
Single<DummyParser>,
|
|
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<ObjcClassParser>,
|
|
Single<ObjcSelectorParser>,
|
|
Single<OptimizeParser>,
|
|
Single<PatchableFunctionEntryParser>,
|
|
Single<PathAttributeParser>,
|
|
Single<PatternComplexityLimitParser>,
|
|
Single<ProcMacroDeriveParser>,
|
|
Single<RecursionLimitParser>,
|
|
Single<ReexportTestHarnessMainParser>,
|
|
Single<RustcAbiParser>,
|
|
Single<RustcAllocatorZeroedVariantParser>,
|
|
Single<RustcBuiltinMacroParser>,
|
|
Single<RustcDefPath>,
|
|
Single<RustcDeprecatedSafe2024Parser>,
|
|
Single<RustcDiagnosticItemParser>,
|
|
Single<RustcForceInlineParser>,
|
|
Single<RustcIfThisChangedParser>,
|
|
Single<RustcLayoutScalarValidRangeEndParser>,
|
|
Single<RustcLayoutScalarValidRangeStartParser>,
|
|
Single<RustcLegacyConstGenericsParser>,
|
|
Single<RustcLintOptDenyFieldAccessParser>,
|
|
Single<RustcMustImplementOneOfParser>,
|
|
Single<RustcNeverTypeOptionsParser>,
|
|
Single<RustcReservationImplParser>,
|
|
Single<RustcScalableVectorParser>,
|
|
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
|
Single<RustcSymbolName>,
|
|
Single<RustcTestMarkerParser>,
|
|
Single<SanitizeParser>,
|
|
Single<ShouldPanicParser>,
|
|
Single<SkipDuringMethodDispatchParser>,
|
|
Single<TestRunnerParser>,
|
|
Single<TransparencyParser>,
|
|
Single<TypeLengthLimitParser>,
|
|
Single<WindowsSubsystemParser>,
|
|
Single<WithoutArgs<AllowIncoherentImplParser>>,
|
|
Single<WithoutArgs<AllowInternalUnsafeParser>>,
|
|
Single<WithoutArgs<AsPtrParser>>,
|
|
Single<WithoutArgs<AutomaticallyDerivedParser>>,
|
|
Single<WithoutArgs<CoinductiveParser>>,
|
|
Single<WithoutArgs<ColdParser>>,
|
|
Single<WithoutArgs<CompilerBuiltinsParser>>,
|
|
Single<WithoutArgs<ConstContinueParser>>,
|
|
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
|
Single<WithoutArgs<CoroutineParser>>,
|
|
Single<WithoutArgs<DefaultLibAllocatorParser>>,
|
|
Single<WithoutArgs<DenyExplicitImplParser>>,
|
|
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
|
Single<WithoutArgs<EiiForeignItemParser>>,
|
|
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<ParenSugarParser>>,
|
|
Single<WithoutArgs<PassByValueParser>>,
|
|
Single<WithoutArgs<PinV2Parser>>,
|
|
Single<WithoutArgs<PointeeParser>>,
|
|
Single<WithoutArgs<PreludeImportParser>>,
|
|
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
|
Single<WithoutArgs<ProcMacroParser>>,
|
|
Single<WithoutArgs<ProfilerRuntimeParser>>,
|
|
Single<WithoutArgs<PubTransparentParser>>,
|
|
Single<WithoutArgs<RustcAllocatorParser>>,
|
|
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
|
|
Single<WithoutArgs<RustcCaptureAnalysisParser>>,
|
|
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
|
Single<WithoutArgs<RustcConversionSuggestionParser>>,
|
|
Single<WithoutArgs<RustcDeallocatorParser>>,
|
|
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
|
Single<WithoutArgs<RustcDoNotConstCheckParser>>,
|
|
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
|
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
|
|
Single<WithoutArgs<RustcDumpPredicatesParser>>,
|
|
Single<WithoutArgs<RustcDumpUserArgsParser>>,
|
|
Single<WithoutArgs<RustcDumpVtableParser>>,
|
|
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
|
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
|
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
|
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
|
Single<WithoutArgs<RustcInsignificantDtorParser>>,
|
|
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
|
|
Single<WithoutArgs<RustcIntrinsicParser>>,
|
|
Single<WithoutArgs<RustcLintOptTyParser>>,
|
|
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
|
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
|
Single<WithoutArgs<RustcMainParser>>,
|
|
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
|
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
|
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
|
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
|
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
|
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
|
|
Single<WithoutArgs<RustcNounwindParser>>,
|
|
Single<WithoutArgs<RustcObjectLifetimeDefaultParser>>,
|
|
Single<WithoutArgs<RustcOffloadKernelParser>>,
|
|
Single<WithoutArgs<RustcOutlivesParser>>,
|
|
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
|
Single<WithoutArgs<RustcPreserveUbChecksParser>>,
|
|
Single<WithoutArgs<RustcProcMacroDeclsParser>>,
|
|
Single<WithoutArgs<RustcReallocatorParser>>,
|
|
Single<WithoutArgs<RustcRegionsParser>>,
|
|
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
|
Single<WithoutArgs<RustcStrictCoherenceParser>>,
|
|
Single<WithoutArgs<RustcTrivialFieldReadsParser>>,
|
|
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
|
|
Single<WithoutArgs<RustcVarianceParser>>,
|
|
Single<WithoutArgs<SpecializationTraitParser>>,
|
|
Single<WithoutArgs<StdInternalSymbolParser>>,
|
|
Single<WithoutArgs<ThreadLocalParser>>,
|
|
Single<WithoutArgs<TrackCallerParser>>,
|
|
Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
|
|
// 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(),
|
|
}
|
|
}
|
|
}
|