Skip to content

Commit 6e0c9bc

Browse files
committed
Handle Drop Error Codes
added some utilites to catch drop related error codes. gcc/rust/ChangeLog: * Make-lang.in: add rust-drop-check.h * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): drop call error * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): union&trait errors * typecheck/rust-hir-type-check.h: peek_trait_impl_map * typecheck/rust-typecheck-context.cc (TypeCheckContext::insert_associated_impl_mapping): peek_trait_impl_map * util/rust-lang-item.cc: add Drop * util/rust-lang-item.h: add Drop * typecheck/rust-drop-check.cc: handle drop logic. * typecheck/rust-drop-check.h: handle drop logic. gcc/testsuite/ChangeLog: * rust/compile/dropck-e0040-direct-drop.rs: New test. * rust/compile/dropck-e0184-copy-drop.rs: New test. * rust/compile/dropck-e0740-union.rs: New test. Signed-off-by: Islam-Imad <islamimad404@gmail.com>
1 parent 4b53420 commit 6e0c9bc

12 files changed

Lines changed: 362 additions & 0 deletions

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ GRS_OBJS = \
194194
rust/rust-hir-generic-param.o \
195195
rust/rust-type-util.o \
196196
rust/rust-coercion.o \
197+
rust/rust-drop-check.o \
197198
rust/rust-casts.o \
198199
rust/rust-unify.o \
199200
rust/rust-hir-type-check-base.o \
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
// Copyright (C) 2026 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+
19+
#include "rust-drop-check.h"
20+
#include "rust-diagnostics.h"
21+
#include "rust-lang-item.h"
22+
#include "rust-hir-type-check.h"
23+
#include "optional.h"
24+
#include "rust-mapping-common.h"
25+
#include "rust-tyty.h"
26+
27+
namespace Rust {
28+
namespace DropCheck {
29+
30+
tl::optional<HirId>
31+
DropChecker::get_trait_hirid (LangItem::Kind lang_kind)
32+
{
33+
auto &mappings = Analysis::Mappings::get ();
34+
auto opt_trait = mappings.lookup_lang_item_node (lang_kind);
35+
if (!opt_trait.has_value ())
36+
return tl::nullopt;
37+
return mappings.lookup_node_to_hir (opt_trait.value ());
38+
}
39+
40+
tl::optional<HirId>
41+
DropChecker::get_drop_hirid ()
42+
{
43+
return get_trait_hirid (LangItem::Kind::DROP);
44+
}
45+
46+
tl::optional<HirId>
47+
DropChecker::get_copy_hirid ()
48+
{
49+
return get_trait_hirid (LangItem::Kind::COPY);
50+
}
51+
52+
bool
53+
DropChecker::is_manually_drop (const TyTy::BaseType *ty)
54+
{
55+
auto &mappings = Analysis::Mappings::get ();
56+
auto manually_drop
57+
= mappings.lookup_lang_item (LangItem::Kind::MANUALLY_DROP);
58+
if (!manually_drop.has_value ())
59+
return false;
60+
return ty->as<const TyTy::ADTType> ()->get_id () == manually_drop.value ();
61+
}
62+
63+
tl::optional<HirId>
64+
DropChecker::impl_trait (const TyTy::BaseType *ty, HirId TraitHirId)
65+
{
66+
TyTy::BaseType *orig = nullptr;
67+
auto tyctx = Resolver::TypeCheckContext::get ();
68+
if (!tyctx->lookup_type (ty->get_ref (), &orig))
69+
return tl::nullopt;
70+
71+
std::vector<std::pair<TyTy::BaseType *, HirId>> impl_map;
72+
if (!tyctx->peek_associated_impl_mapping_for_self (TraitHirId, &impl_map))
73+
return tl::nullopt;
74+
75+
if (orig->get_kind () != TyTy::TypeKind::ADT)
76+
return tl::nullopt;
77+
78+
auto orig_adt = orig->as<TyTy::ADTType> ();
79+
for (auto &entry : impl_map)
80+
{
81+
auto RustType = entry.first;
82+
auto ImplBlockHirId = entry.second;
83+
84+
if (RustType->get_kind () != TyTy::TypeKind::ADT)
85+
continue;
86+
87+
if (orig_adt->get_id () == RustType->as<TyTy::ADTType> ()->get_id ())
88+
return ImplBlockHirId;
89+
}
90+
return tl::nullopt;
91+
}
92+
93+
tl::optional<HirId>
94+
DropChecker::impl_drop (const TyTy::BaseType *ty)
95+
{
96+
auto opt_hirid = get_drop_hirid ();
97+
if (!opt_hirid.has_value ())
98+
return tl::nullopt;
99+
return impl_trait (ty, opt_hirid.value ());
100+
}
101+
tl::optional<HirId>
102+
DropChecker::impl_copy (const TyTy::BaseType *ty)
103+
{
104+
auto opt_hirid = get_copy_hirid ();
105+
if (!opt_hirid.has_value ())
106+
return tl::nullopt;
107+
return impl_trait (ty, opt_hirid.value ());
108+
}
109+
110+
bool
111+
DropChecker::needs_drop (const TyTy::BaseType *ty)
112+
{
113+
// TODO : handle remaining types
114+
if (is_manually_drop (ty))
115+
return false;
116+
117+
if (impl_drop (ty).has_value ())
118+
return true;
119+
120+
switch (ty->get_kind ())
121+
{
122+
case TyTy::ADT:
123+
{
124+
auto adt_type = ty->as<const TyTy::ADTType> ();
125+
for (auto variant : adt_type->get_variants ())
126+
for (auto field : variant->get_fields ())
127+
if (needs_drop (field->get_field_type ()))
128+
return true;
129+
return false;
130+
}
131+
case TyTy::TUPLE:
132+
{
133+
auto tuple_type = ty->as<const TyTy::TupleType> ();
134+
for (auto &field : tuple_type->get_fields ())
135+
if (needs_drop (field.get_tyty ()))
136+
return true;
137+
return false;
138+
}
139+
case TyTy::ARRAY:
140+
return needs_drop (ty->as<const TyTy::ArrayType> ()->get_element_type ());
141+
default:
142+
return false;
143+
}
144+
}
145+
146+
void
147+
DropChecker::check_copy_drop (const TyTy::BaseType *ty, HirId trait_hirid,
148+
location_t locus)
149+
{
150+
bool is_e0184 = false;
151+
is_e0184 |= (trait_hirid == get_copy_hirid () && impl_drop (ty).has_value ());
152+
is_e0184 |= (trait_hirid == get_drop_hirid () && impl_copy (ty).has_value ());
153+
if (is_e0184)
154+
rust_error_at (
155+
locus, ErrorCode::E0184,
156+
"the trait Copy cannot be implemented for type that has a destructor");
157+
}
158+
159+
void
160+
DropChecker::check_union (const TyTy::BaseType *ty)
161+
{
162+
if (ty->get_kind () != TyTy::ADT)
163+
return;
164+
auto adt_type = ty->as<const TyTy::ADTType> ();
165+
if (adt_type->is_union ())
166+
{
167+
for (auto variant : adt_type->get_variants ())
168+
for (auto field : variant->get_fields ())
169+
if (needs_drop (field->get_field_type ()))
170+
{
171+
rust_error_at (field->get_locus (), ErrorCode::E0740,
172+
"field must implement Copy or be wrapped in "
173+
"ManuallyDrop to be used in a union");
174+
}
175+
}
176+
}
177+
178+
void
179+
DropChecker::check_drop_call (HirId trait_hirid, location_t locus)
180+
{
181+
if (trait_hirid == get_drop_hirid ())
182+
{
183+
rust_error_at (locus, ErrorCode::E0040,
184+
"explicit use of destructor method");
185+
}
186+
}
187+
188+
} // namespace DropCheck
189+
} // namespace Rust
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (C) 2026 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+
19+
#ifndef RUST_DROP_CHECK_H
20+
#define RUST_DROP_CHECK_H
21+
22+
#include "optional.h"
23+
#include "rust-mapping-common.h"
24+
#include "rust-tyty.h"
25+
#include "rust-hir-map.h"
26+
27+
namespace Rust {
28+
29+
class TypeCheckContext;
30+
31+
namespace DropCheck {
32+
33+
class DropChecker
34+
{
35+
public:
36+
static tl::optional<HirId> get_trait_hirid (LangItem::Kind lang_kind);
37+
static tl::optional<HirId> get_drop_hirid ();
38+
static tl::optional<HirId> get_copy_hirid ();
39+
40+
static tl::optional<HirId> impl_trait (const TyTy::BaseType *ty,
41+
HirId TraitHirId);
42+
static tl::optional<HirId> impl_drop (const TyTy::BaseType *ty);
43+
static tl::optional<HirId> impl_copy (const TyTy::BaseType *ty);
44+
45+
static bool needs_drop (const TyTy::BaseType *tyty);
46+
static bool is_manually_drop (const TyTy::BaseType *ty);
47+
48+
static void check_copy_drop (const TyTy::BaseType *self, HirId trait_hirid,
49+
location_t locus);
50+
static void check_union (const TyTy::BaseType *ty);
51+
static void check_drop_call (HirId trait_hirid, location_t locus);
52+
};
53+
54+
} // namespace DropCheck
55+
} // namespace Rust
56+
57+
#endif // RUST_DROP_CHECK_H

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "rust-tyty-util.h"
3737
#include "rust-tyty.h"
3838
#include "tree.h"
39+
#include "rust-drop-check.h"
3940

