Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: Add support for missing_unsafe_on_extern feature #126761

Merged
merged 2 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3077,23 +3077,20 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
let def_id = item.owner_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
// FIXME(missing_unsafe_on_extern) handle safety of foreign fns.
// Safety was added as part of the implementation of unsafe extern blocks PR #124482
hir::ForeignItemKind::Fn(decl, names, generics, _) => {
hir::ForeignItemKind::Fn(decl, names, generics, safety) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = clean_generics(generics, cx);
let args = clean_args_from_types_and_names(cx, decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, decl, None, args);
(generics, decl)
});
ForeignFunctionItem(Box::new(Function { decl, generics }))
}
// FIXME(missing_unsafe_on_extern) handle safety of foreign statics.
// Safety was added as part of the implementation of unsafe extern blocks PR #124482
hir::ForeignItemKind::Static(ty, mutability, _) => {
ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
ForeignFunctionItem(Box::new(Function { decl, generics }), safety)
}
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
Static { type_: clean_ty(ty, cx), mutability, expr: None },
safety,
),
hir::ForeignItemKind::Type => ForeignTypeItem,
};

Expand Down
16 changes: 8 additions & 8 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,14 +639,14 @@ impl Item {
hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
}
let header = match *self.kind {
ItemKind::ForeignFunctionItem(_) => {
ItemKind::ForeignFunctionItem(_, safety) => {
let def_id = self.def_id().unwrap();
let abi = tcx.fn_sig(def_id).skip_binder().abi();
hir::FnHeader {
safety: if abi == Abi::RustIntrinsic {
intrinsic_operation_unsafety(tcx, def_id.expect_local())
} else {
hir::Safety::Unsafe
safety
},
abi,
constness: if tcx.is_const_fn(def_id)
Expand Down Expand Up @@ -842,9 +842,9 @@ pub(crate) enum ItemKind {
StructFieldItem(Type),
VariantItem(Variant),
/// `fn`s from an extern block
ForeignFunctionItem(Box<Function>),
ForeignFunctionItem(Box<Function>, hir::Safety),
/// `static`s from an extern block
ForeignStaticItem(Static),
ForeignStaticItem(Static, hir::Safety),
/// `type`s from an extern block
ForeignTypeItem,
MacroItem(Macro),
Expand Down Expand Up @@ -893,8 +893,8 @@ impl ItemKind {
| TyMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignFunctionItem(_, _)
| ForeignStaticItem(_, _)
| ForeignTypeItem
| MacroItem(_)
| ProcMacroItem(_)
Expand Down Expand Up @@ -924,8 +924,8 @@ impl ItemKind {
| StaticItem(_)
| ConstantItem(_, _, _)
| TraitAliasItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignFunctionItem(_, _)
| ForeignStaticItem(_, _)
| ForeignTypeItem
| MacroItem(_)
| ProcMacroItem(_)
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ pub(crate) trait DocFolder: Sized {
| TyMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignFunctionItem(..)
| ForeignStaticItem(..)
| ForeignTypeItem
| MacroItem(_)
| ProcMacroItem(_)
Expand Down
23 changes: 18 additions & 5 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf

match &*item.kind {
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => {
item_function(buf, cx, item, f)
}
clean::TraitItem(ref t) => item_trait(buf, cx, item, t),
Expand All @@ -265,7 +265,8 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf
clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i),
clean::StaticItem(ref i) => item_static(buf, cx, item, i, None),
clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)),
clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c),
clean::ForeignTypeItem => item_foreign_type(buf, cx, item),
clean::KeywordItem => item_keyword(buf, cx, item),
Expand Down Expand Up @@ -491,11 +492,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
}

let unsafety_flag = match *myitem.kind {
clean::FunctionItem(_) | clean::ForeignFunctionItem(_)
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe =>
{
"<sup title=\"unsafe function\">⚠</sup>"
}
clean::ForeignStaticItem(_, hir::Safety::Unsafe) => {
"<sup title=\"unsafe static\">⚠</sup>"
}
_ => "",
};

Expand Down Expand Up @@ -1957,13 +1961,22 @@ fn item_fields(
}
}

fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
fn item_static(
w: &mut impl fmt::Write,
cx: &mut Context<'_>,
it: &clean::Item,
s: &clean::Static,
safety: Option<hir::Safety>,
) {
wrap_item(w, |buffer| {
render_attributes_in_code(buffer, it, cx);
write!(
buffer,
"{vis}static {mutability}{name}: {typ}",
"{vis}{safe}static {mutability}{name}: {typ}",
vis = visibility_print_with_space(it, cx),
safe = safety
.map(|safe| if safe == hir::Safety::Unsafe { "unsafe " } else { "" })
.unwrap_or(""),
mutability = s.mutability.print_with_space(),
name = it.name.unwrap(),
typ = s.type_.print(cx)
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,14 +310,16 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), tcx)),
ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, false, header.unwrap(), tcx)),
ForeignFunctionItem(f, _) => {
ItemEnum::Function(from_function(f, false, header.unwrap(), tcx))
}
TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)),
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), tcx)),
TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), tcx)),
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignTypeItem => ItemEnum::ForeignType,
TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)),
OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ pub(crate) trait DocVisitor: Sized {
| TyMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignFunctionItem(..)
| ForeignStaticItem(..)
| ForeignTypeItem
| MacroItem(_)
| ProcMacroItem(_)
Expand Down
30 changes: 30 additions & 0 deletions tests/rustdoc/unsafe-extern-blocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test to ensure the feature is working as expected.

#![feature(unsafe_extern_blocks)]
#![crate_name = "foo"]

// @has 'foo/index.html'

// First we check that both the static and the function have a "sup" element
// to tell they're unsafe.

// @count - '//ul[@class="item-table"]//sup[@title="unsafe static"]' 1
// @has - '//ul[@class="item-table"]//sup[@title="unsafe static"]' '⚠'
// @count - '//ul[@class="item-table"]//sup[@title="unsafe function"]' 1
// @has - '//ul[@class="item-table"]//sup[@title="unsafe function"]' '⚠'

unsafe extern {
// @has 'foo/static.FOO.html'
// @has - '//pre[@class="rust item-decl"]' 'pub static FOO: i32'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub safe static FOO: i32

pub safe static FOO: i32;
// @has 'foo/static.BAR.html'
// @has - '//pre[@class="rust item-decl"]' 'pub unsafe static BAR: i32'
pub static BAR: i32;

// @has 'foo/fn.foo.html'
// @has - '//pre[@class="rust item-decl"]' 'pub extern "C" fn foo()'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub safe extern "C" fn foo()

pub safe fn foo();
// @has 'foo/fn.bar.html'
// @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn bar()'
pub fn bar();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also add pub unsafe fn baz() and pub unsafe static BAZ: i32 to tests.

Loading