66
77use crate :: errors:: {
88 self , AttrApplication , DebugVisualizerUnreadable , InvalidAttrAtCrateLevel , ObjectLifetimeErr ,
9- OnlyHasEffectOn , TransparentIncompatible , UnrecognizedReprHint ,
9+ OnlyHasEffectOn , ProcMacroDiffArguments , ProcMacroInvalidAbi , ProcMacroMissingArguments ,
10+ ProcMacroTypeError , ProcMacroUnsafe , TransparentIncompatible , UnrecognizedReprHint ,
1011} ;
1112use rustc_ast:: { ast, AttrStyle , Attribute , LitKind , MetaItemKind , MetaItemLit , NestedMetaItem } ;
1213use rustc_data_structures:: fx:: FxHashMap ;
13- use rustc_errors:: { fluent, Applicability , MultiSpan } ;
14+ use rustc_errors:: { fluent, Applicability , IntoDiagnosticArg , MultiSpan } ;
1415use rustc_expand:: base:: resolve_path;
1516use rustc_feature:: { AttributeDuplicates , AttributeType , BuiltinAttribute , BUILTIN_ATTRIBUTE_MAP } ;
1617use rustc_hir as hir;
@@ -19,18 +20,19 @@ use rustc_hir::intravisit::{self, Visitor};
1920use rustc_hir:: {
2021 self , FnSig , ForeignItem , HirId , Item , ItemKind , TraitItem , CRATE_HIR_ID , CRATE_OWNER_ID ,
2122} ;
22- use rustc_hir:: { MethodKind , Target } ;
23+ use rustc_hir:: { MethodKind , Target , Unsafety } ;
2324use rustc_middle:: hir:: nested_filter;
2425use rustc_middle:: middle:: resolve_lifetime:: ObjectLifetimeDefault ;
2526use rustc_middle:: ty:: query:: Providers ;
26- use rustc_middle:: ty:: TyCtxt ;
27+ use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
2728use rustc_session:: lint:: builtin:: {
2829 CONFLICTING_REPR_HINTS , INVALID_DOC_ATTRIBUTES , UNUSED_ATTRIBUTES ,
2930} ;
3031use rustc_session:: parse:: feature_err;
3132use rustc_span:: symbol:: { kw, sym, Symbol } ;
3233use rustc_span:: { Span , DUMMY_SP } ;
3334use rustc_target:: spec:: abi:: Abi ;
35+ use std:: cell:: Cell ;
3436use std:: collections:: hash_map:: Entry ;
3537
3638pub ( crate ) fn target_from_impl_item < ' tcx > (
@@ -62,8 +64,27 @@ enum ItemLike<'tcx> {
6264 ForeignItem ,
6365}
6466
67+ #[ derive( Copy , Clone ) ]
68+ pub ( crate ) enum ProcMacroKind {
69+ FunctionLike ,
70+ Derive ,
71+ Attribute ,
72+ }
73+
74+ impl IntoDiagnosticArg for ProcMacroKind {
75+ fn into_diagnostic_arg ( self ) -> rustc_errors:: DiagnosticArgValue < ' static > {
76+ match self {
77+ ProcMacroKind :: Attribute => "attribute proc macro" ,
78+ ProcMacroKind :: Derive => "derive proc macro" ,
79+ ProcMacroKind :: FunctionLike => "function-like proc macro" ,
80+ }
81+ . into_diagnostic_arg ( )
82+ }
83+ }
84+
6585struct CheckAttrVisitor < ' tcx > {
6686 tcx : TyCtxt < ' tcx > ,
87+ abort : Cell < bool > ,
6788}
6889
6990impl CheckAttrVisitor < ' _ > {
@@ -172,7 +193,7 @@ impl CheckAttrVisitor<'_> {
172193 sym:: path => self . check_generic_attr ( hir_id, attr, target, Target :: Mod ) ,
173194 sym:: plugin_registrar => self . check_plugin_registrar ( hir_id, attr, target) ,
174195 sym:: macro_export => self . check_macro_export ( hir_id, attr, target) ,
175- sym:: ignore | sym:: should_panic | sym :: proc_macro_derive => {
196+ sym:: ignore | sym:: should_panic => {
176197 self . check_generic_attr ( hir_id, attr, target, Target :: Fn )
177198 }
178199 sym:: automatically_derived => {
@@ -182,6 +203,16 @@ impl CheckAttrVisitor<'_> {
182203 self . check_generic_attr ( hir_id, attr, target, Target :: Mod )
183204 }
184205 sym:: rustc_object_lifetime_default => self . check_object_lifetime_default ( hir_id) ,
206+ sym:: proc_macro => {
207+ self . check_proc_macro ( hir_id, target, ProcMacroKind :: FunctionLike )
208+ }
209+ sym:: proc_macro_attribute => {
210+ self . check_proc_macro ( hir_id, target, ProcMacroKind :: Attribute ) ;
211+ }
212+ sym:: proc_macro_derive => {
213+ self . check_generic_attr ( hir_id, attr, target, Target :: Fn ) ;
214+ self . check_proc_macro ( hir_id, target, ProcMacroKind :: Derive )
215+ }
185216 _ => { }
186217 }
187218
@@ -2052,6 +2083,90 @@ impl CheckAttrVisitor<'_> {
20522083 errors:: Unused { attr_span : attr. span , note } ,
20532084 ) ;
20542085 }
2086+
2087+ fn check_proc_macro ( & self , hir_id : HirId , target : Target , kind : ProcMacroKind ) {
2088+ let expected_input_count = match kind {
2089+ ProcMacroKind :: Attribute => 2 ,
2090+ ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => 1 ,
2091+ } ;
2092+
2093+ let expected_signature = match kind {
2094+ ProcMacroKind :: Attribute => "fn(TokenStream, TokenStream) -> TokenStream" ,
2095+ ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => "fn(TokenStream) -> TokenStream" ,
2096+ } ;
2097+
2098+ let tcx = self . tcx ;
2099+ if target == Target :: Fn {
2100+ let Some ( tokenstream) = tcx. get_diagnostic_item ( sym:: TokenStream ) else { return } ;
2101+ let tokenstream = tcx. type_of ( tokenstream) ;
2102+
2103+ let id = hir_id. expect_owner ( ) ;
2104+ let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . unwrap ( ) ;
2105+
2106+ let sig = tcx. fn_sig ( id) ;
2107+
2108+ if sig. abi ( ) != Abi :: Rust {
2109+ tcx. sess
2110+ . emit_err ( ProcMacroInvalidAbi { span : hir_sig. span , abi : sig. abi ( ) . name ( ) } ) ;
2111+ self . abort . set ( true ) ;
2112+ }
2113+
2114+ if sig. unsafety ( ) == Unsafety :: Unsafe {
2115+ tcx. sess . emit_err ( ProcMacroUnsafe { span : hir_sig. span } ) ;
2116+ self . abort . set ( true ) ;
2117+ }
2118+
2119+ let output = sig. output ( ) . skip_binder ( ) ;
2120+
2121+ // Typecheck the output
2122+ if tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , output) != tokenstream {
2123+ tcx. sess . emit_err ( ProcMacroTypeError {
2124+ span : hir_sig. decl . output . span ( ) ,
2125+ found : output,
2126+ kind,
2127+ expected_signature,
2128+ } ) ;
2129+ self . abort . set ( true ) ;
2130+ }
2131+
2132+ // Typecheck "expected_input_count" inputs, emitting
2133+ // `ProcMacroMissingArguments` if there are not enough.
2134+ if let Some ( args) = sig. inputs ( ) . skip_binder ( ) . get ( 0 ..expected_input_count) {
2135+ for ( arg, input) in args. iter ( ) . zip ( hir_sig. decl . inputs ) {
2136+ if tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , * arg) != tokenstream {
2137+ tcx. sess . emit_err ( ProcMacroTypeError {
2138+ span : input. span ,
2139+ found : * arg,
2140+ kind,
2141+ expected_signature,
2142+ } ) ;
2143+ self . abort . set ( true ) ;
2144+ }
2145+ }
2146+ } else {
2147+ tcx. sess . emit_err ( ProcMacroMissingArguments {
2148+ expected_input_count,
2149+ span : hir_sig. span ,
2150+ kind,
2151+ expected_signature,
2152+ } ) ;
2153+ self . abort . set ( true ) ;
2154+ }
2155+
2156+ // Check that there are not too many arguments
2157+ let body_id = tcx. hir ( ) . body_owned_by ( id. def_id ) ;
2158+ let excess = tcx. hir ( ) . body ( body_id) . params . get ( expected_input_count..) ;
2159+ if let Some ( excess @ [ begin @ end] | excess @ [ begin, .., end] ) = excess {
2160+ tcx. sess . emit_err ( ProcMacroDiffArguments {
2161+ span : begin. span . to ( end. span ) ,
2162+ count : excess. len ( ) ,
2163+ kind,
2164+ expected_signature,
2165+ } ) ;
2166+ self . abort . set ( true ) ;
2167+ }
2168+ }
2169+ }
20552170}
20562171
20572172impl < ' tcx > Visitor < ' tcx > for CheckAttrVisitor < ' tcx > {
@@ -2214,12 +2329,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
22142329}
22152330
22162331fn check_mod_attrs ( tcx : TyCtxt < ' _ > , module_def_id : LocalDefId ) {
2217- let check_attr_visitor = & mut CheckAttrVisitor { tcx } ;
2332+ let check_attr_visitor = & mut CheckAttrVisitor { tcx, abort : Cell :: new ( false ) } ;
22182333 tcx. hir ( ) . visit_item_likes_in_module ( module_def_id, check_attr_visitor) ;
22192334 if module_def_id. is_top_level_module ( ) {
22202335 check_attr_visitor. check_attributes ( CRATE_HIR_ID , DUMMY_SP , Target :: Mod , None ) ;
22212336 check_invalid_crate_level_attr ( tcx, tcx. hir ( ) . krate_attrs ( ) ) ;
22222337 }
2338+ if check_attr_visitor. abort . get ( ) {
2339+ tcx. sess . abort_if_errors ( )
2340+ }
22232341}
22242342
22252343pub ( crate ) fn provide ( providers : & mut Providers ) {
0 commit comments