4041
namespace Rust {
4142
namespace Resolver {
@@ -1477,6 +1478,13 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
14771478
infer_arguments.get_mut_regions ()
14781479
= fn->get_used_arguments ().get_regions ();
14791480
HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
1481+
if (impl.has_trait_ref ())
1482+
{
1483+
HIR::TypePath &ref = impl.get_trait_ref ();
1484+
TraitReference *trait_reference = TraitResolver::Resolve (ref);
1485+
DropCheck::DropChecker::check_drop_call (
1486+
trait_reference->get_mappings ().get_hirid (), expr.get_locus ());
1487+
}
14801488
TyTy::BaseType *impl_self_infer
14811489
= TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
14821490
expr.get_locus (),

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "optional.h"
2121
#include "rust-canonical-path.h"
2222
#include "rust-diagnostics.h"
23+
#include "rust-drop-check.h"
2324
#include "rust-hir-item.h"
2425
#include "rust-hir-type-check-enumitem.h"
2526
#include "rust-hir-type-check-implitem.h"
@@ -434,6 +435,8 @@ TypeCheckItem::visit (HIR::Union &union_decl)
434435
context->insert_type (union_decl.get_mappings (), type);
435436
infered = type;
436437

438+
DropCheck::DropChecker::check_union (type);
439+
437440
context->get_variance_analysis_ctx ().add_type_constraints (*type);
438441
}
439442

@@ -869,6 +872,10 @@ TypeCheckItem::validate_trait_impl_block (
869872
context->insert_associated_impl_mapping (
870873
trait_reference->get_mappings ().get_hirid (), self,
871874
impl_block.get_mappings ().get_hirid ());
875+
876+
DropCheck::DropChecker::check_copy_drop (
877+
self, trait_reference->get_mappings ().get_hirid (),
878+
impl_block.get_trait_ref ().get_locus ());
872879
}
873880
}
874881

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ class TypeCheckContext
251251
void insert_associated_impl_mapping (HirId trait_id,
252252
TyTy::BaseType *impl_type,
253253
HirId impl_id);
254+
bool peek_associated_impl_mapping_for_self (
255+
HirId trait_id, std::vector<std::pair<TyTy::BaseType *, HirId>> *mappings);
254256
bool lookup_associated_impl_mapping_for_self (HirId trait_id,
255257
TyTy::BaseType *self,
256258
HirId *mapping);

