Skip to content

Commit 637a59d

Browse files
committed
unsafe impl
1 parent 55ef44b commit 637a59d

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
@@ -1882,7 +1882,13 @@ pub struct MacroDef {
18821882
/// `true` if macro was defined with `macro_rules`.
18831883
pub macro_rules: bool,
18841884

1885-
pub eii_macro_for: Option<Path>,
1885+
pub eii_macro_for: Option<EiiMacroFor>,
1886+
}
1887+
1888+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
1889+
pub struct EiiMacroFor {
1890+
pub extern_item_path: Path,
1891+
pub impl_unsafe: bool,
18861892
}
18871893

18881894
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@@ -3472,7 +3478,16 @@ pub struct Fn {
34723478
pub body: Option<P<Block>>,
34733479

34743480
/// This fn implements some EII, pointed to by the `path`
3475-
pub eii_impl: ThinVec<(NodeId, Path)>,
3481+
pub eii_impl: ThinVec<EIIImpl>,
3482+
}
3483+
3484+
#[derive(Clone, Encodable, Decodable, Debug)]
3485+
pub struct EIIImpl {
3486+
pub node_id: NodeId,
3487+
pub eii_macro_path: Path,
3488+
pub impl_safety: Safety,
3489+
pub span: Span,
3490+
pub inner_span: Span,
34763491
}
34773492

34783493
#[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
@@ -747,8 +747,8 @@ fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
747747

748748
fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
749749
let MacroDef { body, macro_rules: _, eii_macro_for } = macro_def;
750-
if let Some(path) = eii_macro_for {
751-
vis.visit_path(path);
750+
if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = eii_macro_for {
751+
vis.visit_path(extern_item_path);
752752
}
753753
visit_delim_args(vis, body);
754754
}
@@ -977,9 +977,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
977977
// Identifier and visibility are visited as a part of the item.
978978
visit_defaultness(vis, defaultness);
979979

980-
for (node_id, path) in eii_impl {
980+
for EIIImpl { node_id, eii_macro_path, .. } in eii_impl {
981981
vis.visit_id(node_id);
982-
vis.visit_path(path);
982+
vis.visit_path(eii_macro_path);
983983
}
984984
vis.visit_fn_header(header);
985985
vis.visit_generics(generics);

compiler/rustc_ast/src/visit.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,8 @@ impl WalkItemKind for ItemKind {
440440
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
441441
ItemKind::MacroDef(ts) => {
442442
try_visit!(visitor.visit_mac_def(ts, id));
443-
if let Some(i) = &ts.eii_macro_for {
444-
try_visit!(visitor.visit_path(i, id));
443+
if let Some(EiiMacroFor { extern_item_path, impl_unsafe: _ }) = &ts.eii_macro_for {
444+
try_visit!(visitor.visit_path(extern_item_path, id));
445445
}
446446
}
447447
ItemKind::Delegation(box Delegation {
@@ -908,8 +908,8 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
908908
) => {
909909
// Identifier and visibility are visited as a part of the item.
910910

911-
for (node_id, path) in eii_impl {
912-
try_visit!(visitor.visit_path(path, *node_id));
911+
for EIIImpl { node_id, eii_macro_path, .. } in eii_impl {
912+
try_visit!(visitor.visit_path(eii_macro_path, *node_id));
913913
}
914914

915915
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
@@ -162,18 +162,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
162162
) -> Vec<hir::Attribute> {
163163
match i {
164164
ItemKind::Fn(box Fn { eii_impl, .. }) => {
165-
let mut res = Vec::new();
166-
167-
for (id, path) in eii_impl {
168-
let did = self.lower_path_simple_eii(*id, path);
169-
res.push(hir::Attribute::Parsed(AttributeKind::EiiImpl { eii_macro: did }));
165+
let mut eii_impls = ThinVec::new();
166+
for EIIImpl { node_id, eii_macro_path, impl_safety, span, inner_span } in eii_impl {
167+
let did = self.lower_path_simple_eii(*node_id, eii_macro_path);
168+
eii_impls.push(rustc_attr_parsing::EIIImpl {
169+
eii_macro: did,
170+
span: self.lower_span(*span),
171+
inner_span: self.lower_span(*inner_span),
172+
impl_marked_unsafe: self
173+
.lower_safety(*impl_safety, hir::Safety::Safe)
174+
.is_unsafe(),
175+
})
170176
}
171177

172-
res
178+
vec![hir::Attribute::Parsed(AttributeKind::EiiImpl(eii_impls))]
173179
}
174-
ItemKind::MacroDef(MacroDef { eii_macro_for: Some(path), .. }) => {
180+
ItemKind::MacroDef(MacroDef {
181+
eii_macro_for: Some(EiiMacroFor { extern_item_path, impl_unsafe }),
182+
..
183+
}) => {
175184
vec![hir::Attribute::Parsed(AttributeKind::EiiMacroFor {
176-
eii_extern_item: self.lower_path_simple_eii(id, path),
185+
eii_extern_item: self.lower_path_simple_eii(id, extern_item_path),
186+
impl_unsafe: *impl_unsafe,
177187
})]
178188
}
179189
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;
@@ -660,9 +659,16 @@ impl<'a> State<'a> {
660659
}
661660
}
662661

663-
for (_, path) in eii_impl {
662+
for EIIImpl { eii_macro_path, impl_safety, .. } in eii_impl {
664663
self.word("#[");
665-
self.print_path(path, false, 0);
664+
if let Safety::Unsafe(..) = impl_safety {
665+
self.word("unsafe");
666+
self.popen();
667+
}
668+
self.print_path(eii_macro_path, false, 0);
669+
if let Safety::Unsafe(..) = impl_safety {
670+
self.pclose();
671+
}
666672
self.word("]");
667673
self.hardbreak();
668674
}

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_type_ir::solve::NoSolution;
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};
@@ -1296,14 +1296,16 @@ fn check_item_fn(
12961296
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
12971297
// does the function have an EiiImpl attribute? that contains the defid of a *macro*
12981298
// that was used to mark the implementation. This is a two step process.
1299-
if let Some(eii_macro) =
1300-
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl {eii_macro} => *eii_macro)
1299+
for EIIImpl { eii_macro, .. } in
1300+
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::EiiImpl(impls) => impls)
1301+
.into_iter()
1302+
.flatten()
13011303
{
13021304
// we expect this macro to have the `EiiMacroFor` attribute, that points to a function
13031305
// signature that we'd like to compare the function we're currently checking with
1304-
if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(eii_macro), AttributeKind::EiiMacroFor {eii_extern_item} => *eii_extern_item)
1306+
if let Some(eii_extern_item) = find_attr!(tcx.get_all_attrs(*eii_macro), AttributeKind::EiiMacroFor {eii_extern_item, ..} => *eii_extern_item)
13051307
{
1306-
let _ = compare_eii_predicate_entailment(tcx, def_id, eii_extern_item);
1308+
let _ = compare_eii_function_types(tcx, def_id, eii_extern_item);
13071309
} else {
13081310
panic!(
13091311
"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)