Add safe/unsafe to static inside extern blocks

This commit is contained in:
Santiago Pastorino 2024-05-07 14:43:23 +02:00
parent b4cbdb7246
commit bac72cf7cf
No known key found for this signature in database
GPG Key ID: 8131A24E0C79EFAF
27 changed files with 152 additions and 57 deletions

View File

@ -3164,6 +3164,7 @@ pub struct DelegationMac {
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct StaticItem {
pub ty: P<Ty>,
pub safety: Safety,
pub mutability: Mutability,
pub expr: Option<P<Expr>>,
}
@ -3182,7 +3183,7 @@ impl From<StaticItem> for StaticForeignItem {
fn from(static_item: StaticItem) -> StaticForeignItem {
StaticForeignItem {
ty: static_item.ty,
safety: Safety::Default,
safety: static_item.safety,
mutability: static_item.mutability,
expr: static_item.expr,
}
@ -3193,6 +3194,7 @@ impl From<StaticForeignItem> for StaticItem {
fn from(static_item: StaticForeignItem) -> StaticItem {
StaticItem {
ty: static_item.ty,
safety: static_item.safety,
mutability: static_item.mutability,
expr: static_item.expr,
}

View File

@ -1080,7 +1080,7 @@ impl NoopVisitItemKind for ItemKind {
match self {
ItemKind::ExternCrate(_orig_name) => {}
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}

View File

@ -334,7 +334,7 @@ impl WalkItemKind for ItemKind {
match self {
ItemKind::ExternCrate(_) => {}
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)),
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
try_visit!(visitor.visit_ty(ty));
visit_opt!(visitor, visit_expr, expr);
}

View File

@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
}
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => {
let (ty, body_id) =
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
hir::ItemKind::Static(ty, *m, body_id)

View File

@ -171,7 +171,8 @@ impl<'a> State<'a> {
self.print_use_tree(tree);
self.word(";");
}
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => {
self.print_safety(*safety);
self.print_item_const(
item.ident,
Some(*mutbl),

View File

@ -102,7 +102,7 @@ fn intern_as_new_static<'tcx>(
let feed = tcx.create_def(
static_id,
sym::nested,
DefKind::Static { mutability: alloc.0.mutability, nested: true },
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());

View File

@ -711,7 +711,9 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId)
// We're not using `try_global_alloc` since dangling pointers have already been handled.
match ecx.tcx.global_alloc(alloc_id) {
GlobalAlloc::Static(did) => {
let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() };
let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else {
bug!()
};
if nested {
assert!(
ecx.memory.alloc_map.get(alloc_id).is_none(),

View File

@ -631,7 +631,10 @@ impl<'a> ExtCtxt<'a> {
span,
name,
AttrVec::new(),
ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()),
ast::ItemKind::Static(
ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) }
.into(),
),
)
}

View File

@ -76,6 +76,8 @@ pub enum DefKind {
/// Constant generic parameter: `struct Foo<const N: usize> { ... }`
ConstParam,
Static {
/// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`.
safety: hir::Safety,
/// Whether it's a `static mut` or just a `static`.
mutability: ast::Mutability,
/// Whether it's an anonymous static generated for nested allocations.

View File

@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> {
if let hir::ExprKind::Path(qpath) = expr.kind
&& let hir::QPath::Resolved(_, path) = qpath
&& let hir::def::Res::Def(def_kind, _) = path.res
&& let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
&& let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } =
def_kind
{
return Some(qpath_to_string(&tcx, &qpath));
}

View File

@ -156,10 +156,14 @@ fixed_size_enum! {
( Impl { of_trait: false } )
( Impl { of_trait: true } )
( Closure )
( Static { mutability: ast::Mutability::Not, nested: false } )
( Static { mutability: ast::Mutability::Mut, nested: false } )
( Static { mutability: ast::Mutability::Not, nested: true } )
( Static { mutability: ast::Mutability::Mut, nested: true } )
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } )
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } )
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } )
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } )
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } )
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } )
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } )
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } )
( Ctor(CtorOf::Struct, CtorKind::Fn) )
( Ctor(CtorOf::Struct, CtorKind::Const) )
( Ctor(CtorOf::Variant, CtorKind::Fn) )

View File

@ -305,7 +305,9 @@ impl<'hir> Map<'hir> {
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
DefKind::Closure => BodyOwnerKind::Closure,
DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability),
DefKind::Static { safety: _, mutability, nested: false } => {
BodyOwnerKind::Static(mutability)
}
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
}
}

View File

