Fortify check for number of generic parameters.
This commit is contained in:
parent
da175c743c
commit
7b86c6f21e
@ -8,10 +8,11 @@ use super::*;
|
|||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
|
use rustc_hir::{ItemKind, Node, PathSegment};
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::Obligation;
|
use rustc_infer::traits::Obligation;
|
||||||
@ -29,7 +30,6 @@ use rustc_trait_selection::traits;
|
|||||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||||
use rustc_ty_utils::representability::{self, Representability};
|
use rustc_ty_utils::representability::{self, Representability};
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
@ -93,7 +93,6 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
fcx.return_type_pre_known = return_type_pre_known;
|
fcx.return_type_pre_known = return_type_pre_known;
|
||||||
|
|
||||||
let tcx = fcx.tcx;
|
let tcx = fcx.tcx;
|
||||||
let sess = tcx.sess;
|
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
|
|
||||||
let declared_ret_ty = fn_sig.output();
|
let declared_ret_ty = fn_sig.output();
|
||||||
@ -260,20 +259,47 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
|
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
|
||||||
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
|
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
|
||||||
{
|
{
|
||||||
if let Some(panic_info_did) = tcx.lang_items().panic_info() {
|
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||||
if *declared_ret_ty.kind() != ty::Never {
|
|
||||||
sess.span_err(decl.output.span(), "return type should be `!`");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
|
||||||
|
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
|
||||||
|
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
|
||||||
|
{
|
||||||
|
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
(fcx, gen_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_panic_info_fn(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
fn_id: LocalDefId,
|
||||||
|
fn_sig: ty::FnSig<'_>,
|
||||||
|
decl: &hir::FnDecl<'_>,
|
||||||
|
declared_ret_ty: Ty<'_>,
|
||||||
|
) {
|
||||||
|
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
|
||||||
|
tcx.sess.err("language item required, but not found: `panic_info`");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if *declared_ret_ty.kind() != ty::Never {
|
||||||
|
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
let inputs = fn_sig.inputs();
|
let inputs = fn_sig.inputs();
|
||||||
let span = hir.span(fn_id);
|
if inputs.len() != 1 {
|
||||||
if inputs.len() == 1 {
|
let span = tcx.sess.source_map().guess_head_span(span);
|
||||||
|
tcx.sess.span_err(span, "function should have one argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let arg_is_panic_info = match *inputs[0].kind() {
|
let arg_is_panic_info = match *inputs[0].kind() {
|
||||||
ty::Ref(region, ty, mutbl) => match *ty.kind() {
|
ty::Ref(region, ty, mutbl) => match *ty.kind() {
|
||||||
ty::Adt(ref adt, _) => {
|
ty::Adt(ref adt, _) => {
|
||||||
adt.did() == panic_info_did
|
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
|
||||||
&& mutbl == hir::Mutability::Not
|
|
||||||
&& !region.is_static()
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -281,64 +307,75 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !arg_is_panic_info {
|
if !arg_is_panic_info {
|
||||||
sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
|
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Node::Item(item) = hir.get(fn_id)
|
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
||||||
&& let ItemKind::Fn(_, ref generics, _) = item.kind
|
let span = tcx.def_span(fn_id);
|
||||||
&& !generics.params.is_empty()
|
tcx.sess.span_err(span, "should be a function");
|
||||||
{
|
return;
|
||||||
sess.span_err(span, "should have no type parameters");
|
};
|
||||||
}
|
|
||||||
} else {
|
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
||||||
let span = sess.source_map().guess_head_span(span);
|
if generic_counts.types != 0 {
|
||||||
sess.span_err(span, "function should have one argument");
|
let span = tcx.def_span(fn_id);
|
||||||
}
|
tcx.sess.span_err(span, "should have no type parameters");
|
||||||
} else {
|
}
|
||||||
sess.err("language item required, but not found: `panic_info`");
|
if generic_counts.consts != 0 {
|
||||||
}
|
let span = tcx.def_span(fn_id);
|
||||||
}
|
tcx.sess.span_err(span, "should have no const parameters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_alloc_error_fn(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
fn_id: LocalDefId,
|
||||||
|
fn_sig: ty::FnSig<'_>,
|
||||||
|
decl: &hir::FnDecl<'_>,
|
||||||
|
declared_ret_ty: Ty<'_>,
|
||||||
|
) {
|
||||||
|
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
|
||||||
|
tcx.sess.err("language item required, but not found: `alloc_layout`");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
|
|
||||||
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
|
|
||||||
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
|
|
||||||
{
|
|
||||||
if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
|
|
||||||
if *declared_ret_ty.kind() != ty::Never {
|
if *declared_ret_ty.kind() != ty::Never {
|
||||||
sess.span_err(decl.output.span(), "return type should be `!`");
|
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputs = fn_sig.inputs();
|
let inputs = fn_sig.inputs();
|
||||||
let span = hir.span(fn_id);
|
if inputs.len() != 1 {
|
||||||
if inputs.len() == 1 {
|
let span = tcx.def_span(fn_id);
|
||||||
|
let span = tcx.sess.source_map().guess_head_span(span);
|
||||||
|
tcx.sess.span_err(span, "function should have one argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let arg_is_alloc_layout = match inputs[0].kind() {
|
let arg_is_alloc_layout = match inputs[0].kind() {
|
||||||
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
|
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !arg_is_alloc_layout {
|
if !arg_is_alloc_layout {
|
||||||
sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
|
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Node::Item(item) = hir.get(fn_id)
|
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
||||||
&& let ItemKind::Fn(_, ref generics, _) = item.kind
|
let span = tcx.def_span(fn_id);
|
||||||
&& !generics.params.is_empty()
|
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
|
||||||
{
|
return;
|
||||||
sess.span_err(
|
};
|
||||||
span,
|
|
||||||
"`#[alloc_error_handler]` function should have no type parameters",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let span = sess.source_map().guess_head_span(span);
|
|
||||||
sess.span_err(span, "function should have one argument");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sess.err("language item required, but not found: `alloc_layout`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(fcx, gen_ty)
|
let generic_counts = tcx.generics_of(fn_id).own_counts();
|
||||||
|
if generic_counts.types != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
|
||||||
|
}
|
||||||
|
if generic_counts.consts != 0 {
|
||||||
|
let span = tcx.def_span(fn_id);
|
||||||
|
tcx.sess
|
||||||
|
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
|
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
|
||||||
|
@ -660,8 +660,24 @@ fn compare_number_of_generics<'tcx>(
|
|||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let spans = impl_item.generics.spans();
|
let spans = if impl_item.generics.params.is_empty() {
|
||||||
let span = spans.primary_span();
|
vec![impl_item.generics.span]
|
||||||
|
} else {
|
||||||
|
impl_item
|
||||||
|
.generics
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.filter(|p| {
|
||||||
|
matches!(
|
||||||
|
p.kind,
|
||||||
|
hir::GenericParamKind::Type { .. }
|
||||||
|
| hir::GenericParamKind::Const { .. }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(|p| p.span)
|
||||||
|
.collect::<Vec<Span>>()
|
||||||
|
};
|
||||||
|
let span = spans.first().copied();
|
||||||
|
|
||||||
let mut err = tcx.sess.struct_span_err_with_code(
|
let mut err = tcx.sess.struct_span_err_with_code(
|
||||||
spans,
|
spans,
|
||||||
|
@ -8,7 +8,7 @@ LL | type A = u32;
|
|||||||
| ^ lifetimes do not match type in trait
|
| ^ lifetimes do not match type in trait
|
||||||
|
|
||||||
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
|
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
|
||||||
--> $DIR/parameter_number_and_kind_impl.rs:17:12
|
--> $DIR/parameter_number_and_kind_impl.rs:17:16
|
||||||
|
|
|
|
||||||
LL | type B<'a, 'b>;
|
LL | type B<'a, 'b>;
|
||||||
| -- --
|
| -- --
|
||||||
@ -16,9 +16,7 @@ LL | type B<'a, 'b>;
|
|||||||
| expected 0 type parameters
|
| expected 0 type parameters
|
||||||
...
|
...
|
||||||
LL | type B<'a, T> = Vec<T>;
|
LL | type B<'a, T> = Vec<T>;
|
||||||
| ^^ ^
|
| ^ found 1 type parameter
|
||||||
| |
|
|
||||||
| found 1 type parameter
|
|
||||||
|
|
||||||
error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
|
error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
|
||||||
--> $DIR/parameter_number_and_kind_impl.rs:19:11
|
--> $DIR/parameter_number_and_kind_impl.rs:19:11
|
||||||
|
Loading…
x
Reference in New Issue
Block a user