Report an error if a lang item has the wrong number of generic arguments

This commit is contained in:
Fabian Wolff 2021-05-15 19:53:16 +02:00
parent b439be03c9
commit 7217d767b2
12 changed files with 212 additions and 7 deletions

View File

@ -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.

View File

@ -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>`

View File

@ -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))

View File

@ -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,

View 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]
}

View 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`.

View 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]
}

View File

@ -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`.