Skip to content

Commit 06fa6c2

Browse files
committed
unsafe impl
1 parent c27433a commit 06fa6c2

File tree

13 files changed

+178
-52
lines changed

13 files changed

+178
-52
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,7 +1874,13 @@ pub struct MacroDef {
18741874
/// `true` if macro was defined with `macro_rules`.
18751875
pub macro_rules: bool,
18761876

1877-
pub eii_macro_for: Option<Path>,
1877+
pub eii_macro_for: Option<EiiMacroFor>,
1878+
}
1879+
1880+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
1881+
pub struct EiiMacroFor {
1882+
pub extern_item_path: Path,
1883+
pub impl_unsafe: bool,
18781884
}
18791885

18801886
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@@ -3502,7 +3508,16 @@ pub struct Fn {
35023508
pub body: Option<P<Block>>,
35033509

35043510
/// This fn implements some EII, pointed to by the `path`
3505-
pub eii_impl: ThinVec<(NodeId, Path)>,
3511+
pub eii_impl: ThinVec<EIIImpl>,
3512+
}
3513+
3514+
#[derive(Clone, Encodable, Decodable, Debug)]
3515+
pub struct EIIImpl {
3516+
pub node_id: NodeId,
3517+
pub eii_macro_path: Path,
3518+
pub impl_safety: Safety,
3519+
pub span: Span,
3520+
pub inner_span: Span,
35063521
}
35073522

35083523
#[derive(Clone, Encodable, Decodable, Debug)]

compiler/rustc_ast/src/mut_visit.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,8 @@ fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
751751

752752
fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
753753
let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def;
754-
if let Some(path) = eii_macro_for {
755-
vis.visit_path(path);
754+
if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for {
755+
vis.visit_path(extern_item_path);
756756
}
757757
visit_delim_args(vis, body);
758758
}
@@ -981,9 +981,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
981981
// Identifier and visibility are visited as a part of the item.
982982
visit_defaultness(vis, defaultness);
983983

