Skip to content

Commit 4791dc5

Browse files
committed
split up context.rs
1 parent aa80ce1 commit 4791dc5

File tree

7 files changed

+360
-330
lines changed

7 files changed

+360
-330
lines changed

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
//! Specifically, you might not care about managing the state of your [`AttributeParser`]
88
//! state machine yourself. In this case you can choose to implement:
99
//!
10-
//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it
10+
//! - [`SingleAttributeParser`](crate::attributes::SingleAttributeParser): makes it easy to implement an attribute which should error if it
1111
//! appears more than once in a list of attributes
12-
//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
12+
//! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the
1313
//! contents of attributes, if an attribute appear multiple times in a list
1414
//!
1515
//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
@@ -286,7 +286,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
286286
}
287287
}
288288

289-
pub(super) type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind;
289+
type ConvertFn<E> = fn(ThinVec<E>, Span) -> AttributeKind;
290290

291291
/// Alternative to [`AttributeParser`] that automatically handles state management.
292292
/// If multiple attributes appear on an element, combines the values of each into a

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 15 additions & 322 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ use std::ops::{Deref, DerefMut};
44
use std::sync::LazyLock;
55

66
use private::Sealed;
7-
use rustc_ast::{self as ast, AttrStyle, MetaItemLit, NodeId};
8-
use rustc_errors::{DiagCtxtHandle, Diagnostic};
9-
use rustc_feature::{AttributeTemplate, Features};
7+
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
8+
use rustc_errors::Diagnostic;
9+
use rustc_feature::AttributeTemplate;
1010
use rustc_hir::attrs::AttributeKind;
1111
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
12-
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, Target};
12+
use rustc_hir::{AttrPath, HirId};
1313
use rustc_session::Session;
14-
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
14+
use rustc_span::{ErrorGuaranteed, Span, Symbol};
1515

16+
use crate::AttributeParser;
1617
use crate::attributes::allow_unstable::{
1718
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
1819
};
@@ -62,21 +63,21 @@ use crate::attributes::traits::{
6263
};
6364
use crate::attributes::transparency::TransparencyParser;
6465
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
65-
use crate::parser::{ArgParser, MetaItemParser, PathParser};
66+
use crate::parser::{ArgParser, PathParser};
6667
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
6768
use crate::target_checking::AllowedTargets;
6869

6970
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
7071

