Skip to content

Commit

Permalink
Fixes #2500
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
zhanghe9702 committed Jan 31, 2025
1 parent 98d89d5 commit 638befc
Show file tree
Hide file tree
Showing 24 changed files with 166 additions and 2 deletions.
85 changes: 85 additions & 0 deletions gcc/rust/typecheck/rust-hir-inherent-impl-check.h
Original file line number Diff line number Diff line change
@@ -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
// <http://www.gnu.org/licenses/>.
#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<HIR::ImplBlock *> 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
6 changes: 6 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

#include "rust-hir-type-check.h"
#include "rust-hir-full.h"
#include "rust-hir-inherent-impl-check.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"
Expand Down Expand Up @@ -77,6 +79,10 @@ TypeResolution::Resolve (HIR::Crate &crate)
if (saw_errors ())
return;

PrimitiveImplCheck::go ();
if (saw_errors ())
return;

OverlappingImplItemPass::go ();
if (saw_errors ())
return;
Expand Down
6 changes: 6 additions & 0 deletions gcc/rust/typecheck/rust-tyty.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 13 additions & 1 deletion gcc/rust/util/rust-hir-map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<DefId &>
Expand All @@ -1280,6 +1283,15 @@ Mappings::lookup_lang_item (LangItem::Kind item_type)
return it->second;
}

tl::optional<LangItem::Kind &>
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)
{
Expand Down
3 changes: 2 additions & 1 deletion gcc/rust/util/rust-hir-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ class Mappings

void insert_lang_item (LangItem::Kind item_type, DefId id);
tl::optional<DefId &> lookup_lang_item (LangItem::Kind item_type);

tl::optional<LangItem::Kind &> lookup_lang_item (DefId id);
void insert_lang_item_node (LangItem::Kind item_type, NodeId node_id);
tl::optional<NodeId &> lookup_lang_item_node (LangItem::Kind item_type);
NodeId get_lang_item_node (LangItem::Kind item_type);
Expand Down Expand Up @@ -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<LangItem::Kind, DefId> lang_item_mappings;
std::map<DefId, LangItem::Kind> rev_lang_item_mappings;
std::map<LangItem::Kind, NodeId> lang_item_nodes;

std::map<NodeId, Resolver::CanonicalPath> paths;
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/const-issue1440.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/issue-1005.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#[lang = "sized"]
pub trait Sized {}

#[lang = "const_ptr"]
impl<T> *const T {
fn test(self) {}
}
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/issue-1130.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod mem {
}
}

#[lang = "u16"]
impl u16 {
fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
unsafe { mem::transmute(self) }
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/issue-1235.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub union Repr<T> {
raw: FatPtr<T>,
}

#[lang = "slice"]
impl<T> [T] {
pub const fn is_empty(&self) -> bool {
self.len() == 0
Expand Down
2 changes: 2 additions & 0 deletions gcc/testsuite/rust/compile/issue-1237.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ mod intrinsics {
}
}

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

#[lang = "slice"]
impl<T> [T] {
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
unsafe { &*(self as *const [T] as *const T).offset(index as isize) }
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/issue-2190-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fn foo<T: Deref<Target = i32>>(t: &T) -> i32 {
t.max(2)
}

#[lang = "i32"]
impl i32 {
fn max(self, other: i32) -> i32 {
if self > other {
Expand Down
25 changes: 25 additions & 0 deletions gcc/testsuite/rust/compile/issue-2500-rustc.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions gcc/testsuite/rust/compile/issue-2500.rs
Original file line number Diff line number Diff line change
@@ -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 }
}
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/issue-2905-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub mod core {
pub(crate) len: usize,
}

#[lang = "slice"]
impl<T> [T] {
pub fn iter(&self) -> Weird<T> {
Weird::new(self)
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/iterators1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/macros/mbe/macro54.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ impl Number for u32 {
const VALUE: u32 = foo!(number);
}

#[lang = "u32"]
impl u32 {
pub const TWELVE: u32 = foo!(number);
}
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/torture/intrinsics-8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub enum Option<T> {
Some(T),
}

#[lang = "i32"]
impl i32 {
pub fn checked_add(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_add(rhs);
Expand Down
2 changes: 2 additions & 0 deletions gcc/testsuite/rust/compile/torture/issue-1075.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ union Repr<T> {
raw: FatPtr<T>,
}

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

#[lang = "const_ptr"]
impl<T> *const T {
pub const unsafe fn offset(self, count: isize) -> *const T {
unsafe { offset(self, count) }
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/torture/issue-1432.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/execute/torture/issue-1436.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ trait Index<Idx> {
fn index(&self, index: Idx) -> &Self::Output;
}

#[lang = "slice"]
impl<T> [T] {
pub const fn is_empty(&self) -> bool {
self.len() == 0
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/execute/torture/issue-2236.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod core {
}
}

#[lang = "i32"]
impl i32 {
fn max(self, other: i32) -> i32 {
if self > other {
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/execute/torture/iter1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions gcc/testsuite/rust/execute/torture/str-layout1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ pub union Repr<T> {
raw: FatPtr<T>,
}

#[lang = "slice"]
impl<T> [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()
Expand Down

0 comments on commit 638befc

Please sign in to comment.