@@ -4,15 +4,16 @@ use std::ops::{Deref, DerefMut};
44use std:: sync:: LazyLock ;
55
66use 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 ;
1010use rustc_hir:: attrs:: AttributeKind ;
1111use rustc_hir:: lints:: { AttributeLint , AttributeLintKind } ;
12- use rustc_hir:: { AttrArgs , AttrItem , AttrPath , Attribute , HashIgnoredAttrId , HirId , Target } ;
12+ use rustc_hir:: { AttrPath , HirId } ;
1313use 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 ;
1617use crate :: attributes:: allow_unstable:: {
1718 AllowConstFnUnstableParser , AllowInternalUnstableParser , UnstableFeatureBoundParser ,
1819} ;
@@ -62,21 +63,21 @@ use crate::attributes::traits::{
6263} ;
6364use crate :: attributes:: transparency:: TransparencyParser ;
6465use crate :: attributes:: { AttributeParser as _, Combine , Single , WithoutArgs } ;
65- use crate :: parser:: { ArgParser , MetaItemParser , PathParser } ;
66+ use crate :: parser:: { ArgParser , PathParser } ;
6667use crate :: session_diagnostics:: { AttributeParseError , AttributeParseErrorReason , UnknownMetaItem } ;
6768use crate :: target_checking:: AllowedTargets ;
6869
6970type 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
8283type 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