Auto merge of #114748 - cuviper:beta-next, r=cuviper
[beta] backport * Restrict linker version script of proc-macro crates to just its two symbols #114470 * bootstrap: config: fix version comparison bug #114440 * lint/ctypes: only try normalize #113921 * Avoid tls access while iterating through mpsc thread entries #113861 * Substitute types before checking inlining compatibility. #113802 * Revert "fix: bug etc/bash_complettion -> src/etc/... to avoid copy error" #113579 * lint/ctypes: fix () return type checks #113457 * Rename and allow cast_ref_to_mut lint #113422 * Ignore flaky clippy tests. #113621 r? cuviper
This commit is contained in:
commit
d1fa3e4de3
29 changed files with 306 additions and 133 deletions
|
|
@ -13,6 +13,7 @@ use std::{env, mem, str};
|
|||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::find_native_static_library;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols;
|
||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
|
|
@ -659,8 +660,6 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME(#99978) hide #[no_mangle] symbols for proc-macros
|
||||
|
||||
let is_windows = self.sess.target.is_like_windows;
|
||||
let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
|
||||
|
||||
|
|
@ -1679,8 +1678,15 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
|
|||
return exports.iter().map(ToString::to_string).collect();
|
||||
}
|
||||
|
||||
let mut symbols = Vec::new();
|
||||
if let CrateType::ProcMacro = crate_type {
|
||||
exported_symbols_for_proc_macro_crate(tcx)
|
||||
} else {
|
||||
exported_symbols_for_non_proc_macro(tcx, crate_type)
|
||||
}
|
||||
}
|
||||
|
||||
fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
|
||||
let mut symbols = Vec::new();
|
||||
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
|
||||
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
|
||||
if info.level.is_below_threshold(export_threshold) {
|
||||
|
|
@ -1691,6 +1697,19 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
|
|||
symbols
|
||||
}
|
||||
|
||||
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
|
||||
// `exported_symbols` will be empty when !should_codegen.
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let stable_crate_id = tcx.sess.local_stable_crate_id();
|
||||
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
|
||||
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
|
||||
|
||||
vec![proc_macro_decls_name, metadata_symbol_name]
|
||||
}
|
||||
|
||||
pub(crate) fn linked_symbols(
|
||||
tcx: TyCtxt<'_>,
|
||||
crate_type: CrateType,
|
||||
|
|
|
|||
|
|
@ -155,8 +155,6 @@ lint_builtin_unused_doc_comment = unused doc comment
|
|||
lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
|
||||
.suggestion = use `loop`
|
||||
|
||||
lint_cast_ref_to_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
|
||||
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
|
||||
|
||||
lint_check_name_unknown = unknown lint: `{$lint_name}`
|
||||
|
|
@ -264,8 +262,6 @@ lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
|
|||
lint_improper_ctypes_char_reason = the `char` type has no C equivalent
|
||||
lint_improper_ctypes_dyn = trait objects have no C equivalent
|
||||
|
||||
lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
|
||||
|
||||
lint_improper_ctypes_enum_repr_help =
|
||||
consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
|
||||
|
||||
|
|
@ -319,6 +315,8 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
|
|||
|
||||
lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
|
||||
|
||||
lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
|
||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ extern crate tracing;
|
|||
|
||||
mod array_into_iter;
|
||||
pub mod builtin;
|
||||
mod cast_ref_to_mut;
|
||||
mod context;
|
||||
mod deref_into_dyn_supertrait;
|
||||
mod drop_forget_useless;
|
||||
|
|
@ -77,6 +76,7 @@ mod opaque_hidden_inferred_bound;
|
|||
mod pass_by_value;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod reference_casting;
|
||||
mod traits;
|
||||
mod types;
|
||||
mod unused;
|
||||
|
|
@ -98,7 +98,6 @@ use rustc_span::Span;
|
|||
|
||||
use array_into_iter::ArrayIntoIter;
|
||||
use builtin::*;
|
||||
use cast_ref_to_mut::*;
|
||||
use deref_into_dyn_supertrait::*;
|
||||
use drop_forget_useless::*;
|
||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||
|
|
@ -117,6 +116,7 @@ use noop_method_call::*;
|
|||
use opaque_hidden_inferred_bound::*;
|
||||
use pass_by_value::*;
|
||||
use redundant_semicolon::*;
|
||||
use reference_casting::*;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
use unused::*;
|
||||
|
|
@ -216,7 +216,7 @@ late_lint_methods!(
|
|||
BoxPointers: BoxPointers,
|
||||
PathStatements: PathStatements,
|
||||
LetUnderscore: LetUnderscore,
|
||||
CastRefToMut: CastRefToMut,
|
||||
InvalidReferenceCasting: InvalidReferenceCasting,
|
||||
// Depends on referenced function signatures in expressions
|
||||
UnusedResults: UnusedResults,
|
||||
NonUpperCaseGlobals: NonUpperCaseGlobals,
|
||||
|
|
|
|||
|
|
@ -737,10 +737,10 @@ pub enum InvalidFromUtf8Diag {
|
|||
},
|
||||
}
|
||||
|
||||
// cast_ref_to_mut.rs
|
||||
// reference_casting.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_cast_ref_to_mut)]
|
||||
pub struct CastRefToMutDiag;
|
||||
#[diag(lint_invalid_reference_casting)]
|
||||
pub struct InvalidReferenceCastingDiag;
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
|
|
|
|||
|
|
@ -3,15 +3,16 @@ use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp};
|
|||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::{lints::CastRefToMutDiag, LateContext, LateLintPass, LintContext};
|
||||
use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
|
||||
|
||||
declare_lint! {
|
||||
/// The `cast_ref_to_mut` lint checks for casts of `&T` to `&mut T`
|
||||
/// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T`
|
||||
/// without using interior mutability.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![deny(invalid_reference_casting)]
|
||||
/// fn x(r: &i32) {
|
||||
/// unsafe {
|
||||
/// *(r as *const i32 as *mut i32) += 1;
|
||||
|
|
@ -28,14 +29,14 @@ declare_lint! {
|
|||
///
|
||||
/// `UnsafeCell` is the only way to obtain aliasable data that is considered
|
||||
/// mutable.
|
||||
CAST_REF_TO_MUT,
|
||||
Deny,
|
||||
INVALID_REFERENCE_CASTING,
|
||||
Allow,
|
||||
"casts of `&T` to `&mut T` without interior mutability"
|
||||
}
|
||||
|
||||
declare_lint_pass!(CastRefToMut => [CAST_REF_TO_MUT]);
|
||||
declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
|
||||
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else { return; };
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
|
|||
|
||||
let e = e.peel_blocks();
|
||||
if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() {
|
||||
cx.emit_spanned_lint(CAST_REF_TO_MUT, expr.span, CastRefToMutDiag);
|
||||
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -963,12 +963,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
substs: SubstsRef<'tcx>,
|
||||
) -> FfiResult<'tcx> {
|
||||
let field_ty = field.ty(self.cx.tcx, substs);
|
||||
if field_ty.has_opaque_types() {
|
||||
self.check_type_for_ffi(cache, field_ty)
|
||||
} else {
|
||||
let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
|
||||
self.check_type_for_ffi(cache, field_ty)
|
||||
}
|
||||
let field_ty = self
|
||||
.cx
|
||||
.tcx
|
||||
.try_normalize_erasing_regions(self.cx.param_env, field_ty)
|
||||
.unwrap_or(field_ty);
|
||||
self.check_type_for_ffi(cache, field_ty)
|
||||
}
|
||||
|
||||
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
|
||||
|
|
@ -982,39 +982,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
) -> FfiResult<'tcx> {
|
||||
use FfiResult::*;
|
||||
|
||||
let transparent_safety = def.repr().transparent().then(|| {
|
||||
// Can assume that at most one field is not a ZST, so only check
|
||||
// that field's type for FFI-safety.
|
||||
let transparent_with_all_zst_fields = if def.repr().transparent() {
|
||||
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
||||
return self.check_field_type_for_ffi(cache, field, substs);
|
||||
// Transparent newtypes have at most one non-ZST field which needs to be checked..
|
||||
match self.check_field_type_for_ffi(cache, field, substs) {
|
||||
FfiUnsafe { ty, .. } if ty.is_unit() => (),
|
||||
r => return r,
|
||||
}
|
||||
|
||||
false
|
||||
} else {
|
||||
// All fields are ZSTs; this means that the type should behave
|
||||
// like (), which is FFI-unsafe... except if all fields are PhantomData,
|
||||
// which is tested for below
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
||||
// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
|
||||
// `PhantomData`).
|
||||
true
|
||||
}
|
||||
});
|
||||
// We can't completely trust repr(C) markings; make sure the fields are
|
||||
// actually safe.
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
|
||||
let mut all_phantom = !variant.fields.is_empty();
|
||||
for field in &variant.fields {
|
||||
match self.check_field_type_for_ffi(cache, &field, substs) {
|
||||
FfiSafe => {
|
||||
all_phantom = false;
|
||||
}
|
||||
FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_enum_phantomdata,
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
FfiPhantom(..) => {}
|
||||
r => return transparent_safety.unwrap_or(r),
|
||||
all_phantom &= match self.check_field_type_for_ffi(cache, &field, substs) {
|
||||
FfiSafe => false,
|
||||
// `()` fields are FFI-safe!
|
||||
FfiUnsafe { ty, .. } if ty.is_unit() => false,
|
||||
FfiPhantom(..) => true,
|
||||
r @ FfiUnsafe { .. } => return r,
|
||||
}
|
||||
}
|
||||
|
||||
if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
|
||||
if all_phantom {
|
||||
FfiPhantom(ty)
|
||||
} else if transparent_with_all_zst_fields {
|
||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
||||
} else {
|
||||
FfiSafe
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
|
||||
|
|
@ -1217,25 +1221,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let sig = tcx.erase_late_bound_regions(sig);
|
||||
if !sig.output().is_unit() {
|
||||
let r = self.check_type_for_ffi(cache, sig.output());
|
||||
match r {
|
||||
FfiSafe => {}
|
||||
_ => {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
for arg in sig.inputs() {
|
||||
let r = self.check_type_for_ffi(cache, *arg);
|
||||
match r {
|
||||
match self.check_type_for_ffi(cache, *arg) {
|
||||
FfiSafe => {}
|
||||
_ => {
|
||||
return r;
|
||||
}
|
||||
r => return r,
|
||||
}
|
||||
}
|
||||
FfiSafe
|
||||
|
||||
let ret_ty = sig.output();
|
||||
if ret_ty.is_unit() {
|
||||
return FfiSafe;
|
||||
}
|
||||
|
||||
self.check_type_for_ffi(cache, ret_ty)
|
||||
}
|
||||
|
||||
ty::Foreign(..) => FfiSafe,
|
||||
|
|
@ -1317,7 +1315,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if let Some(ty) = self
|
||||
.cx
|
||||
.tcx
|
||||
.normalize_erasing_regions(self.cx.param_env, ty)
|
||||
.try_normalize_erasing_regions(self.cx.param_env, ty)
|
||||
.unwrap_or(ty)
|
||||
.visit_with(&mut ProhibitOpaqueTypes)
|
||||
.break_value()
|
||||
{
|
||||
|
|
@ -1335,16 +1334,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
is_static: bool,
|
||||
is_return_type: bool,
|
||||
) {
|
||||
// We have to check for opaque types before `normalize_erasing_regions`,
|
||||
// which will replace opaque types with their underlying concrete type.
|
||||
if self.check_for_opaque_ty(sp, ty) {
|
||||
// We've already emitted an error due to an opaque type.
|
||||
return;
|
||||
}
|
||||
|
||||
// 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(self.cx.param_env, ty);
|
||||
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_env, ty).unwrap_or(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
|
||||
|
|
@ -1354,7 +1349,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// Don't report FFI errors for unit return types. This check exists here, and not in
|
||||
// `check_foreign_fn` (where it would make more sense) so that normalization has definitely
|
||||
// the caller (where it would make more sense) so that normalization has definitely
|
||||
// happened.
|
||||
if is_return_type && ty.is_unit() {
|
||||
return;
|
||||
|
|
@ -1370,9 +1365,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
None,
|
||||
);
|
||||
}
|
||||
// If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
|
||||
// argument, which after substitution, is `()`, then this branch can be hit.
|
||||
FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
|
||||
FfiResult::FfiUnsafe { ty, reason, help } => {
|
||||
self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,6 +440,10 @@ impl<'tcx> Inliner<'tcx> {
|
|||
validation: Ok(()),
|
||||
};
|
||||
|
||||
for var_debug_info in callee_body.var_debug_info.iter() {
|
||||
checker.visit_var_debug_info(var_debug_info);
|
||||
}
|
||||
|
||||
// Traverse the MIR manually so we can account for the effects of inlining on the CFG.
|
||||
let mut work_list = vec![START_BLOCK];
|
||||
let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
|
||||
|
|
@ -847,7 +851,16 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
|||
if let ProjectionElem::Field(f, ty) = elem {
|
||||
let parent_ty = place_ref.ty(&self.callee_body.local_decls, self.tcx);
|
||||
let check_equal = |this: &mut Self, f_ty| {
|
||||
if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
|
||||
// Fast path if there is nothing to substitute.
|
||||
if ty == f_ty {
|
||||
return;
|
||||
}
|
||||
let ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&ty));
|
||||
let f_ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&f_ty));
|
||||
if ty == f_ty {
|
||||
return;
|
||||
}
|
||||
if !util::is_subtype(this.tcx, this.param_env, ty, f_ty) {
|
||||
trace!(?ty, ?f_ty);
|
||||
this.validation = Err("failed to normalize projection type");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -66,26 +66,32 @@ impl Waker {
|
|||
/// Attempts to find another thread's entry, select the operation, and wake it up.
|
||||
#[inline]
|
||||
pub(crate) fn try_select(&mut self) -> Option<Entry> {
|
||||
self.selectors
|
||||
.iter()
|
||||
.position(|selector| {
|
||||
// Does the entry belong to a different thread?
|
||||
selector.cx.thread_id() != current_thread_id()
|
||||
&& selector // Try selecting this operation.
|
||||
.cx
|
||||
.try_select(Selected::Operation(selector.oper))
|
||||
.is_ok()
|
||||
&& {
|
||||
// Provide the packet.
|
||||
selector.cx.store_packet(selector.packet);
|
||||
// Wake the thread up.
|
||||
selector.cx.unpark();
|
||||
true
|
||||
}
|
||||
})
|
||||
// Remove the entry from the queue to keep it clean and improve
|
||||
// performance.
|
||||
.map(|pos| self.selectors.remove(pos))
|
||||
if self.selectors.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let thread_id = current_thread_id();
|
||||
|
||||
self.selectors
|
||||
.iter()
|
||||
.position(|selector| {
|
||||
// Does the entry belong to a different thread?
|
||||
selector.cx.thread_id() != thread_id
|
||||
&& selector // Try selecting this operation.
|
||||
.cx
|
||||
.try_select(Selected::Operation(selector.oper))
|
||||
.is_ok()
|
||||
&& {
|
||||
// Provide the packet.
|
||||
selector.cx.store_packet(selector.packet);
|
||||
// Wake the thread up.
|
||||
selector.cx.unpark();
|
||||
true
|
||||
}
|
||||
})
|
||||
// Remove the entry from the queue to keep it clean and improve
|
||||
// performance.
|
||||
.map(|pos| self.selectors.remove(pos))
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies all operations waiting to be ready.
|
||||
|
|
|
|||
|
|
@ -1925,7 +1925,8 @@ impl Config {
|
|||
.unwrap();
|
||||
if !(source_version == rustc_version
|
||||
|| (source_version.major == rustc_version.major
|
||||
&& source_version.minor == rustc_version.minor + 1))
|
||||
&& (source_version.minor == rustc_version.minor
|
||||
|| source_version.minor == rustc_version.minor + 1)))
|
||||
{
|
||||
let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
|
||||
eprintln!(
|
||||
|
|
|
|||
|
|
@ -1074,11 +1074,7 @@ impl Step for Cargo {
|
|||
|
||||
tarball.add_file(&cargo, "bin", 0o755);
|
||||
tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
|
||||
tarball.add_renamed_file(
|
||||
etc.join("cargo.bashcomp.sh"),
|
||||
"src/etc/bash_completion.d",
|
||||
"cargo",
|
||||
);
|
||||
tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
|
||||
tarball.add_dir(etc.join("man"), "share/man/man1");
|
||||
tarball.add_legal_and_readme_to("share/doc/cargo");
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
|
|||
("clippy::stutter", "clippy::module_name_repetitions"),
|
||||
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
|
||||
("clippy::zero_width_space", "clippy::invisible_characters"),
|
||||
("clippy::cast_ref_to_mut", "cast_ref_to_mut"),
|
||||
("clippy::cast_ref_to_mut", "invalid_reference_casting"),
|
||||
("clippy::clone_double_ref", "suspicious_double_ref_op"),
|
||||
("clippy::cmp_nan", "invalid_nan_comparisons"),
|
||||
("clippy::drop_bounds", "drop_bounds"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
//@aux-build:proc_macro_attr.rs:proc-macro
|
||||
// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
|
||||
//@ignore-32bit
|
||||
//@ignore-64bit
|
||||
#![warn(clippy::empty_line_after_doc_comments)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
//@aux-build:proc_macro_attr.rs:proc-macro
|
||||
// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
|
||||
//@ignore-32bit
|
||||
//@ignore-64bit
|
||||
#![warn(clippy::empty_line_after_outer_attr)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
//@aux-build:proc_macro_attr.rs:proc-macro
|
||||
// Flaky test, see https://github.com/rust-lang/rust/issues/113585.
|
||||
//@ignore-32bit
|
||||
//@ignore-64bit
|
||||
|
||||
#![warn(clippy::needless_arbitrary_self_type)]
|
||||
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::recursive_format_impl)]
|
||||
#![allow(clippy::invisible_characters)]
|
||||
#![allow(cast_ref_to_mut)]
|
||||
#![allow(suspicious_double_ref_op)]
|
||||
#![allow(invalid_nan_comparisons)]
|
||||
#![allow(invalid_reference_casting)]
|
||||
#![allow(drop_bounds)]
|
||||
#![allow(dropping_copy_types)]
|
||||
#![allow(dropping_references)]
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
#![warn(clippy::module_name_repetitions)]
|
||||
#![warn(clippy::recursive_format_impl)]
|
||||
#![warn(clippy::invisible_characters)]
|
||||
#![warn(cast_ref_to_mut)]
|
||||
#![warn(invalid_reference_casting)]
|
||||
#![warn(suspicious_double_ref_op)]
|
||||
#![warn(invalid_nan_comparisons)]
|
||||
#![warn(drop_bounds)]
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::recursive_format_impl)]
|
||||
#![allow(clippy::invisible_characters)]
|
||||
#![allow(cast_ref_to_mut)]
|
||||
#![allow(suspicious_double_ref_op)]
|
||||
#![allow(invalid_nan_comparisons)]
|
||||
#![allow(invalid_reference_casting)]
|
||||
#![allow(drop_bounds)]
|
||||
#![allow(dropping_copy_types)]
|
||||
#![allow(dropping_references)]
|
||||
|
|
|
|||
|
|
@ -174,11 +174,11 @@ error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_ch
|
|||
LL | #![warn(clippy::zero_width_space)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
|
||||
|
||||
error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut`
|
||||
error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
|
||||
--> $DIR/rename.rs:81:9
|
||||
|
|
||||
LL | #![warn(clippy::cast_ref_to_mut)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
|
||||
|
||||
error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
|
||||
--> $DIR/rename.rs:82:9
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@revisions: stack tree
|
||||
//@[tree]compile-flags: -Zmiri-tree-borrows
|
||||
|
||||
#![allow(cast_ref_to_mut)]
|
||||
#![allow(invalid_reference_casting)]
|
||||
|
||||
fn foo(x: &mut i32) -> i32 {
|
||||
*x = 5;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// This should fail even without validation/SB
|
||||
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||
|
||||
#![allow(cast_ref_to_mut)]
|
||||
#![allow(invalid_reference_casting)]
|
||||
|
||||
fn main() {
|
||||
let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ impl <const B: &'static bool> T<B> {
|
|||
unsafe {
|
||||
*(B as *const bool as *mut bool) = false;
|
||||
//~^ ERROR evaluation of constant value failed [E0080]
|
||||
//~| ERROR casting `&T` to `&mut T` is undefined behavior
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/issue-100313.rs:10:13
|
||||
|
|
||||
LL | *(B as *const bool as *mut bool) = false;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(cast_ref_to_mut)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/issue-100313.rs:10:13
|
||||
|
|
||||
|
|
@ -18,11 +10,11 @@ note: inside `T::<&true>::set_false`
|
|||
LL | *(B as *const bool as *mut bool) = false;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: inside `_`
|
||||
--> $DIR/issue-100313.rs:19:5
|
||||
--> $DIR/issue-100313.rs:18:5
|
||||
|
|
||||
LL | x.set_false();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
|||
28
tests/ui/lint/lint-ctypes-113436-1.rs
Normal file
28
tests/ui/lint/lint-ctypes-113436-1.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#![deny(improper_ctypes_definitions)]
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Foo {
|
||||
a: u8,
|
||||
b: (),
|
||||
}
|
||||
|
||||
extern "C" fn foo(x: Foo) -> Foo {
|
||||
todo!()
|
||||
}
|
||||
|
||||
struct NotSafe(u32);
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Bar {
|
||||
a: u8,
|
||||
b: (),
|
||||
c: NotSafe,
|
||||
}
|
||||
|
||||
extern "C" fn bar(x: Bar) -> Bar {
|
||||
//~^ ERROR `extern` fn uses type `NotSafe`, which is not FFI-safe
|
||||
//~^^ ERROR `extern` fn uses type `NotSafe`, which is not FFI-safe
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
35
tests/ui/lint/lint-ctypes-113436-1.stderr
Normal file
35
tests/ui/lint/lint-ctypes-113436-1.stderr
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
error: `extern` fn uses type `NotSafe`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes-113436-1.rs:22:22
|
||||
|
|
||||
LL | extern "C" fn bar(x: Bar) -> Bar {
|
||||
| ^^^ not FFI-safe
|
||||
|
|
||||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes-113436-1.rs:13:1
|
||||
|
|
||||
LL | struct NotSafe(u32);
|
||||
| ^^^^^^^^^^^^^^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-ctypes-113436-1.rs:1:9
|
||||
|
|
||||
LL | #![deny(improper_ctypes_definitions)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `extern` fn uses type `NotSafe`, which is not FFI-safe
|
||||
--> $DIR/lint-ctypes-113436-1.rs:22:30
|
||||
|
|
||||
LL | extern "C" fn bar(x: Bar) -> Bar {
|
||||
| ^^^ not FFI-safe
|
||||
|
|
||||
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
|
||||
= note: this struct has unspecified layout
|
||||
note: the type is defined here
|
||||
--> $DIR/lint-ctypes-113436-1.rs:13:1
|
||||
|
|
||||
LL | struct NotSafe(u32);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
34
tests/ui/lint/lint-ctypes-113436.rs
Normal file
34
tests/ui/lint/lint-ctypes-113436.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// check-pass
|
||||
#![deny(improper_ctypes_definitions)]
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Wrap<T>(T);
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct TransparentWrap<T>(T);
|
||||
|
||||
pub extern "C" fn f() -> Wrap<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
const _: extern "C" fn() -> Wrap<()> = f;
|
||||
|
||||
pub extern "C" fn ff() -> Wrap<Wrap<()>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
const _: extern "C" fn() -> Wrap<Wrap<()>> = ff;
|
||||
|
||||
pub extern "C" fn g() -> TransparentWrap<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
const _: extern "C" fn() -> TransparentWrap<()> = g;
|
||||
|
||||
pub extern "C" fn gg() -> TransparentWrap<TransparentWrap<()>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
const _: extern "C" fn() -> TransparentWrap<TransparentWrap<()>> = gg;
|
||||
|
||||
fn main() {}
|
||||
12
tests/ui/lint/lint-ctypes-113900.rs
Normal file
12
tests/ui/lint/lint-ctypes-113900.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// check-pass
|
||||
|
||||
// Extending `improper_ctypes` to check external-ABI fn-ptrs means that it can encounter
|
||||
// projections which cannot be normalized - unsurprisingly, this shouldn't crash the compiler.
|
||||
|
||||
trait Bar {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
type Foo<T> = extern "C" fn() -> <T as Bar>::Assoc;
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// check-fail
|
||||
|
||||
#![feature(ptr_from_ref)]
|
||||
#![deny(invalid_reference_casting)]
|
||||
|
||||
extern "C" {
|
||||
// N.B., mutability can be easily incorrect in FFI calls -- as
|
||||
|
|
@ -1,61 +1,65 @@
|
|||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:19:9
|
||||
--> $DIR/reference_casting.rs:20:9
|
||||
|
|
||||
LL | (*(a as *const _ as *mut String)).push_str(" world");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(cast_ref_to_mut)]` on by default
|
||||
note: the lint level is defined here
|
||||
--> $DIR/reference_casting.rs:4:9
|
||||
|
|
||||
LL | #![deny(invalid_reference_casting)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:21:9
|
||||
--> $DIR/reference_casting.rs:22:9
|
||||
|
|
||||
LL | *(a as *const _ as *mut _) = String::from("Replaced");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:23:9
|
||||
--> $DIR/reference_casting.rs:24:9
|
||||
|
|
||||
LL | *(a as *const _ as *mut String) += " world";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:25:25
|
||||
--> $DIR/reference_casting.rs:26:25
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32 as *mut i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:27:25
|
||||
--> $DIR/reference_casting.rs:28:25
|
||||
|
|
||||
LL | let _num = &mut *(num as *const i32).cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:29:20
|
||||
--> $DIR/reference_casting.rs:30:20
|
||||
|
|
||||
LL | let _num = *{ num as *const i32 }.cast_mut();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:31:9
|
||||
--> $DIR/reference_casting.rs:32:9
|
||||
|
|
||||
LL | *std::ptr::from_ref(num).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:33:9
|
||||
--> $DIR/reference_casting.rs:34:9
|
||||
|
|
||||
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:35:9
|
||||
--> $DIR/reference_casting.rs:36:9
|
||||
|
|
||||
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
--> $DIR/cast_ref_to_mut.rs:37:9
|
||||
--> $DIR/reference_casting.rs:38:9
|
||||
|
|
||||
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
11
tests/ui/proc-macro/auxiliary/exports_no_mangle.rs
Normal file
11
tests/ui/proc-macro/auxiliary/exports_no_mangle.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// force-host
|
||||
// no-prefer-dynamic
|
||||
#![crate_type="lib"]
|
||||
|
||||
// Issue 111888: this crate (1.) is imported by a proc-macro crate and (2.)
|
||||
// exports a no_mangle function; that combination of acts was broken for some
|
||||
// period of time. See further discussion in the test file that imports this
|
||||
// crate.
|
||||
|
||||
#[no_mangle]
|
||||
pub fn some_no_mangle_function() { }
|
||||
22
tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
Normal file
22
tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// build-pass
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
// aux-build:exports_no_mangle.rs
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
// Issue #111888: this proc-macro crate imports another crate that itself
|
||||
// exports a no_mangle function.
|
||||
//
|
||||
// That combination was broken for a period of time, because:
|
||||
//
|
||||
// In PR #99944 we *stopped* exporting no_mangle symbols from
|
||||
// proc-macro crates. The constructed linker version script still referred
|
||||
// to them, but resolving that discrepancy was left as a FIXME in the code.
|
||||
//
|
||||
// In PR #108017 we started telling the linker to check (via the
|
||||
// `--no-undefined-version` linker invocation flag) that every symbol referenced
|
||||
// in the "linker version script" is actually present in the linker input. So
|
||||
// the unresolved discrepancy from #99944 started surfacing as a compile-time
|
||||
// error.
|
||||
|
||||
extern crate exports_no_mangle;
|
||||
Loading…
Add table
Add a link
Reference in a new issue