Skip to content

Commit 7b86c6f

Browse files
committed
Fortify check for number of generic parameters.
1 parent da175c7 commit 7b86c6f

File tree

3 files changed

+127
-76
lines changed

3 files changed

+127
-76
lines changed

compiler/rustc_typeck/src/check/check.rs

+107-70
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ use super::*;
88
use rustc_attr as attr;
99
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
1010
use rustc_hir as hir;
11+
use rustc_hir::def::{DefKind, Res};
1112
use rustc_hir::def_id::{DefId, LocalDefId};
1213
use rustc_hir::intravisit::Visitor;
1314
use rustc_hir::lang_items::LangItem;
14-
use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
15+
use rustc_hir::{ItemKind, Node, PathSegment};
1516
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1617
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
1718
use rustc_infer::traits::Obligation;
@@ -29,7 +30,6 @@ use rustc_trait_selection::traits;
2930
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
3031
use rustc_ty_utils::representability::{self, Representability};
3132

32-
use rustc_hir::def::DefKind;
3333
use std::iter;
3434
use std::ops::ControlFlow;
3535

@@ -93,7 +93,6 @@ pub(super) fn check_fn<'a, 'tcx>(
9393
fcx.return_type_pre_known = return_type_pre_known;
9494

9595
let tcx = fcx.tcx;
96-
let sess = tcx.sess;
9796
let hir = tcx.hir();
9897

9998
let declared_ret_ty = fn_sig.output();
@@ -260,85 +259,123 @@ pub(super) fn check_fn<'a, 'tcx>(
260259
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
261260
&& panic_impl_did == hir.local_def_id(fn_id).to_def_id()
262261
{
263-
if let Some(panic_info_did) = tcx.lang_items().panic_info() {
264-
if *declared_ret_ty.kind() != ty::Never {
265-
sess.span_err(decl.output.span(), "return type should be `!`");
266-
}
267-
268-
let inputs = fn_sig.inputs();
269-
let span = hir.span(fn_id);
270-
if inputs.len() == 1 {
271-
let arg_is_panic_info = match *inputs[0].kind() {
272-
ty::Ref(region, ty, mutbl) => match *ty.kind() {
273-
ty::Adt(ref adt, _) => {
274-
adt.did() == panic_info_did
275-
&& mutbl == hir::Mutability::Not
276-
&& !region.is_static()
277-
}
278-
_ => false,
279-
},
280-
_ => false,
281-
};
282-
283-
if !arg_is_panic_info {
284-
sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
285-
}
286-
287-
if let Node::Item(item) = hir.get(fn_id)
288-
&& let ItemKind::Fn(_, ref generics, _) = item.kind
289-
&& !generics.params.is_empty()
290-
{
291-
sess.span_err(span, "should have no type parameters");
292-
}
293-
} else {
294-
let span = sess.source_map().guess_head_span(span);
295-
sess.span_err(span, "function should have one argument");
296-
}
297-
} else {
298-
sess.err("language item required, but not found: `panic_info`");
299-
}
262+
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
300263
}
301264

302265
// Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
303266
if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
304267
&& alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
305268
{
306-
if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
307-
if *declared_ret_ty.kind() != ty::Never {
308-
sess.span_err(decl.output.span(), "return type should be `!`");
309-
}
269+
check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
270+
}
310271

311-
let inputs = fn_sig.inputs();
312-
let span = hir.span(fn_id);
313-
if inputs.len() == 1 {
314-
let arg_is_alloc_layout = match inputs[0].kind() {
315-
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
316-
_ => false,
317-
};
272+
(fcx, gen_ty)
273+
}
318274

319-
if !arg_is_alloc_layout {
320-
sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
321-
}
275+
fn check_panic_info_fn(
276+
tcx: TyCtxt<'_>,
277+
fn_id: LocalDefId,
278+
fn_sig: ty::FnSig<'_>,
279+
decl: &hir::FnDecl<'_>,
280+
declared_ret_ty: Ty<'_>,
281+
) {
282+
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
283+
tcx.sess.err("language item required, but not found: `panic_info`");
284+
return;
285+
};
322286

323-
if let Node::Item(item) = hir.get(fn_id)
324-
&& let ItemKind::Fn(_, ref generics, _) = item.kind
325-
&& !generics.params.is_empty()
326-
{
327-
sess.span_err(
328-
span,
329-
"`#[alloc_error_handler]` function should have no type parameters",
330-
);
331-
}
332-
} else {
333-
let span = sess.source_map().guess_head_span(span);
334-
sess.span_err(span, "function should have one argument");
287+
if *declared_ret_ty.kind() != ty::Never {
288+
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
289+
}
290+
291+
let span = tcx.def_span(fn_id);
292+
let inputs = fn_sig.inputs();
293+
if inputs.len() != 1 {
294+
let span = tcx.sess.source_map().guess_head_span(span);
295+
tcx.sess.span_err(span, "function should have one argument");
296+
return;
297+
}
298+
299+
let arg_is_panic_info = match *inputs[0].kind() {
300+
ty::Ref(region, ty, mutbl) => match *ty.kind() {
301+
ty::Adt(ref adt, _) => {
302+
adt.did() == panic_info_did && mutbl == hir::Mutability::Not && !region.is_static()
335303
}
336-
} else {
337-
sess.err("language item required, but not found: `alloc_layout`");
338-
}
304+
_ => false,
305+
},
306+
_ => false,
307+
};
308+
309+
if !arg_is_panic_info {
310+
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
339311
}
340312

341-
(fcx, gen_ty)
313+
let DefKind::Fn = tcx.def_kind(fn_id) else {
314+
let span = tcx.def_span(fn_id);
315+
tcx.sess.span_err(span, "should be a function");
316+
return;
317+
};
318+
319+
let generic_counts = tcx.generics_of(fn_id).own_counts();
320+
if generic_counts.types != 0 {
321+
let span = tcx.def_span(fn_id);
322+
tcx.sess.span_err(span, "should have no type parameters");
323+
}
324+
if generic_counts.consts != 0 {
325+
let span = tcx.def_span(fn_id);
326+
tcx.sess.span_err(span, "should have no const parameters");
327+
}
328+
}
329+
330+
fn check_alloc_error_fn(
331+
tcx: TyCtxt<'_>,
332+
fn_id: LocalDefId,
333+
fn_sig: ty::FnSig<'_>,
334+
decl: &hir::FnDecl<'_>,
335+
declared_ret_ty: Ty<'_>,
336+
) {
337+
let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
338+
tcx.sess.err("language item required, but not found: `alloc_layout`");
339+
return;
340+
};
341+
342+
if *declared_ret_ty.kind() != ty::Never {
343+
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
344+
}
345+
346+
let inputs = fn_sig.inputs();
347+
if inputs.len() != 1 {
348+
let span = tcx.def_span(fn_id);
349+
let span = tcx.sess.source_map().guess_head_span(span);
350+
tcx.sess.span_err(span, "function should have one argument");
351+
return;
352+
}
353+
354+
let arg_is_alloc_layout = match inputs[0].kind() {
355+
ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
356+
_ => false,
357+
};
358+
359+
if !arg_is_alloc_layout {
360+
tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
361+
}
362+
363+
let DefKind::Fn = tcx.def_kind(fn_id) else {
364+
let span = tcx.def_span(fn_id);
365+
tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
366+
return;
367+
};
368+
369+
let generic_counts = tcx.generics_of(fn_id).own_counts();
370+
if generic_counts.types != 0 {
371+
let span = tcx.def_span(fn_id);
372+
tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
373+
}
374+
if generic_counts.consts != 0 {
375+
let span = tcx.def_span(fn_id);
376+
tcx.sess
377+
.span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
378+
}
342379
}
343380

