Skip to content

Commit a8e3abd

Browse files
author
mejrs
committed
Address feedback
1 parent f920008 commit a8e3abd

File tree

3 files changed

+63
-23
lines changed

3 files changed

+63
-23
lines changed

compiler/rustc_passes/src/check_attr.rs

+36-20
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_hir::{
2323
use rustc_hir::{MethodKind, Target, Unsafety};
2424
use rustc_middle::hir::nested_filter;
2525
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
26+
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
2627
use rustc_middle::ty::query::Providers;
2728
use rustc_middle::ty::{ParamEnv, TyCtxt};
2829
use rustc_session::lint::builtin::{
@@ -84,6 +85,8 @@ impl IntoDiagnosticArg for ProcMacroKind {
8485

8586
struct CheckAttrVisitor<'tcx> {
8687
tcx: TyCtxt<'tcx>,
88+
89+
// Whether or not this visitor should abort after finding errors
8790
abort: Cell<bool>,
8891
}
8992

@@ -2084,6 +2087,9 @@ impl CheckAttrVisitor<'_> {
20842087
);
20852088
}
20862089

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)
20872093
fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
20882094
let expected_input_count = match kind {
20892095
ProcMacroKind::Attribute => 2,
@@ -2103,23 +2109,30 @@ impl CheckAttrVisitor<'_> {
21032109
let id = hir_id.expect_owner();
21042110
let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
21052111

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 };
21072121

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() });
21112124
self.abort.set(true);
21122125
}
21132126

2114-
if sig.unsafety() == Unsafety::Unsafe {
2127+
if sig.unsafety == Unsafety::Unsafe {
21152128
tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span });
21162129
self.abort.set(true);
21172130
}
21182131

2119-
let output = sig.output().skip_binder();
2132+
let output = sig.output();
21202133

21212134
// Typecheck the output
2122-
if tcx.normalize_erasing_regions(ParamEnv::empty(), output) != tokenstream {
2135+
if !drcx.types_may_unify(output, tokenstream) {
21232136
tcx.sess.emit_err(ProcMacroTypeError {
21242137
span: hir_sig.decl.output.span(),
21252138
found: output,
@@ -2129,11 +2142,22 @@ impl CheckAttrVisitor<'_> {
21292142
self.abort.set(true);
21302143
}
21312144

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) {
21372161
tcx.sess.emit_err(ProcMacroTypeError {
21382162
span: input.span,
21392163
found: *arg,
@@ -2143,14 +2167,6 @@ impl CheckAttrVisitor<'_> {
21432167
self.abort.set(true);
21442168
}
21452169
}
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);
21542170
}
21552171

21562172
// Check that there are not too many arguments
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// check-pass
2+
3+
#![crate_type = "proc-macro"]
4+
#![allow(private_in_public)]
5+
extern crate proc_macro;
6+
use proc_macro::TokenStream;
7+
8+
#[proc_macro]
9+
pub fn foo<T>(t: T) -> TokenStream {
10+
TokenStream::new()
11+
}
12+
13+
trait Project {
14+
type Assoc;
15+
}
16+
17+
impl Project for () {
18+
type Assoc = TokenStream;
19+
}
20+
21+
#[proc_macro]
22+
pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc {
23+
TokenStream::new()
24+
}

tests/ui/proc-macro/proc-macro-abi.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ use proc_macro::TokenStream;
66

77
#[proc_macro]
88
pub extern "C" fn abi(a: TokenStream) -> TokenStream {
9-
//~^ ERROR proc macro functions may not be `extern
9+
//~^ ERROR proc macro functions may not be `extern "C"`
1010
a
1111
}
1212

1313
#[proc_macro]
1414
pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
15-
//~^ ERROR proc macro functions may not be `extern
15+
//~^ ERROR proc macro functions may not be `extern "system"`
1616
a
1717
}
1818

1919
#[proc_macro]
2020
pub extern fn abi3(a: TokenStream) -> TokenStream {
21-
//~^ ERROR proc macro functions may not be `extern
21+
//~^ ERROR proc macro functions may not be `extern "C"`
2222
a
2323
}
2424

0 commit comments

Comments
 (0)