@@ -87,6 +87,9 @@ struct AstValidator<'a> {
87
87
/// or `Foo::Bar<impl Trait>`
88
88
is_impl_trait_banned : bool ,
89
89
90
+ /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
91
+ extern_mod_safety : Option < Safety > ,
92
+
90
93
lint_buffer : & ' a mut LintBuffer ,
91
94
}
92
95
@@ -117,6 +120,12 @@ impl<'a> AstValidator<'a> {
117
120
self . outer_trait_or_trait_impl = old;
118
121
}
119
122
123
+ fn with_in_extern_mod ( & mut self , extern_mod_safety : Safety , f : impl FnOnce ( & mut Self ) ) {
124
+ let old = mem:: replace ( & mut self . extern_mod_safety , Some ( extern_mod_safety) ) ;
125
+ f ( self ) ;
126
+ self . extern_mod_safety = old;
127
+ }
128
+
120
129
fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
121
130
let old = mem:: replace ( & mut self . is_impl_trait_banned , true ) ;
122
131
f ( self ) ;
@@ -430,6 +439,20 @@ impl<'a> AstValidator<'a> {
430
439
}
431
440
}
432
441
442
+ fn check_foreign_item_safety ( & self , item_span : Span , safety : Safety ) {
443
+ match safety {
444
+ Safety :: Unsafe ( _) | Safety :: Safe ( _)
445
+ if self . extern_mod_safety == Some ( Safety :: Default ) =>
446
+ {
447
+ self . dcx ( ) . emit_err ( errors:: InvalidSafetyOnExtern {
448
+ item_span,
449
+ block : self . current_extern_span ( ) ,
450
+ } ) ;
451
+ }
452
+ _ => { }
453
+ }
454
+ }
455
+
433
456
fn check_defaultness ( & self , span : Span , defaultness : Defaultness ) {
434
457
if let Defaultness :: Default ( def_span) = defaultness {
435
458
let span = self . session . source_map ( ) . guess_head_span ( span) ;
@@ -1014,26 +1037,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1014
1037
return ; // Avoid visiting again.
1015
1038
}
1016
1039
ItemKind :: ForeignMod ( ForeignMod { abi, safety, .. } ) => {
1017
- let old_item = mem:: replace ( & mut self . extern_mod , Some ( item) ) ;
1018
- self . visibility_not_permitted (
1019
- & item. vis ,
1020
- errors:: VisibilityNotPermittedNote :: IndividualForeignItems ,
1021
- ) ;
1022
-
1023
- if & Safety :: Default == safety {
1024
- self . lint_buffer . buffer_lint (
1025
- MISSING_UNSAFE_ON_EXTERN ,
1026
- item. id ,
1027
- item. span ,
1028
- BuiltinLintDiag :: MissingUnsafeOnExtern ,
1040
+ self . with_in_extern_mod ( * safety, |this| {
1041
+ let old_item = mem:: replace ( & mut this. extern_mod , Some ( item) ) ;
1042
+ this. visibility_not_permitted (
1043
+ & item. vis ,
1044
+ errors:: VisibilityNotPermittedNote :: IndividualForeignItems ,
1029
1045
) ;
1030
- }
1031
1046
1032
- if abi. is_none ( ) {
1033
- self . maybe_lint_missing_abi ( item. span , item. id ) ;
1034
- }
1035
- visit:: walk_item ( self , item) ;
1036
- self . extern_mod = old_item;
1047
+ if & Safety :: Default == safety {
1048
+ this. lint_buffer . buffer_lint (
1049
+ MISSING_UNSAFE_ON_EXTERN ,
1050
+ item. id ,
1051
+ item. span ,
1052
+ BuiltinLintDiag :: MissingUnsafeOnExtern ,
1053
+ ) ;
1054
+ }
1055
+
1056
+ if abi. is_none ( ) {
1057
+ this. maybe_lint_missing_abi ( item. span , item. id ) ;
1058
+ }
1059
+ visit:: walk_item ( this, item) ;
1060
+ this. extern_mod = old_item;
1061
+ } ) ;
1037
1062
return ; // Avoid visiting again.
1038
1063
}
1039
1064
ItemKind :: Enum ( def, _) => {
@@ -1165,6 +1190,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1165
1190
fn visit_foreign_item ( & mut self , fi : & ' a ForeignItem ) {
1166
1191
match & fi. kind {
1167
1192
ForeignItemKind :: Fn ( box Fn { defaultness, sig, body, .. } ) => {
1193
+ self . check_foreign_item_safety ( fi. span , sig. header . safety ) ;
1168
1194
self . check_defaultness ( fi. span , * defaultness) ;
1169
1195
self . check_foreign_fn_bodyless ( fi. ident , body. as_deref ( ) ) ;
1170
1196
self . check_foreign_fn_headerless ( sig. header ) ;
@@ -1184,7 +1210,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
1184
1210
self . check_foreign_ty_genericless ( generics, where_clauses) ;
1185
1211
self . check_foreign_item_ascii_only ( fi. ident ) ;
1186
1212
}
1187
- ForeignItemKind :: Static ( box StaticForeignItem { expr, .. } ) => {
1213
+ ForeignItemKind :: Static ( box StaticForeignItem { expr, safety, .. } ) => {
1214
+ self . check_foreign_item_safety ( fi. span , * safety) ;
1188
1215
self . check_foreign_kind_bodyless ( fi. ident , "static" , expr. as_ref ( ) . map ( |b| b. span ) ) ;
1189
1216
self . check_foreign_item_ascii_only ( fi. ident ) ;
1190
1217
}
@@ -1740,6 +1767,7 @@ pub fn check_crate(
1740
1767
outer_impl_trait : None ,
1741
1768
disallow_tilde_const : Some ( DisallowTildeConstContext :: Item ) ,
1742
1769
is_impl_trait_banned : false ,
1770
+ extern_mod_safety : None ,
1743
1771
lint_buffer : lints,
1744
1772
} ;
1745
1773
visit:: walk_crate ( & mut validator, krate) ;
0 commit comments