Skip to content

Commit f1febc1

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 f1febc1

File tree

5 files changed

+136
-4
lines changed

5 files changed

+136
-4
lines changed

compiler/rustc_passes/messages.ftl

+5-2
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,8 @@ passes_multiple_start_functions =
475475
.previous = previous `#[start]` function here
476476
477477
passes_must_not_suspend =
478-
`must_not_suspend` attribute should be applied to a struct, enum, or trait
479-
.label = is not a struct, enum, or trait
478+
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
479+
.label = is not a struct, enum, union, or trait
480480
481481
passes_must_use_async =
482482
`must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
@@ -542,6 +542,9 @@ passes_non_exported_macro_invalid_attrs =
542542
attribute should be applied to function or closure
543543
.label = not a function or closure
544544
545+
passes_may_dangle =
546+
`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
547+
545548
passes_object_lifetime_err =
546549
{$repr}
547550

compiler/rustc_passes/src/check_attr.rs

+21-2
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, target),
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
@@ -1363,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13631363
}
13641364
}
13651365

1366-
/// Checks if `#[must_not_suspend]` is applied to a function.
1366+
/// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.
13671367
fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
13681368
match target {
13691369
Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
@@ -1373,6 +1373,25 @@ 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, target: Target) {
1378+
if matches!(target, Target::GenericParam(_))
1379+
&& let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1380+
&& matches!(param.kind, hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. })
1381+
&& matches!(param.source, hir::GenericParamSource::Generics)
1382+
&& let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1383+
&& let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1384+
&& let hir::ItemKind::Impl(impl_) = item.kind
1385+
&& let Some(trait_) = impl_.of_trait
1386+
&& let Some(def_id) = trait_.trait_def_id()
1387+
&& self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1388+
{
1389+
return;
1390+
}
1391+
1392+
self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span });
1393+
}
1394+
13761395
/// Checks if `#[cold]` is applied to a non-function.
13771396
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
13781397
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)