mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Report an error if a lang item has the wrong number of generic arguments
This commit is contained in:
parent
b439be03c9
commit
7217d767b2
@ -13,12 +13,13 @@ use crate::weak_lang_items;
|
||||
use rustc_middle::middle::cstore::ExternCrate;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_errors::{pluralize, struct_span_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::lang_items::{extract, ITEM_REFS};
|
||||
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
|
||||
use rustc_span::Span;
|
||||
|
||||
use rustc_middle::ty::query::Providers;
|
||||
|
||||
@ -61,8 +62,7 @@ impl LanguageItemCollector<'tcx> {
|
||||
match ITEM_REFS.get(&value).cloned() {
|
||||
// Known lang item with attribute on correct target.
|
||||
Some((item_index, expected_target)) if actual_target == expected_target => {
|
||||
let def_id = self.tcx.hir().local_def_id(hir_id);
|
||||
self.collect_item(item_index, def_id.to_def_id());
|
||||
self.collect_item_extended(item_index, hir_id, span);
|
||||
}
|
||||
// Known lang item with attribute on incorrect target.
|
||||
Some((_, expected_target)) => {
|
||||
@ -100,11 +100,12 @@ impl LanguageItemCollector<'tcx> {
|
||||
}
|
||||
|
||||
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
|
||||
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
|
||||
let name = lang_item.name();
|
||||
|
||||
// Check for duplicates.
|
||||
if let Some(original_def_id) = self.items.items[item_index] {
|
||||
if original_def_id != item_def_id {
|
||||
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
|
||||
let name = lang_item.name();
|
||||
let mut err = match self.tcx.hir().span_if_local(item_def_id) {
|
||||
Some(span) => struct_span_err!(
|
||||
self.tcx.sess,
|
||||
@ -180,6 +181,83 @@ impl LanguageItemCollector<'tcx> {
|
||||
self.items.groups[group as usize].push(item_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
|
||||
let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
|
||||
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
|
||||
let name = lang_item.name();
|
||||
|
||||
self.collect_item(item_index, item_def_id);
|
||||
|
||||
// Now check whether the lang_item has the expected number of generic
|
||||
// arguments. Binary and indexing operations have one (for the RHS/index),
|
||||
// unary operations have no generic arguments.
|
||||
|
||||
let expected_num = match lang_item {
|
||||
LangItem::Add
|
||||
| LangItem::Sub
|
||||
| LangItem::Mul
|
||||
| LangItem::Div
|
||||
| LangItem::Rem
|
||||
| LangItem::BitXor
|
||||
| LangItem::BitAnd
|
||||
| LangItem::BitOr
|
||||
| LangItem::Shl
|
||||
| LangItem::Shr
|
||||
| LangItem::AddAssign
|
||||
| LangItem::SubAssign
|
||||
| LangItem::MulAssign
|
||||
| LangItem::DivAssign
|
||||
| LangItem::RemAssign
|
||||
| LangItem::BitXorAssign
|
||||
| LangItem::BitAndAssign
|
||||
| LangItem::BitOrAssign
|
||||
| LangItem::ShlAssign
|
||||
| LangItem::ShrAssign
|
||||
| LangItem::Index
|
||||
| LangItem::IndexMut => Some(1),
|
||||
|
||||
LangItem::Neg | LangItem::Not | LangItem::Deref | LangItem::DerefMut => Some(0),
|
||||
|
||||
// FIXME: add more cases?
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(expected_num) = expected_num {
|
||||
let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, generics, ..),
|
||||
..
|
||||
}) => (generics.params.len(), generics.span),
|
||||
_ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item),
|
||||
};
|
||||
|
||||
if expected_num != actual_num {
|
||||
// We are issuing E0718 "incorrect target" here, because while the
|
||||
// item kind of the target is correct, the target is still wrong
|
||||
// because of the wrong number of generic arguments.
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0718,
|
||||
"`{}` language item must be applied to a trait with {} generic argument{}",
|
||||
name,
|
||||
expected_num,
|
||||
pluralize!(expected_num)
|
||||
)
|
||||
.span_label(
|
||||
generics_span,
|
||||
format!(
|
||||
"this trait has {} generic argument{}, not {}",
|
||||
actual_num,
|
||||
pluralize!(actual_num),
|
||||
expected_num
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverses and collects all the lang items in all crates.
|
||||
|
@ -303,8 +303,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
opt_input_types: Option<&[Ty<'tcx>]>,
|
||||
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
|
||||
debug!(
|
||||
"lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})",
|
||||
self_ty, m_name, trait_def_id
|
||||
"lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
|
||||
self_ty, m_name, trait_def_id, opt_input_types
|
||||
);
|
||||
|
||||
// Construct a trait-reference `self_ty : Trait<input_tys>`
|
||||
|
@ -795,6 +795,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
lhs_ty, op, opname, trait_did
|
||||
);
|
||||
|
||||
// Catches cases like #83893, where a lang item is declared with the
|
||||
// wrong number of generic arguments. Should have yielded an error
|
||||
// elsewhere by now, but we have to catch it here so that we do not
|
||||
// index `other_tys` out of bounds (if the lang item has too many
|
||||
// generic arguments, `other_tys` is too short).
|
||||
if let Some(trait_did) = trait_did {
|
||||
let generics = self.tcx.generics_of(trait_did);
|
||||
let expected_num = match op {
|
||||
// Binary ops have a generic right-hand side, unary ops don't
|
||||
Op::Binary(..) => 1,
|
||||
Op::Unary(..) => 0,
|
||||
} + if generics.has_self { 1 } else { 0 };
|
||||
let num_generics = generics.count();
|
||||
if num_generics != expected_num {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
let method = trait_did.and_then(|trait_did| {
|
||||
let opname = Ident::with_dummy_span(opname);
|
||||
self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
|
||||
|
@ -153,6 +153,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
|
||||
PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
|
||||
};
|
||||
|
||||
// If the lang item was declared incorrectly, stop here so that we don't
|
||||
// run into an ICE (#83893). The error is reported where the lang item is
|
||||
// declared.
|
||||
if let Some(trait_did) = imm_tr {
|
||||
let generics = self.tcx.generics_of(trait_did);
|
||||
let expected_num = match op {
|
||||
PlaceOp::Deref => 0,
|
||||
PlaceOp::Index => 1,
|
||||
} + if generics.has_self { 1 } else { 0 };
|
||||
let num_generics = generics.count();
|
||||
if num_generics != expected_num {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
imm_tr.and_then(|trait_did| {
|
||||
self.lookup_method_in_trait(
|
||||
span,
|
||||
@ -177,6 +193,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
|
||||
PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
|
||||
};
|
||||
|
||||
// If the lang item was declared incorrectly, stop here so that we don't
|
||||
// run into an ICE (#83893). The error is reported where the lang item is
|
||||
// declared.
|
||||
if let Some(trait_did) = mut_tr {
|
||||
let generics = self.tcx.generics_of(trait_did);
|
||||
let expected_num = match op {
|
||||
PlaceOp::Deref => 0,
|
||||
PlaceOp::Index => 1,
|
||||
} + if generics.has_self { 1 } else { 0 };
|
||||
let num_generics = generics.count();
|
||||
if num_generics != expected_num {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
mut_tr.and_then(|trait_did| {
|
||||
self.lookup_method_in_trait(
|
||||
span,
|
||||
|
20
src/test/ui/lang-items/wrong-number-generic-args-add.rs
Normal file
20
src/test/ui/lang-items/wrong-number-generic-args-add.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Checks whether declaring a lang item with the wrong number
|
||||
// of generic arguments crashes the compiler (issue #83893).
|
||||
|
||||
#![feature(lang_items,no_core)]
|
||||
#![no_core]
|
||||
#![crate_type="lib"]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait MySized {}
|
||||
|
||||
#[lang = "add"]
|
||||
trait MyAdd<'a, T> {}
|
||||
//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718]
|
||||
|
||||
fn ice() {
|
||||
let r = 5;
|
||||
let a = 6;
|
||||
r + a
|
||||
//~^ ERROR: cannot add `{integer}` to `{integer}` [E0369]
|
||||
}
|
20
src/test/ui/lang-items/wrong-number-generic-args-add.stderr
Normal file
20
src/test/ui/lang-items/wrong-number-generic-args-add.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0718]: `add` language item must be applied to a trait with 1 generic argument
|
||||
--> $DIR/wrong-number-generic-args-add.rs:11:1
|
||||
|
|
||||
LL | #[lang = "add"]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | trait MyAdd<'a, T> {}
|
||||
| ------- this trait has 2 generic arguments, not 1
|
||||
|
||||
error[E0369]: cannot add `{integer}` to `{integer}`
|
||||
--> $DIR/wrong-number-generic-args-add.rs:18:7
|
||||
|
|
||||
LL | r + a
|
||||
| - ^ - {integer}
|
||||
| |
|
||||
| {integer}
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0369, E0718.
|
||||
For more information about an error, try `rustc --explain E0369`.
|
19
src/test/ui/lang-items/wrong-number-generic-args-index.rs
Normal file
19
src/test/ui/lang-items/wrong-number-generic-args-index.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Checks whether declaring a lang item with the wrong number
|
||||
// of generic arguments crashes the compiler (issue #83893).
|
||||
|
||||
#![feature(lang_items,no_core)]
|
||||
#![no_core]
|
||||
#![crate_type="lib"]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait MySized {}
|
||||
|
||||
#[lang = "index"]
|
||||
trait MyIndex<'a, T> {}
|
||||
//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718]
|
||||
|
||||
fn ice() {
|
||||
let arr = [0; 5];
|
||||
let _ = arr[2];
|
||||
//~^ ERROR: cannot index into a value of type `[{integer}; 5]` [E0608]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
error[E0718]: `index` language item must be applied to a trait with 1 generic argument
|
||||
--> $DIR/wrong-number-generic-args-index.rs:11:1
|
||||
|
|
||||
LL | #[lang = "index"]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | trait MyIndex<'a, T> {}
|
||||
| ------- this trait has 2 generic arguments, not 1
|
||||
|
||||
error[E0608]: cannot index into a value of type `[{integer}; 5]`
|
||||
--> $DIR/wrong-number-generic-args-index.rs:17:13
|
||||
|
|
||||
LL | let _ = arr[2];
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0608, E0718.
|
||||
For more information about an error, try `rustc --explain E0608`.
|
Loading…
Reference in New Issue
Block a user