gcc/rust/typecheck/rust-typecheck-context.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,20 @@ TypeCheckContext::insert_associated_impl_mapping (HirId trait_id,
317317
associated_traits_to_impls[trait_id].emplace_back (impl_type, impl_id);
318318
}
319319

320+
bool
321+
TypeCheckContext::peek_associated_impl_mapping_for_self (
322+
HirId trait_id, std::vector<std::pair<TyTy::BaseType *, HirId>> *mappings)
323+
{
324+
auto it = associated_traits_to_impls.find (trait_id);
325+
if (it == associated_traits_to_impls.end ())
326+
return false;
327+
328+
if (mappings != nullptr)
329+
*mappings = it->second;
330+
331+
return true;
332+
}
333+
320334
bool
321335
TypeCheckContext::lookup_associated_impl_mapping_for_self (HirId trait_id,
322336
TyTy::BaseType *self,

gcc/rust/util/rust-lang-item.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
119119
{"discriminant_kind", Kind::DISCRIMINANT_KIND},
120120
{"discriminant_type", Kind::DISCRIMINANT_TYPE},
121121
{"manually_drop", Kind::MANUALLY_DROP},
122+
{"drop", Kind::DROP},
122123
}};
123124

124125
tl::optional<LangItem::Kind>

gcc/rust/util/rust-lang-item.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class LangItem
155155
DISCRIMINANT_KIND,
156156

157157
MANUALLY_DROP,
158+
DROP,
158159
};
159160

160161
static const BiMap<std::string, Kind> lang_items;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(no_core)]
2+
#![feature(lang_items)]
3+
#![no_core]
4+
#[lang = "sized"]
5+
pub trait Sized {}
6+
#[lang = "copy"]
7+
pub trait Copy {}
8+
#[lang = "drop"]
9+
pub trait Drop {
10+
fn drop(&mut self);
11+
}
12+
13+
struct Foo {
14+
x: i32,
15+
}
16+
17+
impl Drop for Foo {
18+
fn drop(&mut self) {}
19+
}
20+
21+
fn main() {
22+
let mut x = Foo { x: -7 };
23+
x.drop(); // { dg-error "explicit use of destructor method .E0040." }
24+
}

0 commit comments

Comments
 (0)