71-
struct GroupTypeInner<S: Stage> {
72-
accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
73-
finalizers: Vec<FinalizeFn<S>>,
72+
pub(super) struct GroupTypeInner<S: Stage> {
73+
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
74+
pub(super) finalizers: Vec<FinalizeFn<S>>,
7475
}
7576

76-
struct GroupTypeInnerAccept<S: Stage> {
77-
template: AttributeTemplate,
78-
accept_fn: AcceptFn<S>,
79-
allowed_targets: AllowedTargets,
77+
pub(super) struct GroupTypeInnerAccept<S: Stage> {
78+
pub(super) template: AttributeTemplate,
79+
pub(super) accept_fn: AcceptFn<S>,
80+
pub(super) allowed_targets: AllowedTargets,
8081
}
8182

8283
type AcceptFn<S> =
@@ -590,7 +591,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
590591
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
591592
pub(crate) target_id: S::Id,
592593

593-
emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
594+
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
594595
}
595596

596597
/// Context given to every attribute parser during finalization.
@@ -661,311 +662,3 @@ impl ShouldEmit {
661662
}
662663
}
663664
}
664-
665-
/// Context created once, for example as part of the ast lowering
666-
/// context, through which all attributes can be lowered.
667-
pub struct AttributeParser<'sess, S: Stage = Late> {
668-
pub(crate) tools: Vec<Symbol>,
669-
pub(crate) features: Option<&'sess Features>,
670-
sess: &'sess Session,
671-
stage: S,
672-
673-
/// *Only* parse attributes with this symbol.
674-
///
675-
/// Used in cases where we want the lowering infrastructure for parse just a single attribute.
676-
parse_only: Option<Symbol>,
677-
}
678-
679-
impl<'sess> AttributeParser<'sess, Early> {
680-
/// This method allows you to parse attributes *before* you have access to features or tools.
681-
/// One example where this is necessary, is to parse `feature` attributes themselves for
682-
/// example.
683-
///
684-
/// Try to use this as little as possible. Attributes *should* be lowered during
685-
/// `rustc_ast_lowering`. Some attributes require access to features to parse, which would
686-
/// crash if you tried to do so through [`parse_limited`](Self::parse_limited).
687-
///
688-
/// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
689-
/// that symbol are picked out of the list of instructions and parsed. Those are returned.
690-
///
691-
/// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
692-
/// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
693-
/// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
694-
pub fn parse_limited(
695-
sess: &'sess Session,
696-
attrs: &[ast::Attribute],
697-
sym: Symbol,
698-
target_span: Span,
699-
target_node_id: NodeId,
700-
features: Option<&'sess Features>,
701-
) -> Option<Attribute> {
702-
let mut p = Self {
703-
features,
704-
tools: Vec::new(),
705-
parse_only: Some(sym),
706-
sess,
707-
stage: Early { emit_errors: ShouldEmit::Nothing },
708-
};
709-
let mut parsed = p.parse_attribute_list(
710-
attrs,
711-
target_span,
712-
target_node_id,
713-
Target::Crate, // Does not matter, we're not going to emit errors anyways
714-
OmitDoc::Skip,
715-
std::convert::identity,
716-
|_lint| {
717-
panic!("can't emit lints here for now (nothing uses this atm)");
718-
},
719-
);
720-
assert!(parsed.len() <= 1);
721-
722-
parsed.pop()
723-
}
724-
725-
pub fn parse_single<T>(
726-
sess: &'sess Session,
727-
attr: &ast::Attribute,
728-
target_span: Span,
729-
target_node_id: NodeId,
730-
features: Option<&'sess Features>,
731-
emit_errors: ShouldEmit,
732-
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
733-
template: &AttributeTemplate,
734-
) -> T {
735-
let mut parser = Self {
736-
features,
737-
tools: Vec::new(),
738-
parse_only: None,
739-
sess,
740-
stage: Early { emit_errors },
741-
};
742-
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
743-
panic!("parse_single called on a doc attr")
744-
};
745-
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
746-
let path = meta_parser.path();
747-
let args = meta_parser.args();
748-
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
749-
shared: SharedContext {
750-
cx: &mut parser,
751-
target_span,
752-
target_id: target_node_id,
753-
emit_lint: &mut |_lint| {
754-
panic!("can't emit lints here for now (nothing uses this atm)");
755-
},
756-
},
757-
attr_span: attr.span,
758-
attr_style: attr.style,
759-
template,
760-
attr_path: path.get_attribute_path(),
761-
};
762-
parse_fn(&mut cx, args)
763-
}
764-
}
765-
766-
impl<'sess, S: Stage> AttributeParser<'sess, S> {
767-
pub fn new(
768-
sess: &'sess Session,
769-
features: &'sess Features,
770-
tools: Vec<Symbol>,
771-
stage: S,
772-
) -> Self {
773-
Self { features: Some(features), tools, parse_only: None, sess, stage }
774-
}
775-
776-
pub(crate) fn sess(&self) -> &'sess Session {
777-
&self.sess
778-
}
779-
780-
pub(crate) fn features(&self) -> &'sess Features {
781-
self.features.expect("features not available at this point in the compiler")
782-
}
783-
784-
pub(crate) fn features_option(&self) -> Option<&'sess Features> {
785-
self.features
786-
}
787-
788-
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
789-
self.sess().dcx()
790-
}
791-
792-
/// Parse a list of attributes.
793-
///
794-
/// `target_span` is the span of the thing this list of attributes is applied to,
795-
/// and when `omit_doc` is set, doc attributes are filtered out.
796-
pub fn parse_attribute_list(
797-
&mut self,
798-
attrs: &[ast::Attribute],
799-
target_span: Span,
800-
target_id: S::Id,
801-
target: Target,
802-
omit_doc: OmitDoc,
803-
804-
lower_span: impl Copy + Fn(Span) -> Span,
805-
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
806-
) -> Vec<Attribute> {
807-
let mut attributes = Vec::new();
808-
let mut attr_paths = Vec::new();
809-
810-
for attr in attrs {
811-
// If we're only looking for a single attribute, skip all the ones we don't care about.
812-
if let Some(expected) = self.parse_only {
813-
if !attr.has_name(expected) {
814-
continue;
815-
}
816-
}
817-
818-
// Sometimes, for example for `#![doc = include_str!("readme.md")]`,
819-
// doc still contains a non-literal. You might say, when we're lowering attributes
820-
// that's expanded right? But no, sometimes, when parsing attributes on macros,
821-
// we already use the lowering logic and these are still there. So, when `omit_doc`
822-
// is set we *also* want to ignore these.
823-
if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
824-
continue;
825-
}
826-
827-
match &attr.kind {
828-
ast::AttrKind::DocComment(comment_kind, symbol) => {
829-
if omit_doc == OmitDoc::Skip {
830-
continue;
831-
}
832-
833-
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
834-
style: attr.style,
835-
kind: *comment_kind,
836-
span: lower_span(attr.span),
837-
comment: *symbol,
838-
}))
839-
}
840-
// // FIXME: make doc attributes go through a proper attribute parser
841-
// ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
842-
// let p = GenericMetaItemParser::from_attr(&n, self.dcx());
843-
//
844-
// attributes.push(Attribute::Parsed(AttributeKind::DocComment {
845-
// style: attr.style,
846-
// kind: CommentKind::Line,
847-
// span: attr.span,
848-
// comment: p.args().name_value(),
849-
// }))
850-
// }
851-
ast::AttrKind::Normal(n) => {
852-
attr_paths.push(PathParser::Ast(&n.item.path));
853-
854-
let parser = MetaItemParser::from_attr(n, self.dcx());
855-
let path = parser.path();
856-
let args = parser.args();
857-
let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
858-
859-
if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
860-
for accept in accepts {
861-
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
862-
shared: SharedContext {
863-
cx: self,
864-
target_span,
865-
target_id,
866-
emit_lint: &mut emit_lint,
867-
},
868-
attr_span: lower_span(attr.span),
869-
attr_style: attr.style,
870-
template: &accept.template,
871-
attr_path: path.get_attribute_path(),
872-
};
873-
874-
(accept.accept_fn)(&mut cx, args);
875-
876-
if self.stage.should_emit().should_emit() {
877-
self.check_target(
878-
path.get_attribute_path(),
879-
attr.span,
880-
&accept.allowed_targets,
881-
target,
882-
target_id,
883-
&mut emit_lint,
884-
);
885-
}
886-
}
887-
} else {
888-
// If we're here, we must be compiling a tool attribute... Or someone
889-
// forgot to parse their fancy new attribute. Let's warn them in any case.
890-
// If you are that person, and you really think your attribute should
891-
// remain unparsed, carefully read the documentation in this module and if
892-
// you still think so you can add an exception to this assertion.
893-
894-
// FIXME(jdonszelmann): convert other attributes, and check with this that
895-
// we caught em all
896-
// const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg];
897-
// assert!(
898-
// self.tools.contains(&parts[0]) || true,
899-
// // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
900-
// "attribute {path} wasn't parsed and isn't a know tool attribute",
901-
// );
902-
903-
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
904-
path: AttrPath::from_ast(&n.item.path),
905-
args: self.lower_attr_args(&n.item.args, lower_span),
906-
id: HashIgnoredAttrId { attr_id: attr.id },
907-
style: attr.style,
908-
span: lower_span(attr.span),
909-
})));
910-
}
911-
}
912-
}
913-
}
914-
915-
let mut parsed_attributes = Vec::new();
916-
for f in &S::parsers().finalizers {
917-
if let Some(attr) = f(&mut FinalizeContext {
918-
shared: SharedContext {
919-
cx: self,
920-
target_span,
921-
target_id,
922-
emit_lint: &mut emit_lint,
923-
},
924-
all_attrs: &attr_paths,
925-
}) {
926-
parsed_attributes.push(Attribute::Parsed(attr));
927-
}
928-
}
929-
930-
attributes.extend(parsed_attributes);
931-
932-
attributes
933-
}
934-
935-
/// Returns whether there is a parser for an attribute with this name
936-
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
937-
Late::parsers().accepters.contains_key(path)
938-
}
939-
940-
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
941-
match args {
942-
ast::AttrArgs::Empty => AttrArgs::Empty,
943-
ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()),
944-
// This is an inert key-value attribute - it will never be visible to macros
945-
// after it gets lowered to HIR. Therefore, we can extract literals to handle
946-
// nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
947-
ast::AttrArgs::Eq { eq_span, expr } => {
948-
// In valid code the value always ends up as a single literal. Otherwise, a dummy
949-
// literal suffices because the error is handled elsewhere.
950-
let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
951-
&& let Ok(lit) =
952-
ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
953-
{
954-
lit
955-
} else {
956-
let guar = self.dcx().span_delayed_bug(
957-
args.span().unwrap_or(DUMMY_SP),
958-
"expr in place where literal is expected (builtin attr parsing)",
959-
);
960-
ast::MetaItemLit {
961-
symbol: sym::dummy,
962-
suffix: None,
963-
kind: ast::LitKind::Err(guar),
964-
span: DUMMY_SP,
965-
}
966-
};
967-
AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
968-
}
969-
}
970-
}
971-
}

0 commit comments

Comments
 (0)