Skip to content

Commit cfb656a

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

File tree

4 files changed

+58
-15
lines changed

4 files changed

+58
-15
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ 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+
ungated!(externally_constructed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
431432

432433
// Limits:
433434
ungated!(

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

+1
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ symbols! {
799799
extern_types,
800800
external,
801801
external_doc,
802+
externally_constructed,
802803
f,
803804
f128,
804805
f128_nan,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ check-pass
2+
3+
#[repr(C)]
4+
#[externally_constructed]
5+
pub struct Foo {
6+
pub i: i16,
7+
align: i16
8+
}
9+
10+
mod ffi {
11+
use super::*;
12+
13+
extern "C" {
14+
pub fn DomPromise_AddRef(promise: *const Promise);
15+
pub fn DomPromise_Release(promise: *const Promise);
16+
}
17+
}
18+
19+
#[repr(C)]
20+
#[externally_constructed]
21+
pub struct Promise {
22+
private: [u8; 0],
23+
__nosync: ::std::marker::PhantomData<::std::rc::Rc<u8>>,
24+
}
25+
26+
pub unsafe trait RefCounted {
27+
unsafe fn addref(&self);
28+
unsafe fn release(&self);
29+
}
30+
31+
unsafe impl RefCounted for Promise {
32+
unsafe fn addref(&self) {
33+
ffi::DomPromise_AddRef(self)
34+
}
35+
unsafe fn release(&self) {
36+
ffi::DomPromise_Release(self)
37+
}
38+
}
39+
40+
fn main() {}

0 commit comments

Comments
 (0)