Skip to content

Commit 638befc

Browse files
committed
Fixes #2500
Add a seperate typecheck pass collect impl blocks, then report errors. gcc/rust/ChangeLog: * typecheck/rust-hir-inherent-impl-check.h: new typecheck pass * typecheck/rust-hir-type-check.cc: modify the function which test primitive type * typecheck/rust-tyty.cc: the new typecheck pass entrypoint gcc/testsuite/ChangeLog: * rust/compile/issue-2500-rustc.rs: testsuite case same with rustc * rust/compile/issue-2500.rs: testsuite case Signed-off-by: Zhang He <[email protected]>
1 parent 98d89d5 commit 638befc

24 files changed

+166
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (C) 2020-2025 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
#ifndef RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H
19+
#define RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H
20+
21+
#include "rust-diagnostics.h"
22+
#include "rust-hir-item.h"
23+
#include "rust-hir-type-check-base.h"
24+
#include "rust-mapping-common.h"
25+
#include "rust-type-util.h"
26+
27+
namespace Rust {
28+
namespace Resolver {
29+
30+
class PrimitiveImplCheck : public TypeCheckBase
31+
{
32+
public:
33+
static void go ()
34+
{
35+
PrimitiveImplCheck pass;
36+
37+
pass.scan ();
38+
}
39+
40+
private:
41+
void scan ()
42+
43+
{
44+
std::vector<HIR::ImplBlock *> possible_primitive_impl;
45+
mappings.iterate_impl_blocks ([&] (HirId id, HIR::ImplBlock *impl) -> bool {
46+
// filtering trait-impl-blocks
47+
if (impl->has_trait_ref ())
48+
return true;
49+
HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid ();
50+
TyTy::BaseType *impl_type = nullptr;
51+
if (!query_type (impl_ty_id, &impl_type))
52+
return true;
53+
DefId defid = impl->get_mappings().get_defid();
54+
// ignore lang item
55+
if (mappings.lookup_lang_item(defid))
56+
return true;
57+
if (is_primitive_type_kind (impl_type->get_kind ()))
58+
{
59+
possible_primitive_impl.push_back (impl);
60+
}
61+
return true;
62+
});
63+
64+
for (auto impl : possible_primitive_impl)
65+
{
66+
report_error (impl);
67+
}
68+
}
69+
70+
void report_error (HIR::ImplBlock *impl)
71+
{
72+
rich_location r (line_table, impl->get_locus ());
73+
std::string msg = "consider using an extension trait instead";
74+
r.add_fixit_replace (impl->get_locus (), msg.c_str ());
75+
r.add_range (impl->get_locus ());
76+
std::string err = "impl";
77+
err = "cannot define inherent `" + err + "` for primitive types";
78+
rust_error_at (r, ErrorCode::E0390, "%s", err.c_str ());
79+
}
80+
};
81+
82+
} // namespace Resolver
83+
} // namespace Rust
84+
85+
#endif // RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H

gcc/rust/typecheck/rust-hir-type-check.cc

+6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
#include "rust-hir-type-check.h"
2020
#include "rust-hir-full.h"
21+
#include "rust-hir-inherent-impl-check.h"
2122
#include "rust-hir-inherent-impl-overlap.h"
23+
#include "rust-hir-inherent-impl-check.h"
2224
#include "rust-hir-pattern.h"
2325
#include "rust-hir-type-check-expr.h"
2426
#include "rust-hir-type-check-item.h"
@@ -77,6 +79,10 @@ TypeResolution::Resolve (HIR::Crate &crate)
7779
if (saw_errors ())
7880
return;
7981

82+
PrimitiveImplCheck::go ();
83+
if (saw_errors ())
84+
return;
85+
8086
OverlappingImplItemPass::go ();
8187
if (saw_errors ())
8288
return;

gcc/rust/typecheck/rust-tyty.cc

+6
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ is_primitive_type_kind (TypeKind kind)
131131
case TypeKind::FLOAT:
132132
case TypeKind::NEVER:
133133
case TypeKind::STR:
134+
case TypeKind::ARRAY:
135+
case TypeKind::SLICE:
136+
case TypeKind::POINTER:
137+
case TypeKind::REF:
138+
case TypeKind::FNPTR:
139+
case TypeKind::TUPLE:
134140
return true;
135141
default:
136142
return false;

gcc/rust/util/rust-hir-map.cc

