@@ -19,9 +19,10 @@ use rustc_hir::{
1919use rustc_hir:: { MethodKind , Target , Unsafety } ;
2020use rustc_middle:: hir:: nested_filter;
2121use rustc_middle:: middle:: resolve_bound_vars:: ObjectLifetimeDefault ;
22- use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
22+ use rustc_middle:: traits:: ObligationCause ;
23+ use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
2324use rustc_middle:: ty:: query:: Providers ;
24- use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
25+ use rustc_middle:: ty:: { self , TyCtxt } ;
2526use rustc_session:: lint:: builtin:: {
2627 CONFLICTING_REPR_HINTS , INVALID_DOC_ATTRIBUTES , INVALID_MACRO_EXPORT_ARGUMENTS ,
2728 UNUSED_ATTRIBUTES ,
@@ -30,6 +31,9 @@ use rustc_session::parse::feature_err;
3031use rustc_span:: symbol:: { kw, sym, Symbol } ;
3132use rustc_span:: { Span , DUMMY_SP } ;
3233use rustc_target:: spec:: abi:: Abi ;
34+ use rustc_trait_selection:: infer:: { TyCtxtInferExt , ValuePairs } ;
35+ use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
36+ use rustc_trait_selection:: traits:: ObligationCtxt ;
3337use std:: cell:: Cell ;
3438use std:: collections:: hash_map:: Entry ;
3539
@@ -2188,100 +2192,99 @@ impl CheckAttrVisitor<'_> {
21882192 ///
21892193 /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
21902194 fn check_proc_macro ( & self , hir_id : HirId , target : Target , kind : ProcMacroKind ) {
2191- let expected_input_count = match kind {
2192- ProcMacroKind :: Attribute => 2 ,
2193- ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => 1 ,
2194- } ;
2195-
2196- let expected_signature = match kind {
2197- ProcMacroKind :: Attribute => "fn(TokenStream, TokenStream) -> TokenStream" ,
2198- ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => "fn(TokenStream) -> TokenStream" ,
2199- } ;
2195+ if target != Target :: Fn {
2196+ return ;
2197+ }
22002198
22012199 let tcx = self . tcx ;
2202- if target == Target :: Fn {
2203- let Some ( tokenstream) = tcx. get_diagnostic_item ( sym:: TokenStream ) else { return } ;
2204- let tokenstream = tcx. type_of ( tokenstream) . subst_identity ( ) ;
2205-
2206- let id = hir_id. expect_owner ( ) ;
2207- let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . unwrap ( ) ;
2208-
2209- let sig =
2210- tcx. liberate_late_bound_regions ( id. to_def_id ( ) , tcx. fn_sig ( id) . subst_identity ( ) ) ;
2211- let sig = tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , sig) ;
2212-
2213- // We don't currently require that the function signature is equal to
2214- // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
2215- // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
2216- //
2217- // Properly checking this means pulling in additional `rustc` crates, so we don't.
2218- let drcx = DeepRejectCtxt { treat_obligation_params : TreatParams :: AsCandidateKey } ;
2219-
2220- if sig. abi != Abi :: Rust {
2221- tcx. sess . emit_err ( errors:: ProcMacroInvalidAbi {
2222- span : hir_sig. span ,
2223- abi : sig. abi . name ( ) ,
2224- } ) ;
2225- self . abort . set ( true ) ;
2226- }
2200+ let Some ( token_stream_def_id) = tcx. get_diagnostic_item ( sym:: TokenStream ) else { return ; } ;
2201+ let Some ( token_stream) = tcx. type_of ( token_stream_def_id) . no_bound_vars ( ) else { return ; } ;
22272202
2228- if sig. unsafety == Unsafety :: Unsafe {
2229- tcx. sess . emit_err ( errors:: ProcMacroUnsafe { span : hir_sig. span } ) ;
2230- self . abort . set ( true ) ;
2231- }
2203+ let def_id = hir_id. expect_owner ( ) . def_id ;
2204+ let param_env = ty:: ParamEnv :: empty ( ) ;
22322205
2233- let output = sig. output ( ) ;
2206+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
2207+ let ocx = ObligationCtxt :: new ( & infcx) ;
22342208
2235- // Typecheck the output
2236- if !drcx. types_may_unify ( output, tokenstream) {
2237- tcx. sess . emit_err ( errors:: ProcMacroTypeError {
2238- span : hir_sig. decl . output . span ( ) ,
2239- found : output,
2240- kind,
2241- expected_signature,
2242- } ) ;
2243- self . abort . set ( true ) ;
2244- }
2209+ let span = tcx. def_span ( def_id) ;
2210+ let fresh_substs = infcx. fresh_substs_for_item ( span, def_id. to_def_id ( ) ) ;
2211+ let sig = tcx. liberate_late_bound_regions (
2212+ def_id. to_def_id ( ) ,
2213+ tcx. fn_sig ( def_id) . subst ( tcx, fresh_substs) ,
2214+ ) ;
22452215
2246- if sig. inputs ( ) . len ( ) < expected_input_count {
2247- tcx. sess . emit_err ( errors:: ProcMacroMissingArguments {
2248- expected_input_count,
2249- span : hir_sig. span ,
2250- kind,
2251- expected_signature,
2252- } ) ;
2253- self . abort . set ( true ) ;
2254- }
2216+ let mut cause = ObligationCause :: misc ( span, def_id) ;
2217+ let sig = ocx. normalize ( & cause, param_env, sig) ;
22552218
2256- // Check that the inputs are correct, if there are enough.
2257- if sig. inputs ( ) . len ( ) >= expected_input_count {
2258- for ( arg, input) in
2259- sig. inputs ( ) . iter ( ) . zip ( hir_sig. decl . inputs ) . take ( expected_input_count)
2260- {
2261- if !drcx. types_may_unify ( * arg, tokenstream) {
2262- tcx. sess . emit_err ( errors:: ProcMacroTypeError {
2263- span : input. span ,
2264- found : * arg,
2265- kind,
2266- expected_signature,
2267- } ) ;
2268- self . abort . set ( true ) ;
2219+ // proc macro is not WF.
2220+ let errors = ocx. select_where_possible ( ) ;
2221+ if !errors. is_empty ( ) {
2222+ return ;
2223+ }
2224+
2225+ let expected_sig = tcx. mk_fn_sig (
2226+ std:: iter:: repeat ( token_stream) . take ( match kind {
2227+ ProcMacroKind :: Attribute => 2 ,
2228+ ProcMacroKind :: Derive | ProcMacroKind :: FunctionLike => 1 ,
2229+ } ) ,
2230+ token_stream,
2231+ false ,
2232+ Unsafety :: Normal ,
2233+ Abi :: Rust ,
2234+ ) ;
2235+
2236+ if let Err ( terr) = ocx. eq ( & cause, param_env, expected_sig, sig) {
2237+ let mut diag = tcx. sess . create_err ( errors:: ProcMacroBadSig { span, kind } ) ;
2238+
2239+ let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) ;
2240+ if let Some ( hir_sig) = hir_sig {
2241+ match terr {
2242+ TypeError :: ArgumentMutability ( idx) | TypeError :: ArgumentSorts ( _, idx) => {
2243+ if let Some ( ty) = hir_sig. decl . inputs . get ( idx) {
2244+ diag. set_span ( ty. span ) ;
2245+ cause. span = ty. span ;
2246+ } else if idx == hir_sig. decl . inputs . len ( ) {
2247+ let span = hir_sig. decl . output . span ( ) ;
2248+ diag. set_span ( span) ;
2249+ cause. span = span;
2250+ }
2251+ }
2252+ TypeError :: ArgCount => {
2253+ if let Some ( ty) = hir_sig. decl . inputs . get ( expected_sig. inputs ( ) . len ( ) ) {
2254+ diag. set_span ( ty. span ) ;
2255+ cause. span = ty. span ;
2256+ }
22692257 }
2258+ TypeError :: UnsafetyMismatch ( _) => {
2259+ // FIXME: Would be nice if we had a span here..
2260+ }
2261+ TypeError :: AbiMismatch ( _) => {
2262+ // FIXME: Would be nice if we had a span here..
2263+ }
2264+ TypeError :: VariadicMismatch ( _) => {
2265+ // FIXME: Would be nice if we had a span here..
2266+ }
2267+ _ => { }
22702268 }
22712269 }
22722270
2273- // Check that there are not too many arguments
2274- let body_id = tcx. hir ( ) . body_owned_by ( id. def_id ) ;
2275- let excess = tcx. hir ( ) . body ( body_id) . params . get ( expected_input_count..) ;
2276- if let Some ( excess @ [ begin @ end] | excess @ [ begin, .., end] ) = excess {
2277- tcx. sess . emit_err ( errors:: ProcMacroDiffArguments {
2278- span : begin. span . to ( end. span ) ,
2279- count : excess. len ( ) ,
2280- kind,
2281- expected_signature,
2282- } ) ;
2283- self . abort . set ( true ) ;
2284- }
2271+ infcx. err_ctxt ( ) . note_type_err (
2272+ & mut diag,
2273+ & cause,
2274+ None ,
2275+ Some ( ValuePairs :: Sigs ( ExpectedFound { expected : expected_sig, found : sig } ) ) ,
2276+ terr,
2277+ false ,
2278+ false ,
2279+ ) ;
2280+ diag. emit ( ) ;
2281+ self . abort . set ( true ) ;
2282+ }
2283+
2284+ let errors = ocx. select_all_or_error ( ) ;
2285+ if !errors. is_empty ( ) {
2286+ infcx. err_ctxt ( ) . report_fulfillment_errors ( & errors) ;
2287+ self . abort . set ( true ) ;
22852288 }
22862289 }
22872290}
0 commit comments