diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-check.h b/gcc/rust/typecheck/rust-hir-inherent-impl-check.h
new file mode 100644
index 000000000000..2426a911d014
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-inherent-impl-check.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2020-2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// .
+#ifndef RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H
+#define RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H
+
+#include "rust-diagnostics.h"
+#include "rust-hir-item.h"
+#include "rust-hir-type-check-base.h"
+#include "rust-mapping-common.h"
+#include "rust-type-util.h"
+
+namespace Rust {
+namespace Resolver {
+
+class PrimitiveImplCheck : public TypeCheckBase
+{
+public:
+ static void go ()
+ {
+ PrimitiveImplCheck pass;
+
+ pass.scan ();
+ }
+
+private:
+ void scan ()
+
+ {
+ std::vector possible_primitive_impl;
+ mappings.iterate_impl_blocks ([&] (HirId id, HIR::ImplBlock *impl) -> bool {
+ // filtering trait-impl-blocks
+ if (impl->has_trait_ref ())
+ return true;
+ HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid ();
+ TyTy::BaseType *impl_type = nullptr;
+ if (!query_type (impl_ty_id, &impl_type))
+ return true;
+ DefId defid = impl->get_mappings ().get_defid ();
+ // ignore lang item
+ if (mappings.lookup_lang_item (defid))
+ return true;
+ if (is_primitive_type_kind (impl_type->get_kind ()))
+ {
+ possible_primitive_impl.push_back (impl);
+ }
+ return true;
+ });
+
+ for (auto impl : possible_primitive_impl)
+ {
+ report_error (impl);
+ }
+ }
+
+ void report_error (HIR::ImplBlock *impl)
+ {
+ rich_location r (line_table, impl->get_locus ());
+ std::string msg = "consider using an extension trait instead";
+ r.add_fixit_replace (impl->get_locus (), msg.c_str ());
+ r.add_range (impl->get_locus ());
+ std::string err = "impl";
+ err = "cannot define inherent `" + err + "` for primitive types";
+ rust_error_at (r, ErrorCode::E0390, "%s", err.c_str ());
+ }
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_INHERENT_IMPL_ITEM_CHECK_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index 1e9f7d2f00dd..2cc2d85340fc 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -19,6 +19,7 @@
#include "rust-hir-type-check.h"
#include "rust-hir-full.h"
#include "rust-hir-inherent-impl-overlap.h"
+#include "rust-hir-inherent-impl-check.h"
#include "rust-hir-pattern.h"
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-item.h"
@@ -77,6 +78,10 @@ TypeResolution::Resolve (HIR::Crate &crate)
if (saw_errors ())
return;
+ PrimitiveImplCheck::go ();
+ if (saw_errors ())
+ return;
+
OverlappingImplItemPass::go ();
if (saw_errors ())
return;
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 116c1abdf8e8..2e1728b3a861 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -131,6 +131,12 @@ is_primitive_type_kind (TypeKind kind)
case TypeKind::FLOAT:
case TypeKind::NEVER:
case TypeKind::STR:
+ case TypeKind::ARRAY:
+ case TypeKind::SLICE:
+ case TypeKind::POINTER:
+ case TypeKind::REF:
+ case TypeKind::FNPTR:
+ case TypeKind::TUPLE:
return true;
default:
return false;
diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc
index 4d2927281a21..705bcd472de4 100644
--- a/gcc/rust/util/rust-hir-map.cc
+++ b/gcc/rust/util/rust-hir-map.cc
@@ -1266,8 +1266,11 @@ Mappings::insert_lang_item (LangItem::Kind item_type, DefId id)
{
auto it = lang_item_mappings.find (item_type);
rust_assert (it == lang_item_mappings.end ());
-
lang_item_mappings[item_type] = id;
+
+ auto rit = rev_lang_item_mappings.find (id);
+ rust_assert (rit == rev_lang_item_mappings.end ());
+ rev_lang_item_mappings[id] = item_type;
}
tl::optional
@@ -1280,6 +1283,15 @@ Mappings::lookup_lang_item (LangItem::Kind item_type)
return it->second;
}
+tl::optional
+Mappings::lookup_lang_item (DefId id)
+{
+ auto it = rev_lang_item_mappings.find (id);
+ if (it == rev_lang_item_mappings.end ())
+ return tl::nullopt;
+ return it->second;
+}
+
void
Mappings::insert_lang_item_node (LangItem::Kind item_type, NodeId node_id)
{
diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h
index 6f21f38b4491..ff72a42b822e 100644
--- a/gcc/rust/util/rust-hir-map.h
+++ b/gcc/rust/util/rust-hir-map.h
@@ -258,7 +258,7 @@ class Mappings
void insert_lang_item (LangItem::Kind item_type, DefId id);
tl::optional lookup_lang_item (LangItem::Kind item_type);
-
+ tl::optional lookup_lang_item (DefId id);
void insert_lang_item_node (LangItem::Kind item_type, NodeId node_id);
tl::optional lookup_lang_item_node (LangItem::Kind item_type);
NodeId get_lang_item_node (LangItem::Kind item_type);
@@ -391,6 +391,7 @@ class Mappings
// We need to have two maps here, as lang-items need to be used for both AST
// passes and HIR passes. Thus those two maps are created at different times.
std::map lang_item_mappings;
+ std::map rev_lang_item_mappings;
std::map lang_item_nodes;
std::map paths;
diff --git a/gcc/testsuite/rust/compile/const-issue1440.rs b/gcc/testsuite/rust/compile/const-issue1440.rs
index 3a2989cc8d02..1cf87c0c6c15 100644
--- a/gcc/testsuite/rust/compile/const-issue1440.rs
+++ b/gcc/testsuite/rust/compile/const-issue1440.rs
@@ -24,6 +24,7 @@ mod mem {
macro_rules! impl_uint {
($($ty:ident = $lang:literal),*) => {
$(
+ #[lang = $lang]
impl $ty {
pub fn wrapping_add(self, rhs: Self) -> Self {
// intrinsics::wrapping_add(self, rhs)
diff --git a/gcc/testsuite/rust/compile/issue-1005.rs b/gcc/testsuite/rust/compile/issue-1005.rs
index 15d4bef08c2a..e4bd7aa69046 100644
--- a/gcc/testsuite/rust/compile/issue-1005.rs
+++ b/gcc/testsuite/rust/compile/issue-1005.rs
@@ -2,6 +2,7 @@
#[lang = "sized"]
pub trait Sized {}
+#[lang = "const_ptr"]
impl *const T {
fn test(self) {}
}
diff --git a/gcc/testsuite/rust/compile/issue-1130.rs b/gcc/testsuite/rust/compile/issue-1130.rs
index 115e6aad2f15..69db6e04072f 100644
--- a/gcc/testsuite/rust/compile/issue-1130.rs
+++ b/gcc/testsuite/rust/compile/issue-1130.rs
@@ -11,6 +11,7 @@ mod mem {
}
}
+#[lang = "u16"]
impl u16 {
fn to_ne_bytes(self) -> [u8; mem::size_of::()] {
unsafe { mem::transmute(self) }
diff --git a/gcc/testsuite/rust/compile/issue-1235.rs b/gcc/testsuite/rust/compile/issue-1235.rs
index 7c85ac4a6b00..9ff9ced6b63a 100644
--- a/gcc/testsuite/rust/compile/issue-1235.rs
+++ b/gcc/testsuite/rust/compile/issue-1235.rs
@@ -13,6 +13,7 @@ pub union Repr {
raw: FatPtr,
}
+#[lang = "slice"]
impl [T] {
pub const fn is_empty(&self) -> bool {
self.len() == 0
diff --git a/gcc/testsuite/rust/compile/issue-1237.rs b/gcc/testsuite/rust/compile/issue-1237.rs
index 79b60b07b522..cdc715ab5197 100644
--- a/gcc/testsuite/rust/compile/issue-1237.rs
+++ b/gcc/testsuite/rust/compile/issue-1237.rs
@@ -10,12 +10,14 @@ mod intrinsics {
}
}
+#[lang = "const_ptr"]
impl *const T {
pub unsafe fn offset(self, count: isize) -> *const T {
unsafe { intrinsics::offset(self, count) }
}
}
+#[lang = "slice"]
impl [T] {
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
unsafe { &*(self as *const [T] as *const T).offset(index as isize) }
diff --git a/gcc/testsuite/rust/compile/issue-2190-2.rs b/gcc/testsuite/rust/compile/issue-2190-2.rs
index 1c933386aa46..b8e0331649d9 100644
--- a/gcc/testsuite/rust/compile/issue-2190-2.rs
+++ b/gcc/testsuite/rust/compile/issue-2190-2.rs
@@ -12,6 +12,7 @@ fn foo>(t: &T) -> i32 {
t.max(2)
}
+#[lang = "i32"]
impl i32 {
fn max(self, other: i32) -> i32 {
if self > other {
diff --git a/gcc/testsuite/rust/compile/issue-2500-rustc.rs b/gcc/testsuite/rust/compile/issue-2500-rustc.rs
new file mode 100644
index 000000000000..e9dbc5aa3546
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2500-rustc.rs
@@ -0,0 +1,25 @@
+impl u8 {
+ // { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
+ pub const B: u8 = 0;
+}
+
+impl str {
+ // { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
+ fn foo() {}
+}
+
+impl char {
+ // { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
+ pub const B: u8 = 0;
+ pub const C: u8 = 0;
+ fn foo() {}
+ fn bar(self) {}
+}
+
+struct MyType;
+impl &MyType {
+ // { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
+ pub fn for_ref(self) {}
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issue-2500.rs b/gcc/testsuite/rust/compile/issue-2500.rs
new file mode 100644
index 000000000000..eacb45a7728f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2500.rs
@@ -0,0 +1,9 @@
+#![allow(unused)]
+fn main() {
+struct Foo {
+ x: i32
+}
+
+impl *mut Foo {}
+// { dg-error "cannot define inherent `impl` for primitive types" "" { target *-*-* } .-1 }
+}
\ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/issue-2905-2.rs b/gcc/testsuite/rust/compile/issue-2905-2.rs
index 83c54ed92e5f..7a5e7420f247 100644
--- a/gcc/testsuite/rust/compile/issue-2905-2.rs
+++ b/gcc/testsuite/rust/compile/issue-2905-2.rs
@@ -92,6 +92,7 @@ pub mod core {
pub(crate) len: usize,
}
+ #[lang = "slice"]
impl [T] {
pub fn iter(&self) -> Weird {
Weird::new(self)
diff --git a/gcc/testsuite/rust/compile/iterators1.rs b/gcc/testsuite/rust/compile/iterators1.rs
index 1141758b14a7..55d5942ef868 100644
--- a/gcc/testsuite/rust/compile/iterators1.rs
+++ b/gcc/testsuite/rust/compile/iterators1.rs
@@ -207,6 +207,7 @@ mod mem {
macro_rules! impl_uint {
($($ty:ident = $lang:literal),*) => {
$(
+ #[lang = $lang]
impl $ty {
pub fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
index 7fab787b9e8d..4c003dcf3488 100644
--- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
@@ -3,6 +3,7 @@
macro_rules! impl_uint {
($($ty:ident = $lang:literal),*) => {
$(
+ #[lang = $lang]
impl $ty {
pub fn to_le(self) -> Self {
#[cfg(not(A))]
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro54.rs b/gcc/testsuite/rust/compile/macros/mbe/macro54.rs
index d3b3f806a6a0..8f0fc6654d4a 100644
--- a/gcc/testsuite/rust/compile/macros/mbe/macro54.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro54.rs
@@ -18,6 +18,7 @@ impl Number for u32 {
const VALUE: u32 = foo!(number);
}
+#[lang = "u32"]
impl u32 {
pub const TWELVE: u32 = foo!(number);
}
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-8.rs b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
index b9bd83c76240..47a9098ffa6a 100644
--- a/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
+++ b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
@@ -16,6 +16,7 @@ pub enum Option {
Some(T),
}
+#[lang = "i32"]
impl i32 {
pub fn checked_add(self, rhs: Self) -> Option {
let (a, b) = self.overflowing_add(rhs);
diff --git a/gcc/testsuite/rust/compile/torture/issue-1075.rs b/gcc/testsuite/rust/compile/torture/issue-1075.rs
index d23774b2c0bb..ba1d424494ce 100644
--- a/gcc/testsuite/rust/compile/torture/issue-1075.rs
+++ b/gcc/testsuite/rust/compile/torture/issue-1075.rs
@@ -20,6 +20,7 @@ union Repr {
raw: FatPtr,
}
+#[lang = "const_slice_ptr"]
impl *const [T] {
pub const fn len(self) -> usize {
// SAFETY: this is safe because `*const [T]` and `FatPtr` have the same layout.
@@ -32,6 +33,7 @@ impl *const [T] {
}
}
+#[lang = "const_ptr"]
impl *const T {
pub const unsafe fn offset(self, count: isize) -> *const T {
unsafe { offset(self, count) }
diff --git a/gcc/testsuite/rust/compile/torture/issue-1432.rs b/gcc/testsuite/rust/compile/torture/issue-1432.rs
index 5b526fdd52db..e66a9bd3c1ba 100644
--- a/gcc/testsuite/rust/compile/torture/issue-1432.rs
+++ b/gcc/testsuite/rust/compile/torture/issue-1432.rs
@@ -29,6 +29,7 @@ mod mem {
macro_rules! impl_uint {
($($ty:ident = $lang:literal),*) => {
$(
+ #[lang = $lang]
impl $ty {
pub fn wrapping_add(self, rhs: Self) -> Self {
// intrinsics::wrapping_add(self, rhs)
diff --git a/gcc/testsuite/rust/execute/torture/issue-1436.rs b/gcc/testsuite/rust/execute/torture/issue-1436.rs
index 5d909078b5ec..769ef672839b 100644
--- a/gcc/testsuite/rust/execute/torture/issue-1436.rs
+++ b/gcc/testsuite/rust/execute/torture/issue-1436.rs
@@ -86,6 +86,7 @@ trait Index {
fn index(&self, index: Idx) -> &Self::Output;
}
+#[lang = "slice"]
impl [T] {
pub const fn is_empty(&self) -> bool {
self.len() == 0
diff --git a/gcc/testsuite/rust/execute/torture/issue-2236.rs b/gcc/testsuite/rust/execute/torture/issue-2236.rs
index 850b99718ef6..884c46bd36bd 100644
--- a/gcc/testsuite/rust/execute/torture/issue-2236.rs
+++ b/gcc/testsuite/rust/execute/torture/issue-2236.rs
@@ -20,6 +20,7 @@ mod core {
}
}
+#[lang = "i32"]
impl i32 {
fn max(self, other: i32) -> i32 {
if self > other {
diff --git a/gcc/testsuite/rust/execute/torture/iter1.rs b/gcc/testsuite/rust/execute/torture/iter1.rs
index c3b6c7bc3f89..6ff9529ad42e 100644
--- a/gcc/testsuite/rust/execute/torture/iter1.rs
+++ b/gcc/testsuite/rust/execute/torture/iter1.rs
@@ -208,6 +208,7 @@ mod mem {
macro_rules! impl_uint {
($($ty:ident = $lang:literal),*) => {
$(
+ #[lang = $lang]
impl $ty {
pub fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
diff --git a/gcc/testsuite/rust/execute/torture/str-layout1.rs b/gcc/testsuite/rust/execute/torture/str-layout1.rs
index fb3b4e34a7c2..e76b43948672 100644
--- a/gcc/testsuite/rust/execute/torture/str-layout1.rs
+++ b/gcc/testsuite/rust/execute/torture/str-layout1.rs
@@ -27,12 +27,14 @@ pub union Repr {
raw: FatPtr,
}
+#[lang = "slice"]
impl [T] {
pub const fn len(&self) -> usize {
unsafe { Repr { rust: self }.raw.len }
}
}
+#[lang = "str"]
impl str {
pub const fn len(&self) -> usize {
self.as_bytes().len()