Rollup merge of #85339 - FabianWolff:issue-83893, r=varkor
Report an error if a lang item has the wrong number of generic arguments This pull request fixes #83893. The issue is that the lang item code currently checks whether the lang item has the correct item kind (e.g. a `#[lang="add"]` has to be a trait), but not whether the item has the correct number of generic arguments. This can lead to an "index out of bounds" ICE when the compiler tries to create more substitutions than there are suitable types available (if the lang item was declared with too many generic arguments). For instance, here is a reduced ("reduced" in the sense that it does not trigger additional errors) version of the example given in #83893: ```rust #![feature(lang_items,no_core)] #![no_core] #![crate_type="lib"] #[lang = "sized"] trait MySized {} #[lang = "add"] trait MyAdd<'a, T> {} fn ice() { let r = 5; let a = 6; r + a } ``` On current nightly, this immediately causes an ICE without any warnings or errors emitted. With the changes in this PR, however, I get no ICE and two errors: ``` error[E0718]: `add` language item must be applied to a trait with 1 generic argument --> pr-ex.rs:8:1 | 8 | #[lang = "add"] | ^^^^^^^^^^^^^^^ 9 | trait MyAdd<'a, T> {} | ------- this trait has 2 generic arguments, not 1 error[E0369]: cannot add `{integer}` to `{integer}` --> pr-ex.rs:14:7 | 14 | 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`. ```
This commit is contained in:
commit
1bfd987f69
13 changed files with 263 additions and 7 deletions
|
@ -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>`
|
||||
|
|
|
@ -1187,3 +1187,14 @@ fn fatally_break_rust(sess: &Session) {
|
|||
fn potentially_plural_count(count: usize, word: &str) -> String {
|
||||
format!("{} {}{}", count, word, pluralize!(count))
|
||||
}
|
||||
|
||||
fn has_expected_num_generic_args<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_did: Option<DefId>,
|
||||
expected: usize,
|
||||
) -> bool {
|
||||
trait_did.map_or(true, |trait_did| {
|
||||
let generics = tcx.generics_of(trait_did);
|
||||
generics.count() == expected + if generics.has_self { 1 } else { 0 }
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Code related to processing overloaded binary and unary operators.
|
||||
|
||||
use super::method::MethodCallee;
|
||||
use super::FnCtxt;
|
||||
use super::{has_expected_num_generic_args, FnCtxt};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
|
@ -795,6 +795,23 @@ 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 !has_expected_num_generic_args(
|
||||
self.tcx,
|
||||
trait_did,
|
||||
match op {
|
||||
// Binary ops have a generic right-hand side, unary ops don't
|
||||
Op::Binary(..) => 1,
|
||||
Op::Unary(..) => 0,
|
||||
},
|
||||
) {
|
||||
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))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::check::method::MethodCallee;
|
||||
use crate::check::{FnCtxt, PlaceOp};
|
||||
use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::InferOk;
|
||||
|
@ -153,6 +153,21 @@ 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 !has_expected_num_generic_args(
|
||||
self.tcx,
|
||||
imm_tr,
|
||||
match op {
|
||||
PlaceOp::Deref => 0,
|
||||
PlaceOp::Index => 1,
|
||||
},
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
imm_tr.and_then(|trait_did| {
|
||||
self.lookup_method_in_trait(
|
||||
span,
|
||||
|
@ -177,6 +192,21 @@ 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 !has_expected_num_generic_args(
|
||||
self.tcx,
|
||||
mut_tr,
|
||||
match op {
|
||||
PlaceOp::Deref => 0,
|
||||
PlaceOp::Index => 1,
|
||||
},
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
mut_tr.and_then(|trait_did| {
|
||||
self.lookup_method_in_trait(
|
||||
span,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue