Skip to content

Commit cca8d72

Browse files
committed
Add attr externally_constructed indicates pub struct with private fields could be constructed externally
1 parent 8cf5101 commit cca8d72

File tree

7 files changed

+87
-15
lines changed

7 files changed

+87
-15
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
428428
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
429429
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
430430
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
431+
gated!(
432+
externally_constructed, Normal, template!(Word), WarnFollowing,
433+
EncodeCrossCrate::Yes, externally_constructed_attr, experimental!(mark_externally_constructed)
434+
),
431435

432436
// Limits:
433437
ungated!(

compiler/rustc_feature/src/unstable.rs

+3
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,9 @@ declare_features! (
463463
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
464464
/// Allows defining `extern type`s.
465465
(unstable, extern_types, "1.23.0", Some(43467)),
466+
/// Allows `#[externally_constructed]` on pub structs with private fields,
467+
/// indicates they will be contructed externally during dead code analysis.
468+
(unstable, externally_constructed_attr, "CURRENT_RUSTC_VERSION", Some(126634)),
466469
/// Allow using 128-bit (quad precision) floating point numbers.
467470
(unstable, f128, "1.78.0", Some(116909)),
468471
/// Allow using 16-bit (half precision) floating point numbers.

compiler/rustc_passes/src/dead.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,22 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
5959
// treat PhantomData and positional ZST as public,
6060
// we don't want to lint types which only have them,
6161
// cause it's a common way to use such types to check things like well-formedness
62-
tcx.adt_def(id).all_fields().all(|field| {
63-
let field_type = tcx.type_of(field.did).instantiate_identity();
64-
if field_type.is_phantom_data() {
65-
return true;
66-
}
67-
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
68-
if is_positional
69-
&& tcx
70-
.layout_of(tcx.param_env(field.did).and(field_type))
71-
.map_or(true, |layout| layout.is_zst())
72-
{
73-
return true;
74-
}
75-
field.vis.is_public()
76-
})
62+
tcx.has_attr(id, sym::externally_constructed)
63+
|| tcx.adt_def(id).all_fields().all(|field| {
64+
let field_type = tcx.type_of(field.did).instantiate_identity();
65+
if field_type.is_phantom_data() {
66+
return true;
67+
}
68+
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
69+
if is_positional
70+
&& tcx
71+
.layout_of(tcx.param_env(field.did).and(field_type))
72+
.map_or(true, |layout| layout.is_zst())
73+
{
74+
return true;
75+
}
76+
field.vis.is_public()
77+
})
7778
}
7879

7980
/// check struct and its fields are public or not,

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,8 @@ symbols! {
799799
extern_types,
800800
external,
801801
external_doc,
802+
externally_constructed,
803+
externally_constructed_attr,
802804
f,
803805
f128,
804806
f128_nan,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//@ check-pass
2+
#![feature(externally_constructed_attr)]
3+
4+
#[repr(C)]
5+
#[externally_constructed]
6+
pub struct Foo {
7+
pub i: i16,
8+
align: i16
9+
}
10+
11+
mod ffi {
12+
use super::*;
13+
14+
extern "C" {
15+
pub fn DomPromise_AddRef(promise: *const Promise);
16+
pub fn DomPromise_Release(promise: *const Promise);
17+
}
18+
}
19+
20+
#[repr(C)]
21+
#[externally_constructed]
22+
pub struct Promise {
23+
private: [u8; 0],
24+
__nosync: ::std::marker::PhantomData<::std::rc::Rc<u8>>,
25+
}
26+
27+
pub unsafe trait RefCounted {
28+
unsafe fn addref(&self);
29+
unsafe fn release(&self);
30+
}
31+
32+
unsafe impl RefCounted for Promise {
33+
unsafe fn addref(&self) {
34+
ffi::DomPromise_AddRef(self)
35+
}
36+
unsafe fn release(&self) {
37+
ffi::DomPromise_Release(self)
38+
}
39+
}
40+
41+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#[repr(C)]
2+
#[externally_constructed] //~ ERROR the `#[mark_externally_constructed]` attribute is an experimental feature
3+
pub struct Foo {
4+
pub i: i16,
5+
align: i16
6+
}
7+
8+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0658]: the `#[mark_externally_constructed]` attribute is an experimental feature
2+
--> $DIR/feature-gate-externally_constructed_attr.rs:2:1
3+
|
4+
LL | #[externally_constructed]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #126634 <https://github.com/rust-lang/rust/issues/126634> for more information
8+
= help: add `#![feature(externally_constructed_attr)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: aborting due to 1 previous error
12+
13+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)