+13-1
Original file line numberDiff line numberDiff line change
@@ -1266,8 +1266,11 @@ Mappings::insert_lang_item (LangItem::Kind item_type, DefId id)
12661266
{
12671267
auto it = lang_item_mappings.find (item_type);
12681268
rust_assert (it == lang_item_mappings.end ());
1269-
12701269
lang_item_mappings[item_type] = id;
1270+
1271+
auto rit = rev_lang_item_mappings.find(id);
1272+
rust_assert (rit == rev_lang_item_mappings.end ());
1273+
rev_lang_item_mappings[id] = item_type;
12711274
}
12721275

12731276
tl::optional<DefId &>
@@ -1280,6 +1283,15 @@ Mappings::lookup_lang_item (LangItem::Kind item_type)
12801283
return it->second;
12811284
}
12821285

1286+
tl::optional<LangItem::Kind &>
1287+
Mappings::lookup_lang_item(DefId id)
1288+
{
1289+
auto it = rev_lang_item_mappings.find (id);
1290+
if (it == rev_lang_item_mappings.end ())
1291+
return tl::nullopt;
1292+
return it->second;
1293+
}
1294+
12831295
void
12841296
Mappings::insert_lang_item_node (LangItem::Kind item_type, NodeId node_id)
12851297
{

gcc/rust/util/rust-hir-map.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ class Mappings
258258

259259
void insert_lang_item (LangItem::Kind item_type, DefId id);
260260
tl::optional<DefId &> lookup_lang_item (LangItem::Kind item_type);
261-
261+
tl::optional<LangItem::Kind &> lookup_lang_item (DefId id);
262262
void insert_lang_item_node (LangItem::Kind item_type, NodeId node_id);
263263
tl::optional<NodeId &> lookup_lang_item_node (LangItem::Kind item_type);
264264
NodeId get_lang_item_node (LangItem::Kind item_type);
@@ -391,6 +391,7 @@ class Mappings
391391
// We need to have two maps here, as lang-items need to be used for both AST
392392
// passes and HIR passes. Thus those two maps are created at different times.
393393
std::map<LangItem::Kind, DefId> lang_item_mappings;
394+
std::map<DefId, LangItem::Kind> rev_lang_item_mappings;
394395
std::map<LangItem::Kind, NodeId> lang_item_nodes;
395396

396397
std::map<NodeId, Resolver::CanonicalPath> paths;

gcc/testsuite/rust/compile/const-issue1440.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ mod mem {
2424
macro_rules! impl_uint {
2525
($($ty:ident = $lang:literal),*) => {
2626
$(
27+
#[lang = $lang]
2728
impl $ty {
2829
pub fn wrapping_add(self, rhs: Self) -> Self {
2930
// intrinsics::wrapping_add(self, rhs)

gcc/testsuite/rust/compile/issue-1005.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#[lang = "sized"]
33
pub trait Sized {}
44

5+
#[lang = "const_ptr"]
56
impl<T> *const T {
67
fn test(self) {}
78
}

gcc/testsuite/rust/compile/issue-1130.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod mem {
1111
}
1212
}
1313

14+
#[lang = "u16"]
1415
impl u16 {
1516
fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
1617
unsafe { mem::transmute(self) }

gcc/testsuite/rust/compile/issue-1235.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub union Repr<T> {
1313
raw: FatPtr<T>,
1414
}
1515

16+
#[lang = "slice"]
1617
impl<T> [T] {
1718
pub const fn is_empty(&self) -> bool {
1819
self.len() == 0

gcc/testsuite/rust/compile/issue-1237.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ mod intrinsics {
1010
}
1111
}
1212

13+
#[lang = "const_ptr"]
1314
impl<T> *const T {
1415
pub unsafe fn offset(self, count: isize) -> *const T {
1516
unsafe { intrinsics::offset(self, count) }
1617
}
1718
}
1819

20+
#[lang = "slice"]
1921
impl<T> [T] {
2022
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
2123
unsafe { &*(self as *const [T] as *const T).offset(index as isize) }

gcc/testsuite/rust/compile/issue-2190-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ fn foo<T: Deref<Target = i32>>(t: &T) -> i32 {
1212
t.max(2)
1313
}
1414

15+
#[lang = "i32"]
1516
impl i32 {
1617
fn max(self, other: i32) -> i32 {
1718
if self > other {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
impl u8 {
2+
// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
3+
pub const B: u8 = 0;
4+
}
5+
6+
impl str {
7+
// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
8+
fn foo() {}
9+
}
10+
11+
impl char {
12+
// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
13+
pub const B: u8 = 0;
14+
pub const C: u8 = 0;
15+
fn foo() {}
16+
fn bar(self) {}
17+
}
18+
19+
struct MyType;
20+
impl &MyType {
21+
// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
22+
pub fn for_ref(self) {}
23+
}
24+
25+
fn main() {}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![allow(unused)]
2+
fn main() {
3+
struct Foo {
4+
x: i32
5+
}
6+
7+
impl *mut Foo {}
8+
// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
9+
}

gcc/testsuite/rust/compile/issue-2905-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub mod core {
9292
pub(crate) len: usize,
9393
}
9494

95+
#[lang = "slice"]
9596
impl<T> [T] {
9697
pub fn iter(&self) -> Weird<T> {
9798
Weird::new(self)

gcc/testsuite/rust/compile/iterators1.rs

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ mod mem {
207207
macro_rules! impl_uint {
208208
($($ty:ident = $lang:literal),*) => {
209209
$(
210+
#[lang = $lang]
210211
impl $ty {
211212
pub fn wrapping_add(self, rhs: Self) -> Self {
212213
unsafe {

gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
macro_rules! impl_uint {
44
($($ty:ident = $lang:literal),*) => {
55
$(
6+
#[lang = $lang]
67
impl $ty {
78
pub fn to_le(self) -> Self {
89
#[cfg(not(A))]

gcc/testsuite/rust/compile/macros/mbe/macro54.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ impl Number for u32 {
1818
const VALUE: u32 = foo!(number);
1919
}
2020

21+
#[lang = "u32"]
2122
impl u32 {
2223
pub const TWELVE: u32 = foo!(number);
2324
}

gcc/testsuite/rust/compile/torture/intrinsics-8.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum Option<T> {
1616
Some(T),
1717
}
1818

19+
#[lang = "i32"]
1920
impl i32 {
2021
pub fn checked_add(self, rhs: Self) -> Option<Self> {
2122
let (a, b) = self.overflowing_add(rhs);

gcc/testsuite/rust/compile/torture/issue-1075.rs

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ union Repr<T> {
2020
raw: FatPtr<T>,
2121
}
2222

23+
#[lang = "const_slice_ptr"]
2324
impl<T> *const [T] {
2425
pub const fn len(self) -> usize {
2526
// SAFETY: this is safe because `*const [T]` and `FatPtr<T>` have the same layout.
@@ -32,6 +33,7 @@ impl<T> *const [T] {
3233
}
3334
}
3435

36+
#[lang = "const_ptr"]
3537
impl<T> *const T {
3638
pub const unsafe fn offset(self, count: isize) -> *const T {
3739
unsafe { offset(self, count) }

gcc/testsuite/rust/compile/torture/issue-1432.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ mod mem {
2929
macro_rules! impl_uint {
3030
($($ty:ident = $lang:literal),*) => {
3131
$(
32+
#[lang = $lang]
3233
impl $ty {
3334
pub fn wrapping_add(self, rhs: Self) -> Self {
3435
// intrinsics::wrapping_add(self, rhs)

gcc/testsuite/rust/execute/torture/issue-1436.rs

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ trait Index<Idx> {
8686
fn index(&self, index: Idx) -> &Self::Output;
8787
}
8888

89+
#[lang = "slice"]
8990
impl<T> [T] {
9091
pub const fn is_empty(&self) -> bool {
9192
self.len() == 0

gcc/testsuite/rust/execute/torture/issue-2236.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod core {
2020
}
2121
}
2222

23+
#[lang = "i32"]
2324
impl i32 {
2425
fn max(self, other: i32) -> i32 {
2526
if self > other {

gcc/testsuite/rust/execute/torture/iter1.rs

+1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ mod mem {
208208
macro_rules! impl_uint {
209209
($($ty:ident = $lang:literal),*) => {
210210
$(
211+
#[lang = $lang]
211212
impl $ty {
212213
pub fn wrapping_add(self, rhs: Self) -> Self {
213214
unsafe {

gcc/testsuite/rust/execute/torture/str-layout1.rs

+2
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ pub union Repr<T> {
2727
raw: FatPtr<T>,
2828
}
2929

30+
#[lang = "slice"]
3031
impl<T> [T] {
3132
pub const fn len(&self) -> usize {
3233
unsafe { Repr { rust: self }.raw.len }
3334
}
3435
}
3536

37+
#[lang = "str"]
3638
impl str {
3739
pub const fn len(&self) -> usize {
3840
self.as_bytes().len()

0 commit comments

Comments
 (0)