344381
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {

compiler/rustc_typeck/src/check/compare_method.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,24 @@ fn compare_number_of_generics<'tcx>(
660660
_ => None,
661661
})
662662
.collect();
663-
let spans = impl_item.generics.spans();
664-
let span = spans.primary_span();
663+
let spans = if impl_item.generics.params.is_empty() {
664+
vec![impl_item.generics.span]
665+
} else {
666+
impl_item
667+
.generics
668+
.params
669+
.iter()
670+
.filter(|p| {
671+
matches!(
672+
p.kind,
673+
hir::GenericParamKind::Type { .. }
674+
| hir::GenericParamKind::Const { .. }
675+
)
676+
})
677+
.map(|p| p.span)
678+
.collect::<Vec<Span>>()
679+
};
680+
let span = spans.first().copied();
665681

666682
let mut err = tcx.sess.struct_span_err_with_code(
667683
spans,

src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@ LL | type A = u32;
88
| ^ lifetimes do not match type in trait
99

1010
error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters
11-
--> $DIR/parameter_number_and_kind_impl.rs:17:12
11+
--> $DIR/parameter_number_and_kind_impl.rs:17:16
1212
|
1313
LL | type B<'a, 'b>;
1414
| -- --
1515
| |
1616
| expected 0 type parameters
1717
...
1818
LL | type B<'a, T> = Vec<T>;
19-
| ^^ ^
20-
| |
21-
| found 1 type parameter
19+
| ^ found 1 type parameter
2220

2321
error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration
2422
--> $DIR/parameter_number_and_kind_impl.rs:19:11

0 commit comments

Comments
 (0)