@@ -87,6 +87,9 @@ struct AstValidator<'a> {
8787 /// or `Foo::Bar<impl Trait>`
8888 is_impl_trait_banned : bool ,
8989
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+
9093 lint_buffer : & ' a mut LintBuffer ,
9194}
9295
@@ -117,6 +120,12 @@ impl<'a> AstValidator<'a> {
117120 self . outer_trait_or_trait_impl = old;
118121 }
119122
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+
120129 fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
121130 let old = mem:: replace ( & mut self . is_impl_trait_banned , true ) ;
122131 f ( self ) ;
@@ -430,6 +439,20 @@ impl<'a> AstValidator<'a> {
430439 }
431440 }
432441
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+
433456 fn check_defaultness ( & self , span : Span , defaultness : Defaultness ) {
434457 if let Defaultness :: Default ( def_span) = defaultness {
435458 let span = self . session . source_map ( ) . guess_head_span ( span) ;
@@ -1014,26 +1037,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
10141037 return ; // Avoid visiting again.
10151038 }
10161039 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 ,
10291045 ) ;
1030- }
10311046
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+ } ) ;
10371062 return ; // Avoid visiting again.
10381063 }
10391064 ItemKind :: Enum ( def, _) => {
@@ -1165,6 +1190,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11651190 fn visit_foreign_item ( & mut self , fi : & ' a ForeignItem ) {
11661191 match & fi. kind {
11671192 ForeignItemKind :: Fn ( box Fn { defaultness, sig, body, .. } ) => {
1193+ self . check_foreign_item_safety ( fi. span , sig. header . safety ) ;
11681194 self . check_defaultness ( fi. span , * defaultness) ;
11691195 self . check_foreign_fn_bodyless ( fi. ident , body. as_deref ( ) ) ;
11701196 self . check_foreign_fn_headerless ( sig. header ) ;
@@ -1184,7 +1210,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11841210 self . check_foreign_ty_genericless ( generics, where_clauses) ;
11851211 self . check_foreign_item_ascii_only ( fi. ident ) ;
11861212 }
1187- ForeignItemKind :: Static ( box StaticForeignItem { expr, .. } ) => {
1213+ ForeignItemKind :: Static ( box StaticForeignItem { expr, safety, .. } ) => {
1214+ self . check_foreign_item_safety ( fi. span , * safety) ;
11881215 self . check_foreign_kind_bodyless ( fi. ident , "static" , expr. as_ref ( ) . map ( |b| b. span ) ) ;
11891216 self . check_foreign_item_ascii_only ( fi. ident ) ;
11901217 }
@@ -1740,6 +1767,7 @@ pub fn check_crate(
17401767 outer_impl_trait : None ,
17411768 disallow_tilde_const : Some ( DisallowTildeConstContext :: Item ) ,
17421769 is_impl_trait_banned : false ,
1770+ extern_mod_safety : None ,
17431771 lint_buffer : lints,
17441772 } ;
17451773 visit:: walk_crate ( & mut validator, krate) ;
0 commit comments