984-
for (node_id, path) in eii_impl {
984+
for EIIImpl { node_id, eii_macro_path, .. } in eii_impl {
985985
vis.visit_id(node_id);
986-
vis.visit_path(path);
986+
vis.visit_path(eii_macro_path);
987987
}
988988
vis.visit_fn_header(header);
989989
vis.visit_generics(generics);

compiler/rustc_ast/src/visit.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ impl WalkItemKind for ItemKind {
460460
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
461461
ItemKind::MacroDef(ts) => {
462462
try_visit!(visitor.visit_mac_def(ts, id));
463-
if let Some(i) = &ts.eii_macro_for {
464-
try_visit!(visitor.visit_path(i, id));
463+
if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for {
464+
try_visit!(visitor.visit_path(extern_item_path, id));
465465
}
466466
}
467467
ItemKind::Delegation(box Delegation {
@@ -935,8 +935,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
935935
) => {
936936
// Identifier and visibility are visited as a part of the item.
937937

938-
for (node_id, path) in eii_impl {
939-
try_visit!(visitor.visit_path(path, *node_id));
938+
for EIIImpl { node_id, eii_macro_path, .. } in eii_impl {
939+
try_visit!(visitor.visit_path(eii_macro_path, *node_id));
940940
}
941941

942942
try_visit!(visitor.visit_fn_header(header));

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,18 +156,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
156156
) -> Vec<hir::Attribute> {
157157
match i {
158158
ItemKind::Fn(box Fn { eii_impl, .. }) => {
159-
let mut res = Vec::new();
160-
161-
for (id, path) in eii_impl {
162-
let did = self.lower_path_simple_eii(*id, path);
163-
res.push(hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did }));
159+
let mut eii_impls = ThinVec::new();
160+
for EIIImpl { node_id, eii_macro_path, impl_safety, span, inner_span } in eii_impl {
161+
let did = self.lower_path_simple_eii(*node_id, eii_macro_path);
162+
eii_impls.push(rustc_attr_parsing::EIIImpl {
163+
eii_macro: did,
164+
span: self.lower_span(*span),
165+
inner_span: self.lower_span(*inner_span),
166+
impl_marked_unsafe: self
167+
.lower_safety(*impl_safety, hir::Safety::Safe)
168+
.is_unsafe(),
169+
})
164170
}
165171

166-
res
172+
vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(eii_impls))]
167173
}
168-
ItemKind::MacroDef(MacroDef { eii_macro_for: Some(path), .. }) => {
174+
ItemKind::MacroDef(MacroDef {
175+
eii_macro_for: Some(EiiMacroFor { extern_item_path, impl_unsafe }),
176+
..
177+
}) => {
169178
vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor {
170-
eii_extern_item: self.lower_path_simple_eii(id, path),
179+
eii_extern_item: self.lower_path_simple_eii(id, extern_item_path),
180+
impl_unsafe: *impl_unsafe,
171181
})]
172182
}
173183
ItemKind::ExternCrate(..)

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
930930
) => {
931931
self.check_defaultness(item.span, *defaultness);
932932

933-
for (id, path) in eii_impl {
934-
self.visit_path(path, *id);
933+
for EIIImpl { node_id, eii_macro_path, .. } in eii_impl {
934+
self.visit_path(eii_macro_path, *node_id);
935935
}
936936

937937
let is_intrinsic =

compiler/rustc_ast_pretty/src/pprust/state/item.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use ast::StaticItem;
22
use itertools::{Itertools, Position};
3-
use rustc_ast as ast;
4-
use rustc_ast::ModKind;
53
use rustc_ast::ptr::P;
4+
use rustc_ast::{self as ast, EIIImpl, ModKind, Safety};
65
use rustc_span::Ident;
76

87
use crate::pp::Breaks::Inconsistent;
@@ -682,9 +681,16 @@ impl<'a> State<'a> {
682681

683682
self.print_define_opaques(define_opaque.as_deref());
684683

685-
for (_, path) in eii_impl {
684+
for EIIImpl { eii_macro_path, impl_safety, .. } in eii_impl {
686685
self.word("#[");
687-
self.print_path(path, false, 0);
686+
if let Safety::Unsafe(..) = impl_safety {
687+
self.word("unsafe");
688+
self.popen();
689+
}
690+
self.print_path(eii_macro_path, false, 0);
691+
if let Safety::Unsafe(..) = impl_safety {
692+
self.pclose();
693+
}
688694
self.word("]");
689695
self.hardbreak();
690696
}

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ impl Deprecation {
139139
}
140140
}
141141

142+
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
143+
pub struct EIIImpl {
144+
pub eii_macro: DefId,
145+
pub impl_marked_unsafe: bool,
146+
pub span: Span,
147+
pub inner_span: Span,
148+
}
149+
142150
/// Represent parsed, *built in*, inert attributes.
143151
///
144152
/// That means attributes that are not actually ever expanded.
@@ -190,12 +198,11 @@ pub enum AttributeKind {
190198
span: Span,
191199
comment: Symbol,
192200
},
193-
Eii(Span),
194-
EiiImpl {
195-
eii_macro: DefId,
196-
},
201+
EiiImpl(ThinVec<EIIImpl>),
197202
EiiMacroFor {
198203
eii_extern_item: DefId,
204+
/// whether or not it is unsafe to implement this EII
205+
impl_unsafe: bool,
199206
},
200207
MacroTransparency(Transparency),
201208
Repr(ThinVec<(ReprAttr, Span)>),

compiler/rustc_builtin_macros/src/eii.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use rustc_ast::{DUMMY_NODE_ID, ItemKind, ast};
1+
use rustc_ast::{DUMMY_NODE_ID, EIIImpl, EiiMacroFor, ItemKind, ast};
22
use rustc_expand::base::{Annotatable, ExtCtxt};
3-
use rustc_span::Span;
3+
use rustc_span::{Span, Span, kw};
44

55
pub(crate) fn eii_macro_for(
66
ecx: &mut ExtCtxt<'_>,
@@ -13,7 +13,22 @@ pub(crate) fn eii_macro_for(
1313

1414
let Some(list) = meta_item.meta_item_list() else { panic!("expected list") };
1515

16-
d.eii_macro_for = Some(list[0].meta_item().unwrap().path.clone());
16+
let Some(extern_item_path) = list.get(0).and_then(|i| i.meta_item()).map(|i| i.path.clone())
17+
else {
18+
panic!("expected a path to an `extern` item");
19+
};
20+
21+
let impl_unsafe = if let Some(i) = list.get(1) {
22+
if i.lit().and_then(|i| i.kind.str()).is_some_and(|i| i == kw::Unsafe) {
23+
true
24+
} else {
25+
panic!("expected the string `\"unsafe\"` here or no other arguments");
26+
}
27+
} else {
28+
false
29+
};
30+
31+
d.eii_macro_for = Some(EiiMacroFor { extern_item_path, impl_unsafe });
1732

1833
// Return the original item and the new methods.
1934
vec![item]
@@ -31,7 +46,14 @@ pub(crate) fn eii_macro(
3146

3247
assert!(meta_item.is_word());
3348

34-
f.eii_impl.push((DUMMY_NODE_ID, meta_item.path.clone()));
49+
f.eii_impl.push(EIIImpl {
50+
node_id: DUMMY_NODE_ID,
51+
eii_macro_path: meta_item.path.clone(),
52+
impl_safety: meta_item.unsafety,
53+
span,
54+
inner_span: meta_item.span,
55+
is_default: false,
56+
});
3557

3658
vec![item]
3759
}

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::{ControlFlow, Deref};
33

44
use hir::intravisit::{self, Visitor};
55
use rustc_abi::ExternAbi;
6-
use rustc_attr_parsing::{AttributeKind, find_attr};
6+
use rustc_attr_parsing::{AttributeKind, EIIImpl, find_attr};
77
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
88
use rustc_errors::codes::*;
99
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
@@ -40,7 +40,7 @@ use rustc_trait_selection::traits::{
4040
use tracing::{debug, instrument};
4141
use {rustc_ast as ast, rustc_hir as hir};
4242

43-
use super::compare_eii::compare_eii_predicate_entailment;
43+
use super::compare_eii::{compare_eii_function_types, compare_eii_predicate_entailment};
4444
use crate::autoderef::Autoderef;
4545
use crate::collect::CollectItemTypesVisitor;
4646
use crate::constrained_generic_params::{Parameter, identify_constrained_generic_params};
@@ -1298,14 +1298,16 @@ fn check_item_fn(
12981298
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
12991299
// does the function have an EiiImpl attribute? that contains the defid of a *macro*
13001300
// that was used to mark the implementation. This is a two step process.
1301-
if let Some(eii_macro) =
1302-
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl {eii_macro} => *eii_macro)
1301+
for EIIImpl { eii_macro, .. } in
1302+
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl(impls) => impls)
1303+
.into_iter()
1304+
.flatten()
13031305
{
13041306
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
13051307
// signature that we'd like to compare the function we're currently checking with
1306-
if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(eii_macro), AttributeKind::EiiMacroFor {eii_extern_item} => *eii_extern_item)
1308+
if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor {eii_extern_item, ..} => *eii_extern_item)
13071309
{
1308-
let _ = compare_eii_predicate_entailment(tcx, def_id, eii_extern_item);
1310+
let _ = compare_eii_function_types(tcx, def_id, eii_extern_item);
13091311
} else {
13101312
panic!(
13111313
"EII impl macro {eii_macro:?} did not have an eii macro for attribute pointing to a function"

compiler/rustc_passes/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ passes_duplicate_lang_item_crate_depends =
311311
.first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
312312
.second_definition_path = second definition in `{$crate_name}` loaded from {$path}
313313
314+
passes_eii_impl_not_function =
315+
`eii_macro_for` is only valid on functions
316+
317+
passes_eii_impl_requires_unsafe =
318+
`#[{$name}]` is unsafe to implement
319+
passes_eii_impl_requires_unsafe_suggestion = wrap the attribute in `unsafe(...)`
314320
passes_export_name =
315321
attribute should be applied to a free function, impl method or static
316322
.label = not a free function, impl method or static

0 commit comments

Comments
 (0)