Skip to content

Rollup of 6 pull requests #73710

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

Closed
wants to merge 17 commits into from
Closed
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
2 changes: 2 additions & 0 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
@@ -92,11 +92,13 @@
//! pub struct Foo;
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_new() -> Box<Foo> {
//! Box::new(Foo)
//! }
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
//! ```
//!
4 changes: 2 additions & 2 deletions src/liballoc/vec.rs
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@
use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
use core::hash::{self, Hash};
use core::hash::{Hash, Hasher};
use core::intrinsics::{arith_offset, assume};
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::marker::PhantomData;
@@ -1943,7 +1943,7 @@ impl<T: Clone> Clone for Vec<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for Vec<T> {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&**self, state)
}
}
1 change: 1 addition & 0 deletions src/libpanic_abort/lib.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
use core::any::Any;

#[rustc_std_internal_symbol]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
unreachable!()
}
1 change: 1 addition & 0 deletions src/libpanic_unwind/lib.rs
Original file line number Diff line number Diff line change
@@ -81,6 +81,7 @@ extern "C" {
mod dwarf;

#[rustc_std_internal_symbol]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
Box::into_raw(imp::cleanup(payload))
}
3 changes: 2 additions & 1 deletion src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
@@ -167,7 +167,8 @@ macro_rules! late_lint_mod_passes {
$args,
[
HardwiredLints: HardwiredLints,
ImproperCTypes: ImproperCTypes,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
VariantSizeDifferences: VariantSizeDifferences,
BoxPointers: BoxPointers,
PathStatements: PathStatements,
120 changes: 95 additions & 25 deletions src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
use rustc_target::spec::abi::Abi;

@@ -498,10 +498,24 @@ declare_lint! {
"proper use of libc types in foreign modules"
}

declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);

declare_lint! {
IMPROPER_CTYPES_DEFINITIONS,
Warn,
"proper use of libc types in foreign item definitions"
}

declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);

enum ImproperCTypesMode {
Declarations,
Definitions,
}

struct ImproperCTypesVisitor<'a, 'tcx> {
cx: &'a LateContext<'a, 'tcx>,
mode: ImproperCTypesMode,
}

enum FfiResult<'tcx> {
@@ -804,27 +818,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
help: Some("consider using a struct instead".into()),
},

ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
if {
matches!(self.mode, ImproperCTypesMode::Definitions)
&& ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
} =>
{
FfiSafe
}

ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
self.check_type_for_ffi(cache, ty)
}

ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),

ty::FnPtr(sig) => {
match sig.abi() {
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe {
ty,
reason: "this function pointer has Rust-specific calling convention"
if self.is_internal_abi(sig.abi()) {
return FfiUnsafe {
ty,
reason: "this function pointer has Rust-specific calling convention".into(),
help: Some(
"consider using an `extern fn(...) -> ...` \
function pointer instead"
.into(),
help: Some(
"consider using an `extern fn(...) -> ...` \
function pointer instead"
.into(),
),
};
}
_ => {}
),
};
}

let sig = cx.erase_late_bound_regions(&sig);
@@ -857,15 +876,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
}

// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
ty::Param(..) | ty::Projection(..)
if matches!(self.mode, ImproperCTypesMode::Definitions) =>
{
FfiSafe
}

ty::Param(..)
| ty::Projection(..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Placeholder(..)
| ty::Projection(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
}
@@ -877,9 +904,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
note: &str,
help: Option<&str>,
) {
self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
let mut diag =
lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
let lint = match self.mode {
ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
};

self.cx.struct_span_lint(lint, sp, |lint| {
let item_description = match self.mode {
ImproperCTypesMode::Declarations => "block",
ImproperCTypesMode::Definitions => "fn",
};
let mut diag = lint.build(&format!(
"`extern` {} uses type `{}`, which is not FFI-safe",
item_description, ty
));
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help {
diag.help(help);
@@ -947,7 +985,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {

// it is only OK to use this function because extern fns cannot have
// any generic types right now:
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);

// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
@@ -997,15 +1035,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let ty = self.cx.tcx.type_of(def_id);
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
}

fn is_internal_abi(&self, abi: Abi) -> bool {
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
true
} else {
false
}
}
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
let mut vis = ImproperCTypesVisitor { cx };
let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
// Don't worry about types in internal ABIs.
} else {

if !vis.is_internal_abi(abi) {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
vis.check_foreign_fn(it.hir_id, decl);
@@ -1019,6 +1064,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
}
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
kind: hir::intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl<'_>,
_: &'tcx hir::Body<'_>,
_: Span,
hir_id: hir::HirId,
) {
use hir::intravisit::FnKind;

let abi = match kind {
FnKind::ItemFn(_, _, header, ..) => header.abi,
FnKind::Method(_, sig, ..) => sig.header.abi,
_ => return,
};

let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
if !vis.is_internal_abi(abi) {
vis.check_foreign_fn(hir_id, decl);
}
}
}

declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
1 change: 1 addition & 0 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ pub struct RustString {

/// Appending to a Rust string -- used by RawRustStringOstream.
#[no_mangle]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
sr: &RustString,
ptr: *const c_char,
1 change: 0 additions & 1 deletion src/librustc_target/spec/apple_sdk_base.rs
Original file line number Diff line number Diff line change
@@ -141,7 +141,6 @@ pub fn opts(arch: Arch, os: AppleOS) -> Result<TargetOptions, String> {
let pre_link_args = build_pre_link_args(arch, os)?;
Ok(TargetOptions {
cpu: target_cpu(arch),
dynamic_linking: false,
executables: true,
pre_link_args,
link_env_remove: link_env_remove(arch),
88 changes: 86 additions & 2 deletions src/libstd/keyword_docs.rs
Original file line number Diff line number Diff line change
@@ -1009,9 +1009,93 @@ mod return_keyword {}
//
/// The receiver of a method, or the current module.
///
/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
/// `self` is used in two situations: referencing the current module and marking
/// the receiver of a method.
///
/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
/// In paths, `self` can be used to refer to the current module, either in a
/// [`use`] statement or in a path to access an element:
///
/// ```
/// # #![allow(unused_imports)]
/// use std::io::{self, Read};
/// ```
///
/// Is functionally the same as:
///
/// ```
/// # #![allow(unused_imports)]
/// use std::io;
/// use std::io::Read;
/// ```
///
/// Using `self` to access an element in the current module:
///
/// ```
/// # #![allow(dead_code)]
/// # fn main() {}
/// fn foo() {}
/// fn bar() {
/// self::foo()
/// }
/// ```
///
/// `self` as the current receiver for a method allows to omit the parameter
/// type most of the time. With the exception of this particularity, `self` is
/// used much like any other parameter:
///
/// ```
/// struct Foo(i32);
///
/// impl Foo {
/// // No `self`.
/// fn new() -> Self {
/// Self(0)
/// }
///
/// // Consuming `self`.
/// fn consume(self) -> Self {
/// Self(self.0 + 1)
/// }
///
/// // Borrowing `self`.
/// fn borrow(&self) -> &i32 {
/// &self.0
/// }
///
/// // Borrowing `self` mutably.
/// fn borrow_mut(&mut self) -> &mut i32 {
/// &mut self.0
/// }
/// }
///
/// // This method must be called with a `Type::` prefix.
/// let foo = Foo::new();
/// assert_eq!(foo.0, 0);
///
/// // Those two calls produces the same result.
/// let foo = Foo::consume(foo);
/// assert_eq!(foo.0, 1);
/// let foo = foo.consume();
/// assert_eq!(foo.0, 2);
///
/// // Borrowing is handled automatically with the second syntax.
/// let borrow_1 = Foo::borrow(&foo);
/// let borrow_2 = foo.borrow();
/// assert_eq!(borrow_1, borrow_2);
///
/// // Borrowing mutably is handled automatically too with the second syntax.
/// let mut foo = Foo::new();
/// *Foo::borrow_mut(&mut foo) += 1;
/// assert_eq!(foo.0, 1);
/// *foo.borrow_mut() += 1;
/// assert_eq!(foo.0, 2);
/// ```
///
/// Note that this automatic conversion when calling `foo.method()` is not
/// limited to the examples above. See the [Reference] for more information.
///
/// [`use`]: keyword.use.html
/// [Reference]: ../reference/items/associated-items.html#methods
mod self_keyword {}

#[doc(keyword = "Self")]
Loading