@ -559,10 +559,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
match (kind, body.source.promoted) {
(_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts
(DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
(DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => {
(DefKind::Static { safety: _, mutability: hir::Mutability::Not, nested: false }, _) => {
write!(w, "static ")?
}
(DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => {
(DefKind::Static { safety: _, mutability: hir::Mutability::Mut, nested: false }, _) => {
write!(w, "static mut ")?
}
(_, _) if is_function => write!(w, "fn ")?,

View File

@ -2,6 +2,7 @@ use crate::build::ExprCategory;
use crate::errors::*;
use rustc_errors::DiagArgValue;
use rustc_hir::def::DefKind;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
use rustc_middle::mir::BorrowKind;
use rustc_middle::span_bug;
@ -456,7 +457,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
if self.tcx.is_mutable_static(def_id) {
self.requires_unsafe(expr.span, UseOfMutableStatic);
} else if self.tcx.is_foreign_item(def_id) {
self.requires_unsafe(expr.span, UseOfExternStatic);
match self.tcx.def_kind(def_id) {
DefKind::Static { safety: hir::Safety::Safe, .. } => {}
_ => self.requires_unsafe(expr.span, UseOfExternStatic),
}
}
} else if self.thir[arg].ty.is_unsafe_ptr() {
self.requires_unsafe(expr.span, DerefOfRawPointer);

View File

@ -226,10 +226,11 @@ impl<'a> Parser<'a> {
self.expect_keyword(kw::Extern)?;
self.parse_item_foreign_mod(attrs, safety)?
} else if self.is_static_global() {
let safety = self.parse_safety(Case::Sensitive);
// STATIC ITEM
self.bump(); // `static`
let mutability = self.parse_mutability();
let (ident, item) = self.parse_static_item(mutability)?;
let (ident, item) = self.parse_static_item(safety, mutability)?;
(ident, ItemKind::Static(Box::new(item)))
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
// CONST ITEM
@ -952,7 +953,7 @@ impl<'a> Parser<'a> {
let kind = match AssocItemKind::try_from(kind) {
Ok(kind) => kind,
Err(kind) => match kind {
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
AssocItemKind::Const(Box::new(ConstItem {
defaultness: Defaultness::Final,
@ -1259,7 +1260,10 @@ impl<'a> Parser<'a> {
matches!(token.kind, token::BinOp(token::Or) | token::OrOr)
})
} else {
false
let quals: &[Symbol] = &[kw::Unsafe, kw::Safe];
// `$qual static`
quals.iter().any(|&kw| self.check_keyword(kw))
&& self.look_ahead(1, |t| t.is_keyword(kw::Static))
}
}
@ -1320,7 +1324,11 @@ impl<'a> Parser<'a> {
/// ```ebnf
/// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ;
/// ```
fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> {
fn parse_static_item(
&mut self,
safety: Safety,
mutability: Mutability,
) -> PResult<'a, (Ident, StaticItem)> {
let ident = self.parse_ident()?;
if self.token.kind == TokenKind::Lt && self.may_recover() {
@ -1341,7 +1349,7 @@ impl<'a> Parser<'a> {
self.expect_semi()?;
Ok((ident, StaticItem { ty, mutability, expr }))
Ok((ident, StaticItem { ty, safety, mutability, expr }))
}
/// Parse a constant item with the prefix `"const"` already parsed.

View File

@ -2,6 +2,7 @@ use crate::{ImplTraitContext, Resolver};
use rustc_ast::visit::FnKind;
use rustc_ast::*;
use rustc_expand::expand::AstFragment;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::LocalDefId;
use rustc_span::hygiene::LocalExpnId;
@ -128,7 +129,11 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ItemKind::Union(..) => DefKind::Union,
ItemKind::ExternCrate(..) => DefKind::ExternCrate,
ItemKind::TyAlias(..) => DefKind::TyAlias,
ItemKind::Static(s) => DefKind::Static { mutability: s.mutability, nested: false },
ItemKind::Static(s) => DefKind::Static {
safety: hir::Safety::Safe,
mutability: s.mutability,
nested: false,
},
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
ItemKind::MacroDef(..) => {
@ -215,8 +220,15 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
ty: _,
mutability,
expr: _,
safety: _,
}) => DefKind::Static { mutability, nested: false },
safety,
}) => {
let safety = match safety {
ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe,
ast::Safety::Safe(_) => hir::Safety::Safe,
};
DefKind::Static { safety, mutability, nested: false }
}
ForeignItemKind::Fn(_) => DefKind::Fn,
ForeignItemKind::TyAlias(_) => DefKind::ForeignTy,
ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id),

View File

@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag, DiagMessage};
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{DefKind, Namespace, PerNS};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::Mutability;
use rustc_hir::{Mutability, Safety};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
@ -1517,7 +1517,11 @@ impl Disambiguator {
"union" => Kind(DefKind::Union),
"module" | "mod" => Kind(DefKind::Mod),
"const" | "constant" => Kind(DefKind::Const),
"static" => Kind(DefKind::Static { mutability: Mutability::Not, nested: false }),
"static" => Kind(DefKind::Static {
mutability: Mutability::Not,
nested: false,
safety: Safety::Safe,
}),
"function" | "fn" | "method" => Kind(DefKind::Fn),
"derive" => Kind(DefKind::Macro(MacroKind::Derive)),
"type" => NS(Namespace::TypeNS),

View File

@ -308,13 +308,15 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
ty: lt,
mutability: lm,
expr: le,
safety: ls,
}),
Static(box StaticItem {
ty: rt,
mutability: rm,
expr: re,
safety: rs,
}),
) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re),
(
Const(box ConstItem {
defaultness: ld,

View File

@ -1,11 +1,19 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
--> $DIR/extern-items-unsafe.rs:11:5
--> $DIR/extern-items-unsafe.rs:12:5
|
LL | test1(i);
| ^^^^^^^^ call to unsafe function
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 1 previous error
error[E0133]: use of extern static is unsafe and requires unsafe function or block
--> $DIR/extern-items-unsafe.rs:12:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,11 +1,19 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
--> $DIR/extern-items-unsafe.rs:11:5
--> $DIR/extern-items-unsafe.rs:12:5
|
LL | test1(i);
| ^^^^^^^^ call to unsafe function
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 1 previous error
error[E0133]: use of extern static is unsafe and requires unsafe block
--> $DIR/extern-items-unsafe.rs:12:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -4,17 +4,19 @@
//@[edition2024] compile-flags: -Zunstable-options
unsafe extern "C" {
static TEST1: i32;
fn test1(i: i32);
}
fn test2(i: i32) {
test1(i);
fn test2() {
test1(TEST1);
//~^ ERROR: call to unsafe function `test1` is unsafe
//~| ERROR: use of extern static is unsafe
}
fn test3(i: i32) {
fn test3() {
unsafe {
test1(i);
test1(TEST1);
}
}

View File

@ -5,11 +5,12 @@
//@ check-pass
unsafe extern "C" {
safe static TEST1: i32;
safe fn test1(i: i32);
}
fn test2(i: i32) {
test1(i);
fn test2() {
test1(TEST1);
}
fn main() {}

View File

@ -1,10 +1,12 @@
extern "C" {
safe static TEST1: i32;
//~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
safe fn test1(i: i32);
//~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers
}
fn test2(i: i32) {
test1(i);
fn test2() {
test1(TEST1);
}
fn main() {}

View File

@ -3,8 +3,17 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers
|
LL | extern "C" {
| ---------- help: add unsafe to this `extern` block
LL | safe static TEST1: i32;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: items in unadorned `extern` blocks cannot have safety qualifiers
--> $DIR/safe-unsafe-on-unadorned-extern-block.rs:4:5
|
LL | extern "C" {
| ---------- help: add unsafe to this `extern` block
...
LL | safe fn test1(i: i32);
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
error: aborting due to 2 previous errors

View File

@ -1,11 +1,19 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block
--> $DIR/unsafe-items.rs:17:5
--> $DIR/unsafe-items.rs:18:5
|
LL | test1(i);
| ^^^^^^^^ call to unsafe function
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 1 previous error
error[E0133]: use of extern static is unsafe and requires unsafe function or block
--> $DIR/unsafe-items.rs:18:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,11 +1,19 @@
error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block
--> $DIR/unsafe-items.rs:17:5
--> $DIR/unsafe-items.rs:18:5
|
LL | test1(i);
| ^^^^^^^^ call to unsafe function
LL | test1(TEST1);
| ^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 1 previous error
error[E0133]: use of extern static is unsafe and requires unsafe block
--> $DIR/unsafe-items.rs:18:11
|
LL | test1(TEST1);
| ^^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -4,18 +4,20 @@
//@[edition2024] compile-flags: -Zunstable-options
unsafe extern "C" {
unsafe static TEST1: i32;
unsafe fn test1(i: i32);
}
fn test2(i: i32) {
fn test2() {
unsafe {
test1(i);
test1(TEST1);
}
}
fn test3(i: i32) {
test1(i);
fn test3() {
test1(TEST1);
//~^ ERROR: call to unsafe function `test1` is unsafe
//~| ERROR: use of extern static is unsafe
}
fn main() {}