summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes/src/check_attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_passes/src/check_attr.rs')
-rw-r--r--compiler/rustc_passes/src/check_attr.rs186
1 files changed, 89 insertions, 97 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 5ef3e13ef..80a93da2b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -19,9 +19,10 @@ use rustc_hir::{
use rustc_hir::{MethodKind, Target, Unsafety};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
UNUSED_ATTRIBUTES,
@@ -30,6 +31,9 @@ use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::ObligationCtxt;
use std::cell::Cell;
use std::collections::hash_map::Entry;
@@ -1105,17 +1109,6 @@ impl CheckAttrVisitor<'_> {
}
}
- sym::primitive => {
- if !self.tcx.features().rustdoc_internals {
- self.tcx.emit_spanned_lint(
- INVALID_DOC_ATTRIBUTES,
- hir_id,
- i_meta.span,
- errors::DocPrimitive,
- );
- }
- }
-
_ => {
let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
if i_meta.has_name(sym::spotlight) {
@@ -1903,7 +1896,7 @@ impl CheckAttrVisitor<'_> {
match target {
Target::Fn => {
for attr in attrs {
- if self.tcx.sess.is_proc_macro_attr(attr) {
+ if attr.is_proc_macro_attr() {
debug!("Is proc macro attr");
return true;
}
@@ -2188,100 +2181,99 @@ impl CheckAttrVisitor<'_> {
///
/// If this best effort goes wrong, it will just emit a worse error later (see #102923)
fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
- let expected_input_count = match kind {
- ProcMacroKind::Attribute => 2,
- ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
- };
-
- let expected_signature = match kind {
- ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream",
- ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream",
- };
+ if target != Target::Fn {
+ return;
+ }
let tcx = self.tcx;
- if target == Target::Fn {
- let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return};
- let tokenstream = tcx.type_of(tokenstream).subst_identity();
-
- let id = hir_id.expect_owner();
- let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
-
- let sig =
- tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id).subst_identity());
- let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig);
-
- // We don't currently require that the function signature is equal to
- // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
- // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
- //
- // Properly checking this means pulling in additional `rustc` crates, so we don't.
- let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
-
- if sig.abi != Abi::Rust {
- tcx.sess.emit_err(errors::ProcMacroInvalidAbi {
- span: hir_sig.span,
- abi: sig.abi.name(),
- });
- self.abort.set(true);
- }
+ let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else { return; };
+ let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else { return; };
- if sig.unsafety == Unsafety::Unsafe {
- tcx.sess.emit_err(errors::ProcMacroUnsafe { span: hir_sig.span });
- self.abort.set(true);
- }
+ let def_id = hir_id.expect_owner().def_id;
+ let param_env = ty::ParamEnv::empty();
- let output = sig.output();
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
- // Typecheck the output
- if !drcx.types_may_unify(output, tokenstream) {
- tcx.sess.emit_err(errors::ProcMacroTypeError {
- span: hir_sig.decl.output.span(),
- found: output,
- kind,
- expected_signature,
- });
- self.abort.set(true);
- }
+ let span = tcx.def_span(def_id);
+ let fresh_substs = infcx.fresh_substs_for_item(span, def_id.to_def_id());
+ let sig = tcx.liberate_late_bound_regions(
+ def_id.to_def_id(),
+ tcx.fn_sig(def_id).subst(tcx, fresh_substs),
+ );
- if sig.inputs().len() < expected_input_count {
- tcx.sess.emit_err(errors::ProcMacroMissingArguments {
- expected_input_count,
- span: hir_sig.span,
- kind,
- expected_signature,
- });
- self.abort.set(true);
- }
+ let mut cause = ObligationCause::misc(span, def_id);
+ let sig = ocx.normalize(&cause, param_env, sig);
- // Check that the inputs are correct, if there are enough.
- if sig.inputs().len() >= expected_input_count {
- for (arg, input) in
- sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
- {
- if !drcx.types_may_unify(*arg, tokenstream) {
- tcx.sess.emit_err(errors::ProcMacroTypeError {
- span: input.span,
- found: *arg,
- kind,
- expected_signature,
- });
- self.abort.set(true);
+ // proc macro is not WF.
+ let errors = ocx.select_where_possible();
+ if !errors.is_empty() {
+ return;
+ }
+
+ let expected_sig = tcx.mk_fn_sig(
+ std::iter::repeat(token_stream).take(match kind {
+ ProcMacroKind::Attribute => 2,
+ ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
+ }),
+ token_stream,
+ false,
+ Unsafety::Normal,
+ Abi::Rust,
+ );
+
+ if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
+ let mut diag = tcx.sess.create_err(errors::ProcMacroBadSig { span, kind });
+
+ let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
+ if let Some(hir_sig) = hir_sig {
+ match terr {
+ TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
+ if let Some(ty) = hir_sig.decl.inputs.get(idx) {
+ diag.set_span(ty.span);
+ cause.span = ty.span;
+ } else if idx == hir_sig.decl.inputs.len() {
+ let span = hir_sig.decl.output.span();
+ diag.set_span(span);
+ cause.span = span;
+ }
}
+ TypeError::ArgCount => {
+ if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
+ diag.set_span(ty.span);
+ cause.span = ty.span;
+ }
+ }
+ TypeError::UnsafetyMismatch(_) => {
+ // FIXME: Would be nice if we had a span here..
+ }
+ TypeError::AbiMismatch(_) => {
+ // FIXME: Would be nice if we had a span here..
+ }
+ TypeError::VariadicMismatch(_) => {
+ // FIXME: Would be nice if we had a span here..
+ }
+ _ => {}
}
}
- // Check that there are not too many arguments
- let body_id = tcx.hir().body_owned_by(id.def_id);
- let excess = tcx.hir().body(body_id).params.get(expected_input_count..);
- if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess {
- tcx.sess.emit_err(errors::ProcMacroDiffArguments {
- span: begin.span.to(end.span),
- count: excess.len(),
- kind,
- expected_signature,
- });
- self.abort.set(true);
- }
+ infcx.err_ctxt().note_type_err(
+ &mut diag,
+ &cause,
+ None,
+ Some(ValuePairs::Sigs(ExpectedFound { expected: expected_sig, found: sig })),
+ terr,
+ false,
+ false,
+ );
+ diag.emit();
+ self.abort.set(true);
+ }
+
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors);
+ self.abort.set(true);
}
}
}