Skip to content

Commit 3a9bf45

Browse files
committed
Check that #[may_dangle] is properly applied
It's only valid when applied to a type or lifetime parameter in `Drop` trait implementation.
1 parent 7521bda commit 3a9bf45

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

compiler/rustc_passes/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ passes_macro_export_on_decl_macro =
444444
passes_macro_use =
445445
`#[{$name}]` only has an effect on `extern crate` and modules
446446
447+
passes_may_dangle =
448+
`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
449+
447450
passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
448451
passes_missing_const_err =
449452
attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`

compiler/rustc_passes/src/check_attr.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
189189
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
190190
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
191191
[sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
192+
[sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr),
192193
[sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
193194
[sym::rustc_allow_incoherent_impl, ..] => {
194195
self.check_allow_incoherent_impl(attr, span, target)
@@ -255,7 +256,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
255256
| sym::cfg_attr
256257
// need to be fixed
257258
| sym::cfi_encoding // FIXME(cfi_encoding)
258-
| sym::may_dangle // FIXME(dropck_eyepatch)
259259
| sym::pointee // FIXME(derive_smart_pointer)
260260
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
261261
| sym::used // handled elsewhere to restrict to static items
@@ -1373,6 +1373,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13731373
}
13741374
}
13751375

1376+
/// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl.
1377+
fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) {
1378+
if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1379+
&& matches!(
1380+
param.kind,
1381+
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }
1382+
)
1383+
&& matches!(param.source, hir::GenericParamSource::Generics)
1384+
&& let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1385+
&& let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1386+
&& let hir::ItemKind::Impl(impl_) = item.kind
1387+
&& let Some(trait_) = impl_.of_trait
1388+
&& let Some(def_id) = trait_.trait_def_id()
1389+
&& self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1390+
{
1391+
return;
1392+
}
1393+
1394+
self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span });
1395+
}
1396+
13761397
/// Checks if `#[cold]` is applied to a non-function.
13771398
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
13781399
match target {

compiler/rustc_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,13 @@ pub struct NonExportedMacroInvalidAttrs {
737737
pub attr_span: Span,
738738
}
739739

740+
#[derive(Diagnostic)]
741+
#[diag(passes_may_dangle)]
742+
pub struct InvalidMayDangle {
743+
#[primary_span]
744+
pub attr_span: Span,
745+
}
746+
740747
#[derive(LintDiagnostic)]
741748
#[diag(passes_unused_duplicate)]
742749
pub struct UnusedDuplicate {

tests/ui/attributes/may_dangle.rs

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#![feature(dropck_eyepatch)]
2+
3+
struct Implee1<'a, T, const N: usize>(&'a T);
4+
struct Implee2<'a, T, const N: usize>(&'a T);
5+
struct Implee3<'a, T, const N: usize>(&'a T);
6+
trait NotDrop {}
7+
8+
unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {}
9+
//~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
10+
11+
unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {}
12+
//~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
13+
14+
unsafe impl<'a, T, #[may_dangle] const N: usize> Drop for Implee1<'a, T, N> {
15+
//~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
16+
fn drop(&mut self) {}
17+
}
18+
19+
// Ok, lifetime param in a `Drop` impl.
20+
unsafe impl<#[may_dangle] 'a, T, const N: usize> Drop for Implee2<'a, T, N> {
21+
fn drop(&mut self) {}
22+
}
23+
24+
// Ok, type param in a `Drop` impl.
25+
unsafe impl<'a, #[may_dangle] T, const N: usize> Drop for Implee3<'a, T, N> {
26+
fn drop(&mut self) {}
27+
}
28+
29+
// Check that this check is not textual.
30+
mod fake {
31+
trait Drop {
32+
fn drop(&mut self);
33+
}
34+
struct Implee<T>(T);
35+
36+
unsafe impl<#[may_dangle] T> Drop for Implee<T> {
37+
//~^ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
38+
fn drop(&mut self) {}
39+
}
40+
}
41+
42+
#[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
43+
struct Dangling;
44+
45+
#[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
46+
impl NotDrop for () {
47+
}
48+
49+
#[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
50+
fn main() {
51+
#[may_dangle] //~ ERROR must be applied to a lifetime or type generic parameter in `Drop` impl
52+
let () = ();
53+
}

tests/ui/attributes/may_dangle.stderr

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
2+
--> $DIR/may_dangle.rs:8:13
3+
|
4+
LL | unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {}
5+
| ^^^^^^^^^^^^^
6+
7+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
8+
--> $DIR/may_dangle.rs:11:17
9+
|
10+
LL | unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {}
11+
| ^^^^^^^^^^^^^
12+
13+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
14+
--> $DIR/may_dangle.rs:14:20
15+
|
16+
LL | unsafe impl<'a, T, #[may_dangle] const N: usize> Drop for Implee1<'a, T, N> {
17+
| ^^^^^^^^^^^^^
18+
19+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
20+
--> $DIR/may_dangle.rs:42:1
21+
|
22+
LL | #[may_dangle]
23+
| ^^^^^^^^^^^^^
24+
25+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
26+
--> $DIR/may_dangle.rs:45:1
27+
|
28+
LL | #[may_dangle]
29+
| ^^^^^^^^^^^^^
30+
31+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
32+
--> $DIR/may_dangle.rs:49:1
33+
|
34+
LL | #[may_dangle]
35+
| ^^^^^^^^^^^^^
36+
37+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
38+
--> $DIR/may_dangle.rs:51:5
39+
|
40+
LL | #[may_dangle]
41+
| ^^^^^^^^^^^^^
42+
43+
error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
44+
--> $DIR/may_dangle.rs:36:17
45+
|
46+
LL | unsafe impl<#[may_dangle] T> Drop for Implee<T> {
47+
| ^^^^^^^^^^^^^
48+
49+
error: aborting due to 8 previous errors
50+

0 commit comments

Comments
 (0)