Skip to content

Commit 385a233

Browse files
committed
Detect incorrect number of lang item generics
1 parent 5585532 commit 385a233

12 files changed

+330
-319
lines changed

compiler/rustc_error_codes/src/error_codes/E0152.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Erroneous code example:
66
#![feature(lang_items)]
77
88
#[lang = "owned_box"]
9-
struct Foo; // error: duplicate lang item found: `owned_box`
9+
struct Foo<T>(T); // error: duplicate lang item found: `owned_box`
1010
```
1111

1212
Lang items are already implemented in the standard library. Unless you are

compiler/rustc_hir/src/lang_items.rs

+163-151
Large diffs are not rendered by default.

compiler/rustc_passes/src/lang_items.rs

+35-87
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_errors::{pluralize, struct_span_err};
1717
use rustc_hir as hir;
1818
use rustc_hir::def_id::DefId;
1919
use rustc_hir::itemlikevisit::ItemLikeVisitor;
20-
use rustc_hir::lang_items::{extract, ITEM_REFS};
20+
use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
2121
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
2222
use rustc_span::Span;
2323

@@ -182,121 +182,69 @@ impl LanguageItemCollector<'tcx> {
182182
}
183183

184184
// Like collect_item() above, but also checks whether the lang item is declared
185-
// with the right number of generic arguments if it is a trait.
185+
// with the right number of generic arguments.
186186
fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
187187
let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
188188
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
189189
let name = lang_item.name();
190190

191-
self.collect_item(item_index, item_def_id);
192-
193191
// Now check whether the lang_item has the expected number of generic
194-
// arguments if it is a trait. Generally speaking, binary and indexing
195-
// operations have one (for the RHS/index), unary operations have none,
196-
// and the rest also have none except for the closure traits (one for
197-
// the argument list), generators (one for the resume argument),
198-
// ordering/equality relations (one for the RHS), and various conversion
199-
// traits.
200-
201-
let expected_num = match lang_item {
202-
// Binary operations
203-
LangItem::Add
204-
| LangItem::Sub
205-
| LangItem::Mul
206-
| LangItem::Div
207-
| LangItem::Rem
208-
| LangItem::BitXor
209-
| LangItem::BitAnd
210-
| LangItem::BitOr
211-
| LangItem::Shl
212-
| LangItem::Shr
213-
| LangItem::AddAssign
214-
| LangItem::SubAssign
215-
| LangItem::MulAssign
216-
| LangItem::DivAssign
217-
| LangItem::RemAssign
218-
| LangItem::BitXorAssign
219-
| LangItem::BitAndAssign
220-
| LangItem::BitOrAssign
221-
| LangItem::ShlAssign
222-
| LangItem::ShrAssign
223-
| LangItem::Index
224-
| LangItem::IndexMut
225-
226-
// Miscellaneous
227-
| LangItem::Unsize
228-
| LangItem::CoerceUnsized
229-
| LangItem::DispatchFromDyn
230-
| LangItem::Fn
231-
| LangItem::FnMut
232-
| LangItem::FnOnce
233-
| LangItem::Generator
234-
| LangItem::PartialEq
235-
| LangItem::PartialOrd
236-
=> Some(1),
237-
238-
// Unary operations
239-
LangItem::Neg
240-
| LangItem::Not
241-
242-
// Miscellaneous
243-
| LangItem::Deref
244-
| LangItem::DerefMut
245-
| LangItem::Sized
246-
| LangItem::StructuralPeq
247-
| LangItem::StructuralTeq
248-
| LangItem::Copy
249-
| LangItem::Clone
250-
| LangItem::Sync
251-
| LangItem::DiscriminantKind
252-
| LangItem::PointeeTrait
253-
| LangItem::Freeze
254-
| LangItem::Drop
255-
| LangItem::Receiver
256-
| LangItem::Future
257-
| LangItem::Unpin
258-
| LangItem::Termination
259-
| LangItem::Try
260-
=> Some(0),
192+
// arguments. Generally speaking, binary and indexing operations have
193+
// one (for the RHS/index), unary operations have none, the closure
194+
// traits have one for the argument list, generators have one for the
195+
// resume argument, and ordering/equality relations have one for the RHS
196+
// Some other types like Box and various functions like drop_in_place
197+
// have minimum requirements.
261198

262-
// Not a trait
263-
_ => None,
264-
};
199+
if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id)
200+
{
201+
let (actual_num, generics_span) = match kind.generics() {
202+
Some(generics) => (generics.params.len(), generics.span),
203+
None => (0, *item_span),
204+
};
265205

266-
if let Some(expected_num) = expected_num {
267-
let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) {
268-
hir::Node::Item(hir::Item {
269-
kind: hir::ItemKind::Trait(_, _, generics, ..),
270-
..
271-
}) => (generics.params.len(), generics.span),
272-
_ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item),
206+
let required = match lang_item.required_generics() {
207+
GenericRequirement::Exact(num) if num != actual_num => {
208+
Some((format!("{}", num), pluralize!(num)))
209+
}
210+
GenericRequirement::Minimum(num) if actual_num < num => {
211+
Some((format!("at least {}", num), pluralize!(num)))
212+
}
213+
// If the number matches, or there is no requirement, handle it normally
214+
_ => None,
273215
};
274216

275-
if expected_num != actual_num {
217+
if let Some((range_str, pluralized)) = required {
276218
// We are issuing E0718 "incorrect target" here, because while the
277219
// item kind of the target is correct, the target is still wrong
278220
// because of the wrong number of generic arguments.
279221
struct_span_err!(
280222
self.tcx.sess,
281223
span,
282224
E0718,
283-
"`{}` language item must be applied to a trait with {} generic argument{}",
225+
"`{}` language item must be applied to a {} with {} generic argument{}",
284226
name,
285-
expected_num,
286-
pluralize!(expected_num)
227+
kind.descr(),
228+
range_str,
229+
pluralized,
287230
)
288231
.span_label(
289232
generics_span,
290233
format!(
291-
"this trait has {} generic argument{}, not {}",
234+
"this {} has {} generic argument{}",
235+
kind.descr(),
292236
actual_num,
293237
pluralize!(actual_num),
294-
expected_num
295238
),
296239
)
297240
.emit();
241+
242+
// return early to not collect the lang item
243+
return;
298244
}
299245
}
246+
247+
self.collect_item(item_index, item_def_id);
300248
}
301249
}
302250

src/test/ui/error-codes/E0152.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![feature(lang_items)]
33

44
#[lang = "owned_box"]
5-
struct Foo; //~ ERROR E0152
5+
struct Foo<T>(T); //~ ERROR E0152
66

77
fn main() {
88
}

src/test/ui/error-codes/E0152.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0152]: found duplicate lang item `owned_box`
22
--> $DIR/E0152.rs:5:1
33
|
4-
LL | struct Foo;
5-
| ^^^^^^^^^^^
4+
LL | struct Foo<T>(T);
5+
| ^^^^^^^^^^^^^^^^^
66
|
77
= note: the lang item is first defined in crate `alloc` (which `std` depends on)
88
= note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// build-pass
2+
3+
#![feature(lang_items,no_core)]
4+
#![no_core]
5+
#![crate_type="lib"]
6+
7+
#[lang = "sized"]
8+
trait MySized {}
9+
10+
#[lang = "copy"]
11+
trait MyCopy {}
12+
13+
#[lang = "drop"]
14+
trait MyDrop<T> {}
15+
16+
struct S;
17+
18+
impl<T> MyDrop<T> for S {}
19+
20+
#[lang = "i32"]
21+
impl<'a> i32 {
22+
fn foo() {}
23+
}
24+
25+
fn bar() {
26+
i32::foo();
27+
S;
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Checks whether declaring a lang item with the wrong number
2+
// of generic arguments crashes the compiler (issue #83893, #87573, and part of #9307).
3+
4+
#![feature(lang_items, no_core)]
5+
#![no_core]
6+
#![crate_type = "lib"]
7+
8+
#[lang = "sized"]
9+
trait MySized {}
10+
11+
#[lang = "add"]
12+
trait MyAdd<'a, T> {}
13+
//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718]
14+
15+
#[lang = "drop_in_place"]
16+
//~^ ERROR `drop_in_place` language item must be applied to a function with at least 1 generic
17+
fn my_ptr_drop() {}
18+
19+
#[lang = "index"]
20+
trait MyIndex<'a, T> {}
21+
//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718]
22+
23+
#[lang = "phantom_data"]
24+
//~^ ERROR `phantom_data` language item must be applied to a struct with 1 generic argument
25+
struct MyPhantomData<T, U>;
26+
//~^ ERROR parameter `T` is never used
27+
//~| ERROR parameter `U` is never used
28+
29+
fn ice() {
30+
// Use add
31+
let r = 5;
32+
let a = 6;
33+
r + a;
34+
35+
// Use drop in place
36+
my_ptr_drop();
37+
38+
// Use index
39+
let arr = [0; 5];
40+
let _ = arr[2];
41+
42+
// Use phantomdata
43+
let _ = MyPhantomData::<(), i32>;
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
error[E0718]: `add` language item must be applied to a trait with 1 generic argument
2+
--> $DIR/lang-item-generic-requirements.rs:11:1
3+
|
4+
LL | #[lang = "add"]
5+
| ^^^^^^^^^^^^^^^
6+
LL | trait MyAdd<'a, T> {}
7+
| ------- this trait has 2 generic arguments
8+
9+
error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument
10+
--> $DIR/lang-item-generic-requirements.rs:15:1
11+
|
12+
LL | #[lang = "drop_in_place"]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
14+
LL |
15+
LL | fn my_ptr_drop() {}
16+
| - this function has 0 generic arguments
17+
18+
error[E0718]: `index` language item must be applied to a trait with 1 generic argument
19+
--> $DIR/lang-item-generic-requirements.rs:19:1
20+
|
21+
LL | #[lang = "index"]
22+
| ^^^^^^^^^^^^^^^^^
23+
LL | trait MyIndex<'a, T> {}
24+
| ------- this trait has 2 generic arguments
25+
26+
error[E0718]: `phantom_data` language item must be applied to a struct with 1 generic argument
27+
--> $DIR/lang-item-generic-requirements.rs:23:1
28+
|
29+
LL | #[lang = "phantom_data"]
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^
31+
LL |
32+
LL | struct MyPhantomData<T, U>;
33+
| ------ this struct has 2 generic arguments
34+
35+
error[E0392]: parameter `T` is never used
36+
--> $DIR/lang-item-generic-requirements.rs:25:22
37+
|
38+
LL | struct MyPhantomData<T, U>;
39+
| ^ unused parameter
40+
|
41+
= help: consider removing `T` or referring to it in a field
42+
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
43+
44+
error[E0392]: parameter `U` is never used
45+
--> $DIR/lang-item-generic-requirements.rs:25:25
46+
|
47+
LL | struct MyPhantomData<T, U>;
48+
| ^ unused parameter
49+
|
50+
= help: consider removing `U` or referring to it in a field
51+
= help: if you intended `U` to be a const parameter, use `const U: usize` instead
52+
53+
error: aborting due to 6 previous errors
54+
55+
Some errors have detailed explanations: E0392, E0718.
56+
For more information about an error, try `rustc --explain E0392`.

src/test/ui/lang-items/wrong-number-generic-args-add.rs

-20
This file was deleted.

src/test/ui/lang-items/wrong-number-generic-args-add.stderr

-20
This file was deleted.

src/test/ui/lang-items/wrong-number-generic-args-index.rs

-19
This file was deleted.

0 commit comments

Comments
 (0)