@@ -23,6 +23,7 @@ use rustc_hir::{
23
23
use rustc_hir:: { MethodKind , Target , Unsafety } ;
24
24
use rustc_middle:: hir:: nested_filter;
25
25
use rustc_middle:: middle:: resolve_lifetime:: ObjectLifetimeDefault ;
26
+ use rustc_middle:: ty:: fast_reject:: { DeepRejectCtxt , TreatParams } ;
26
27
use rustc_middle:: ty:: query:: Providers ;
27
28
use rustc_middle:: ty:: { ParamEnv , TyCtxt } ;
28
29
use rustc_session:: lint:: builtin:: {
@@ -84,6 +85,8 @@ impl IntoDiagnosticArg for ProcMacroKind {
84
85
85
86
struct CheckAttrVisitor < ' tcx > {
86
87
tcx : TyCtxt < ' tcx > ,
88
+
89
+ // Whether or not this visitor should abort after finding errors
87
90
abort : Cell < bool > ,
88
91
}
89
92
@@ -2084,6 +2087,9 @@ impl CheckAttrVisitor<'_> {
2084
2087
) ;
2085
2088
}
2086
2089
2090
+ /// A best effort attempt to create an error for a mismatching proc macro signature.
2091
+ ///
2092
+ /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
2087
2093
fn check_proc_macro ( & self , hir_id : HirId , target : Target , kind : ProcMacroKind ) {
2088
2094
let expected_input_count = match kind {
2089
2095
ProcMacroKind :: Attribute => 2 ,
@@ -2103,23 +2109,30 @@ impl CheckAttrVisitor<'_> {
2103
2109
let id = hir_id. expect_owner ( ) ;
2104
2110
let hir_sig = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id) . unwrap ( ) ;
2105
2111
2106
- let sig = tcx. fn_sig ( id) ;
2112
+ let sig = tcx. liberate_late_bound_regions ( id. to_def_id ( ) , tcx. fn_sig ( id) ) ;
2113
+ let sig = tcx. normalize_erasing_regions ( ParamEnv :: empty ( ) , sig) ;
2114
+
2115
+ // We don't currently require that the function signature is equal to
2116
+ // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
2117
+ // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
2118
+ //
2119
+ // Properly checking this means pulling in additional `rustc` crates, so we don't.
2120
+ let drcx = DeepRejectCtxt { treat_obligation_params : TreatParams :: AsInfer } ;
2107
2121
2108
- if sig. abi ( ) != Abi :: Rust {
2109
- tcx. sess
2110
- . emit_err ( ProcMacroInvalidAbi { span : hir_sig. span , abi : sig. abi ( ) . name ( ) } ) ;
2122
+ if sig. abi != Abi :: Rust {
2123
+ tcx. sess . emit_err ( ProcMacroInvalidAbi { span : hir_sig. span , abi : sig. abi . name ( ) } ) ;
2111
2124
self . abort . set ( true ) ;
2112
2125
}
2113
2126
2114
- if sig. unsafety ( ) == Unsafety :: Unsafe {
2127
+ if sig. unsafety == Unsafety :: Unsafe {
2115
2128
tcx. sess . emit_err ( ProcMacroUnsafe { span : hir_sig. span } ) ;
2116
2129
self . abort . set ( true ) ;
2117
2130
}
2118
2131
2119
- let output = sig. output ( ) . skip_binder ( ) ;
2132
+ let output = sig. output ( ) ;
2120
2133
2121
2134
// Typecheck the output
2122
- if tcx . normalize_erasing_regions ( ParamEnv :: empty ( ) , output ) != tokenstream {
2135
+ if !drcx . types_may_unify ( output , tokenstream) {
2123
2136
tcx. sess . emit_err ( ProcMacroTypeError {
2124
2137
span : hir_sig. decl . output . span ( ) ,
2125
2138
found : output,
@@ -2129,11 +2142,22 @@ impl CheckAttrVisitor<'_> {
2129
2142
self . abort . set ( true ) ;
2130
2143
}
2131
2144
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 {
2145
+ if sig. inputs ( ) . len ( ) < expected_input_count {
2146
+ tcx. sess . emit_err ( ProcMacroMissingArguments {
2147
+ expected_input_count,
2148
+ span : hir_sig. span ,
2149
+ kind,
2150
+ expected_signature,
2151
+ } ) ;
2152
+ self . abort . set ( true ) ;
2153
+ }
2154
+
2155
+ // Check that the inputs are correct, if there are enough.
2156
+ if sig. inputs ( ) . len ( ) >= expected_input_count {
2157
+ for ( arg, input) in
2158
+ sig. inputs ( ) . iter ( ) . zip ( hir_sig. decl . inputs ) . take ( expected_input_count)
2159
+ {
2160
+ if !drcx. types_may_unify ( * arg, tokenstream) {
2137
2161
tcx. sess . emit_err ( ProcMacroTypeError {
2138
2162
span : input. span ,
2139
2163
found : * arg,
@@ -2143,14 +2167,6 @@ impl CheckAttrVisitor<'_> {
2143
2167
self . abort . set ( true ) ;
2144
2168
}
2145
2169
}
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
2170
}
2155
2171
2156
2172
// Check that there are not too many arguments
0 commit comments