Merge pull request #4211 from rust-lang/rustup-2025-02-26
Automatic Rustup
This commit is contained in:
@@ -16,8 +16,8 @@ index 7165c3e48af..968552ad435 100644
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core", public = true }
|
||||
-compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
-compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
|
||||
@@ -460,64 +460,6 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
||||
});
|
||||
}
|
||||
|
||||
sym::simd_fpow => {
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
if !a.layout().ty.is_simd() {
|
||||
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
|
||||
return;
|
||||
}
|
||||
|
||||
simd_pair_for_each_lane(fx, a, b, ret, &|fx, lane_ty, _ret_lane_ty, a_lane, b_lane| {
|
||||
match lane_ty.kind() {
|
||||
ty::Float(FloatTy::F32) => fx.lib_call(
|
||||
"powf",
|
||||
vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
|
||||
vec![AbiParam::new(types::F32)],
|
||||
&[a_lane, b_lane],
|
||||
)[0],
|
||||
ty::Float(FloatTy::F64) => fx.lib_call(
|
||||
"pow",
|
||||
vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
|
||||
vec![AbiParam::new(types::F64)],
|
||||
&[a_lane, b_lane],
|
||||
)[0],
|
||||
_ => unreachable!("{:?}", lane_ty),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sym::simd_fpowi => {
|
||||
intrinsic_args!(fx, args => (a, exp); intrinsic);
|
||||
let exp = exp.load_scalar(fx);
|
||||
|
||||
if !a.layout().ty.is_simd() {
|
||||
report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
|
||||
return;
|
||||
}
|
||||
|
||||
simd_for_each_lane(
|
||||
fx,
|
||||
a,
|
||||
ret,
|
||||
&|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
|
||||
ty::Float(FloatTy::F32) => fx.lib_call(
|
||||
"__powisf2", // compiler-builtins
|
||||
vec![AbiParam::new(types::F32), AbiParam::new(types::I32)],
|
||||
vec![AbiParam::new(types::F32)],
|
||||
&[lane, exp],
|
||||
)[0],
|
||||
ty::Float(FloatTy::F64) => fx.lib_call(
|
||||
"__powidf2", // compiler-builtins
|
||||
vec![AbiParam::new(types::F64), AbiParam::new(types::I32)],
|
||||
vec![AbiParam::new(types::F64)],
|
||||
&[lane, exp],
|
||||
)[0],
|
||||
_ => unreachable!("{:?}", lane_ty),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
sym::simd_fsin
|
||||
| sym::simd_fcos
|
||||
| sym::simd_fexp
|
||||
|
||||
@@ -772,8 +772,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
sym::simd_floor => "floor",
|
||||
sym::simd_fma => "fma",
|
||||
sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary
|
||||
sym::simd_fpowi => "__builtin_powi",
|
||||
sym::simd_fpow => "pow",
|
||||
sym::simd_fsin => "sin",
|
||||
sym::simd_fsqrt => "sqrt",
|
||||
sym::simd_round => "round",
|
||||
@@ -788,24 +786,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
let mut vector_elements = vec![];
|
||||
for i in 0..in_len {
|
||||
let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64);
|
||||
// we have to treat fpowi specially, since fpowi's second argument is always an i32
|
||||
let mut arguments = vec![];
|
||||
if name == sym::simd_fpowi {
|
||||
arguments = vec![
|
||||
bx.extract_element(args[0].immediate(), index).to_rvalue(),
|
||||
args[1].immediate(),
|
||||
];
|
||||
} else {
|
||||
for arg in args {
|
||||
let mut element = bx.extract_element(arg.immediate(), index).to_rvalue();
|
||||
// FIXME: it would probably be better to not have casts here and use the proper
|
||||
// instructions.
|
||||
if let Some(typ) = cast_type {
|
||||
element = bx.context.new_cast(None, element, typ);
|
||||
}
|
||||
arguments.push(element);
|
||||
for arg in args {
|
||||
let mut element = bx.extract_element(arg.immediate(), index).to_rvalue();
|
||||
// FIXME: it would probably be better to not have casts here and use the proper
|
||||
// instructions.
|
||||
if let Some(typ) = cast_type {
|
||||
element = bx.context.new_cast(None, element, typ);
|
||||
}
|
||||
};
|
||||
arguments.push(element);
|
||||
}
|
||||
let mut result = bx.context.new_call(None, function, &arguments);
|
||||
if cast_type.is_some() {
|
||||
result = bx.context.new_cast(None, result, elem_ty);
|
||||
@@ -829,8 +819,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
||||
| sym::simd_floor
|
||||
| sym::simd_fma
|
||||
| sym::simd_relaxed_fma
|
||||
| sym::simd_fpow
|
||||
| sym::simd_fpowi
|
||||
| sym::simd_fsin
|
||||
| sym::simd_fsqrt
|
||||
| sym::simd_round
|
||||
|
||||
@@ -1581,8 +1581,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
|
||||
sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
|
||||
@@ -1615,8 +1613,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
| sym::simd_flog
|
||||
| sym::simd_floor
|
||||
| sym::simd_fma
|
||||
| sym::simd_fpow
|
||||
| sym::simd_fpowi
|
||||
| sym::simd_fsin
|
||||
| sym::simd_fsqrt
|
||||
| sym::simd_relaxed_fma
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::env;
|
||||
use std::fmt::{Display, from_fn};
|
||||
use std::num::ParseIntError;
|
||||
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::spec::Target;
|
||||
|
||||
@@ -26,6 +27,89 @@ pub(super) fn macho_platform(target: &Target) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add relocation and section data needed for a symbol to be considered
|
||||
/// undefined by ld64.
|
||||
///
|
||||
/// The relocation must be valid, and hence must point to a valid piece of
|
||||
/// machine code, and hence this is unfortunately very architecture-specific.
|
||||
///
|
||||
///
|
||||
/// # New architectures
|
||||
///
|
||||
/// The values here are basically the same as emitted by the following program:
|
||||
///
|
||||
/// ```c
|
||||
/// // clang -c foo.c -target $CLANG_TARGET
|
||||
/// void foo(void);
|
||||
///
|
||||
/// extern int bar;
|
||||
///
|
||||
/// void* foobar[2] = {
|
||||
/// (void*)foo,
|
||||
/// (void*)&bar,
|
||||
/// // ...
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Can be inspected with:
|
||||
/// ```console
|
||||
/// objdump --macho --reloc foo.o
|
||||
/// objdump --macho --full-contents foo.o
|
||||
/// ```
|
||||
pub(super) fn add_data_and_relocation(
|
||||
file: &mut object::write::Object<'_>,
|
||||
section: object::write::SectionId,
|
||||
symbol: object::write::SymbolId,
|
||||
target: &Target,
|
||||
kind: SymbolExportKind,
|
||||
) -> object::write::Result<()> {
|
||||
let authenticated_pointer =
|
||||
kind == SymbolExportKind::Text && target.llvm_target.starts_with("arm64e");
|
||||
|
||||
let data: &[u8] = match target.pointer_width {
|
||||
_ if authenticated_pointer => &[0, 0, 0, 0, 0, 0, 0, 0x80],
|
||||
32 => &[0; 4],
|
||||
64 => &[0; 8],
|
||||
pointer_width => unimplemented!("unsupported Apple pointer width {pointer_width:?}"),
|
||||
};
|
||||
|
||||
if target.arch == "x86_64" {
|
||||
// Force alignment for the entire section to be 16 on x86_64.
|
||||
file.section_mut(section).append_data(&[], 16);
|
||||
} else {
|
||||
// Elsewhere, the section alignment is the same as the pointer width.
|
||||
file.section_mut(section).append_data(&[], target.pointer_width as u64);
|
||||
}
|
||||
|
||||
let offset = file.section_mut(section).append_data(data, data.len() as u64);
|
||||
|
||||
let flags = if authenticated_pointer {
|
||||
object::write::RelocationFlags::MachO {
|
||||
r_type: object::macho::ARM64_RELOC_AUTHENTICATED_POINTER,
|
||||
r_pcrel: false,
|
||||
r_length: 3,
|
||||
}
|
||||
} else if target.arch == "arm" {
|
||||
// FIXME(madsmtm): Remove once `object` supports 32-bit ARM relocations:
|
||||
// https://github.com/gimli-rs/object/pull/757
|
||||
object::write::RelocationFlags::MachO {
|
||||
r_type: object::macho::ARM_RELOC_VANILLA,
|
||||
r_pcrel: false,
|
||||
r_length: 2,
|
||||
}
|
||||
} else {
|
||||
object::write::RelocationFlags::Generic {
|
||||
kind: object::RelocationKind::Absolute,
|
||||
encoding: object::RelocationEncoding::Generic,
|
||||
size: target.pointer_width as u8,
|
||||
}
|
||||
};
|
||||
|
||||
file.add_relocation(section, object::write::Relocation { offset, addend: 0, symbol, flags })?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deployment target or SDK version.
|
||||
///
|
||||
/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
|
||||
|
||||
@@ -2058,8 +2058,8 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
|
||||
/// linker, and since they never participate in the linking, using `KEEP` in the linker scripts
|
||||
/// can't keep them either. This causes #47384.
|
||||
///
|
||||
/// To keep them around, we could use `--whole-archive` and equivalents to force rlib to
|
||||
/// participate in linking like object files, but this proves to be expensive (#93791). Therefore
|
||||
/// To keep them around, we could use `--whole-archive`, `-force_load` and equivalents to force rlib
|
||||
/// to participate in linking like object files, but this proves to be expensive (#93791). Therefore
|
||||
/// we instead just introduce an undefined reference to them. This could be done by `-u` command
|
||||
/// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only
|
||||
/// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections`
|
||||
@@ -2101,8 +2101,20 @@ fn add_linked_symbol_object(
|
||||
file.set_mangling(object::write::Mangling::None);
|
||||
}
|
||||
|
||||
// ld64 requires a relocation to load undefined symbols, see below.
|
||||
// Not strictly needed if linking with lld, but might as well do it there too.
|
||||
let ld64_section_helper = if file.format() == object::BinaryFormat::MachO {
|
||||
Some(file.add_section(
|
||||
file.segment_name(object::write::StandardSegment::Data).to_vec(),
|
||||
"__data".into(),
|
||||
object::SectionKind::Data,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for (sym, kind) in symbols.iter() {
|
||||
file.add_symbol(object::write::Symbol {
|
||||
let symbol = file.add_symbol(object::write::Symbol {
|
||||
name: sym.clone().into(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
@@ -2116,6 +2128,47 @@ fn add_linked_symbol_object(
|
||||
section: object::write::SymbolSection::Undefined,
|
||||
flags: object::SymbolFlags::None,
|
||||
});
|
||||
|
||||
// The linker shipped with Apple's Xcode, ld64, works a bit differently from other linkers.
|
||||
//
|
||||
// Code-wise, the relevant parts of ld64 are roughly:
|
||||
// 1. Find the `ArchiveLoadMode` based on commandline options, default to `parseObjects`.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.cpp#L924-L932
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.h#L55
|
||||
//
|
||||
// 2. Read the archive table of contents (__.SYMDEF file).
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L294-L325
|
||||
//
|
||||
// 3. Begin linking by loading "atoms" from input files.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/doc/design/linker.html
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1349
|
||||
//
|
||||
// a. Directly specified object files (`.o`) are parsed immediately.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L4611-L4627
|
||||
//
|
||||
// - Undefined symbols are not atoms (`n_value > 0` denotes a common symbol).
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L2455-L2468
|
||||
// https://maskray.me/blog/2022-02-06-all-about-common-symbols
|
||||
//
|
||||
// - Relocations/fixups are atoms.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ce6341ae966b3451aa54eeb049f2be865afbd578/src/ld/parsers/macho_relocatable_file.cpp#L2088-L2114
|
||||
//
|
||||
// b. Archives are not parsed yet.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L467-L577
|
||||
//
|
||||
// 4. When a symbol is needed by an atom, parse the object file that contains the symbol.
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1417-L1491
|
||||
// https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L579-L597
|
||||
//
|
||||
// All of the steps above are fairly similar to other linkers, except that **it completely
|
||||
// ignores undefined symbols**.
|
||||
//
|
||||
// So to make this trick work on ld64, we need to do something else to load the relevant
|
||||
// object files. We do this by inserting a relocation (fixup) for each symbol.
|
||||
if let Some(section) = ld64_section_helper {
|
||||
apple::add_data_and_relocation(&mut file, section, symbol, &sess.target, *kind)
|
||||
.expect("failed adding relocation");
|
||||
}
|
||||
}
|
||||
|
||||
let path = tmpdir.join("symbols.o");
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#![feature(box_into_inner)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(error_reporter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(negative_impls)]
|
||||
|
||||
@@ -1011,7 +1011,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"#![rustc_force_inline] forces a free function to be inlined"
|
||||
"#[rustc_force_inline] forces a free function to be inlined"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
@@ -605,6 +605,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
|
||||
hir_analysis_unused_generic_parameter_ty_alias_help =
|
||||
consider removing `{$param_name}` or referring to it in the body of the type alias
|
||||
|
||||
hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type
|
||||
|
||||
hir_analysis_value_of_associated_struct_already_specified =
|
||||
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
|
||||
.label = re-bound here
|
||||
|
||||
@@ -992,6 +992,32 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
|
||||
let trait_def = tcx.trait_def(trait_ref.def_id);
|
||||
|
||||
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
|
||||
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
|
||||
let param_env = tcx.param_env(impl_id);
|
||||
|
||||
let self_is_guaranteed_unsized = match tcx
|
||||
.struct_tail_raw(
|
||||
trait_ref.self_ty(),
|
||||
|ty| {
|
||||
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
|
||||
Ty::new_error_with_message(
|
||||
tcx,
|
||||
tcx.def_span(impl_id),
|
||||
"struct tail should be computable",
|
||||
)
|
||||
})
|
||||
},
|
||||
|| (),
|
||||
)
|
||||
.kind()
|
||||
{
|
||||
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
for &impl_item in impl_item_refs {
|
||||
let ty_impl_item = tcx.associated_item(impl_item);
|
||||
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
|
||||
@@ -1021,6 +1047,15 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
|
||||
tcx.emit_node_span_lint(
|
||||
rustc_lint_defs::builtin::DEAD_CODE,
|
||||
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
|
||||
tcx.def_span(ty_impl_item.def_id),
|
||||
errors::UselessImplItem,
|
||||
)
|
||||
}
|
||||
|
||||
check_specialization_validity(
|
||||
tcx,
|
||||
trait_def,
|
||||
@@ -1044,7 +1079,11 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
.as_ref()
|
||||
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
|
||||
|
||||
if !is_implemented && tcx.defaultness(impl_id).is_final() {
|
||||
if !is_implemented
|
||||
&& tcx.defaultness(impl_id).is_final()
|
||||
// unsized types don't need to implement methods that have `Self: Sized` bounds.
|
||||
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
|
||||
{
|
||||
missing_items.push(tcx.associated_item(trait_item_id));
|
||||
}
|
||||
|
||||
|
||||
@@ -645,7 +645,6 @@ pub fn check_intrinsic_type(
|
||||
| sym::simd_xor
|
||||
| sym::simd_fmin
|
||||
| sym::simd_fmax
|
||||
| sym::simd_fpow
|
||||
| sym::simd_saturating_add
|
||||
| sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)),
|
||||
sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)),
|
||||
@@ -668,7 +667,6 @@ pub fn check_intrinsic_type(
|
||||
| sym::simd_floor
|
||||
| sym::simd_round
|
||||
| sym::simd_trunc => (1, 0, vec![param(0)], param(0)),
|
||||
sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)),
|
||||
sym::simd_fma | sym::simd_relaxed_fma => {
|
||||
(1, 0, vec![param(0), param(0), param(0)], param(0))
|
||||
}
|
||||
|
||||
@@ -908,6 +908,10 @@ pub(crate) enum ImplNotMarkedDefault {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_useless_impl_item)]
|
||||
pub(crate) struct UselessImplItem;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_missing_trait_item, code = E0046)]
|
||||
pub(crate) struct MissingTraitItem {
|
||||
|
||||
@@ -23,7 +23,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use rustc_span::{ExpnKind, Ident, MacroKind, Span, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
@@ -1365,6 +1365,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.param_env,
|
||||
ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]),
|
||||
))
|
||||
&& !expr
|
||||
.span
|
||||
.macro_backtrace()
|
||||
.any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
|
||||
{
|
||||
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||
|
||||
@@ -1380,10 +1384,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
|
||||
}
|
||||
diag.multipart_suggestion(
|
||||
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::iter::repeat;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use hir::intravisit::Visitor;
|
||||
use hir::intravisit::{self, Visitor};
|
||||
use rustc_ast::Recovered;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
|
||||
@@ -9,6 +9,7 @@ use rustc_errors::{
|
||||
use rustc_hir::{self as hir, HirIdSet};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, LintId};
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
@@ -160,7 +161,7 @@ impl IfLetRescope {
|
||||
let lifetime_end = source_map.end_point(conseq.span);
|
||||
|
||||
if let ControlFlow::Break(significant_dropper) =
|
||||
(FindSignificantDropper { cx }).visit_expr(init)
|
||||
(FindSignificantDropper { cx }).check_if_let_scrutinee(init)
|
||||
{
|
||||
first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id)));
|
||||
significant_droppers.push(significant_dropper);
|
||||
@@ -363,96 +364,97 @@ enum SingleArmMatchBegin {
|
||||
WithoutOpenBracket(Span),
|
||||
}
|
||||
|
||||
struct FindSignificantDropper<'tcx, 'a> {
|
||||
struct FindSignificantDropper<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
|
||||
type Result = ControlFlow<Span>;
|
||||
impl<'tcx> FindSignificantDropper<'_, 'tcx> {
|
||||
/// Check the scrutinee of an `if let` to see if it promotes any temporary values
|
||||
/// that would change drop order in edition 2024. Specifically, it checks the value
|
||||
/// of the scrutinee itself, and also recurses into the expression to find any ref
|
||||
/// exprs (or autoref) which would promote temporaries that would be scoped to the
|
||||
/// end of this `if`.
|
||||
fn check_if_let_scrutinee(&mut self, init: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
|
||||
self.check_promoted_temp_with_drop(init)?;
|
||||
self.visit_expr(init)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
if self
|
||||
/// Check that an expression is not a promoted temporary with a significant
|
||||
/// drop impl.
|
||||
///
|
||||
/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
|
||||
/// or is the scrutinee of the `if let`, *and* the expression is not a place
|
||||
/// expr, and it has a significant drop.
|
||||
fn check_promoted_temp_with_drop(&self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
|
||||
if !expr.is_place_expr(|base| {
|
||||
self.cx
|
||||
.typeck_results()
|
||||
.adjustments()
|
||||
.get(base.hir_id)
|
||||
.is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
|
||||
}) && self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.expr_ty(expr)
|
||||
.has_significant_drop(self.cx.tcx, self.cx.typing_env())
|
||||
{
|
||||
return ControlFlow::Break(expr.span);
|
||||
}
|
||||
match expr.kind {
|
||||
hir::ExprKind::ConstBlock(_)
|
||||
| hir::ExprKind::Lit(_)
|
||||
| hir::ExprKind::Path(_)
|
||||
| hir::ExprKind::Assign(_, _, _)
|
||||
| hir::ExprKind::AssignOp(_, _, _)
|
||||
| hir::ExprKind::Break(_, _)
|
||||
| hir::ExprKind::Continue(_)
|
||||
| hir::ExprKind::Ret(_)
|
||||
| hir::ExprKind::Become(_)
|
||||
| hir::ExprKind::InlineAsm(_)
|
||||
| hir::ExprKind::OffsetOf(_, _)
|
||||
| hir::ExprKind::Repeat(_, _)
|
||||
| hir::ExprKind::Err(_)
|
||||
| hir::ExprKind::Struct(_, _, _)
|
||||
| hir::ExprKind::Closure(_)
|
||||
| hir::ExprKind::Block(_, _)
|
||||
| hir::ExprKind::DropTemps(_)
|
||||
| hir::ExprKind::Loop(_, _, _, _) => ControlFlow::Continue(()),
|
||||
|
||||
hir::ExprKind::Tup(exprs) | hir::ExprKind::Array(exprs) => {
|
||||
for expr in exprs {
|
||||
self.visit_expr(expr)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
hir::ExprKind::Call(callee, args) => {
|
||||
self.visit_expr(callee)?;
|
||||
for expr in args {
|
||||
self.visit_expr(expr)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
hir::ExprKind::MethodCall(_, receiver, args, _) => {
|
||||
self.visit_expr(receiver)?;
|
||||
for expr in args {
|
||||
self.visit_expr(expr)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
hir::ExprKind::Index(left, right, _) | hir::ExprKind::Binary(_, left, right) => {
|
||||
self.visit_expr(left)?;
|
||||
self.visit_expr(right)
|
||||
}
|
||||
hir::ExprKind::Unary(_, expr)
|
||||
| hir::ExprKind::Cast(expr, _)
|
||||
| hir::ExprKind::Type(expr, _)
|
||||
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
|
||||
| hir::ExprKind::Yield(expr, _)
|
||||
| hir::ExprKind::AddrOf(_, _, expr)
|
||||
| hir::ExprKind::Match(expr, _, _)
|
||||
| hir::ExprKind::Field(expr, _)
|
||||
| hir::ExprKind::Let(&hir::LetExpr {
|
||||
init: expr,
|
||||
span: _,
|
||||
pat: _,
|
||||
ty: _,
|
||||
recovered: Recovered::No,
|
||||
}) => self.visit_expr(expr),
|
||||
hir::ExprKind::Let(_) => ControlFlow::Continue(()),
|
||||
|
||||
hir::ExprKind::If(cond, _, _) => {
|
||||
if let hir::ExprKind::Let(hir::LetExpr {
|
||||
init,
|
||||
span: _,
|
||||
pat: _,
|
||||
ty: _,
|
||||
recovered: Recovered::No,
|
||||
}) = cond.kind
|
||||
{
|
||||
self.visit_expr(init)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
ControlFlow::Break(expr.span)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindSignificantDropper<'_, 'tcx> {
|
||||
type Result = ControlFlow<Span>;
|
||||
|
||||
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result {
|
||||
// Blocks introduce temporary terminating scope for all of its
|
||||
// statements, so just visit the tail expr, skipping over any
|
||||
// statements. This prevents false positives like `{ let x = &Drop; }`.
|
||||
if let Some(expr) = b.expr { self.visit_expr(expr) } else { ControlFlow::Continue(()) }
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||
// Check for promoted temporaries from autoref, e.g.
|
||||
// `if let None = TypeWithDrop.as_ref() {} else {}`
|
||||
// where `fn as_ref(&self) -> Option<...>`.
|
||||
for adj in self.cx.typeck_results().expr_adjustments(expr) {
|
||||
match adj.kind {
|
||||
// Skip when we hit the first deref expr.
|
||||
Adjust::Deref(_) => break,
|
||||
Adjust::Borrow(_) => {
|
||||
self.check_promoted_temp_with_drop(expr)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match expr.kind {
|
||||
// Account for cases like `if let None = Some(&Drop) {} else {}`.
|
||||
hir::ExprKind::AddrOf(_, _, expr) => {
|
||||
self.check_promoted_temp_with_drop(expr)?;
|
||||
intravisit::walk_expr(self, expr)
|
||||
}
|
||||
// `(Drop, ()).1` introduces a temporary and then moves out of
|
||||
// part of it, therefore we should check it for temporaries.
|
||||
// FIXME: This may have false positives if we move the part
|
||||
// that actually has drop, but oh well.
|
||||
hir::ExprKind::Index(expr, _, _) | hir::ExprKind::Field(expr, _) => {
|
||||
self.check_promoted_temp_with_drop(expr)?;
|
||||
intravisit::walk_expr(self, expr)
|
||||
}
|
||||
// If always introduces a temporary terminating scope for its cond and arms,
|
||||
// so don't visit them.
|
||||
hir::ExprKind::If(..) => ControlFlow::Continue(()),
|
||||
// Match introduces temporary terminating scopes for arms, so don't visit
|
||||
// them, and only visit the scrutinee to account for cases like:
|
||||
// `if let None = match &Drop { _ => Some(1) } {} else {}`.
|
||||
hir::ExprKind::Match(scrut, _, _) => self.visit_expr(scrut),
|
||||
// Self explanatory.
|
||||
hir::ExprKind::DropTemps(_) => ControlFlow::Continue(()),
|
||||
// Otherwise, walk into the expr's parts.
|
||||
_ => intravisit::walk_expr(self, expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#![feature(array_windows)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(let_chains)]
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#![feature(coroutines)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(error_iter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#![feature(decl_macro)]
|
||||
#![feature(discriminant_kind)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(intra_doc_pointers)]
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(let_chains)]
|
||||
|
||||
@@ -68,9 +68,7 @@ cfg_match! {
|
||||
|
||||
const CHUNK_SIZE: usize = 16;
|
||||
|
||||
let src_bytes = src.as_bytes();
|
||||
|
||||
let chunk_count = src.len() / CHUNK_SIZE;
|
||||
let (chunks, tail) = src.as_bytes().as_chunks::<CHUNK_SIZE>();
|
||||
|
||||
// This variable keeps track of where we should start decoding a
|
||||
// chunk. If a multi-byte character spans across chunk boundaries,
|
||||
@@ -78,11 +76,10 @@ cfg_match! {
|
||||
// handled it.
|
||||
let mut intra_chunk_offset = 0;
|
||||
|
||||
for chunk_index in 0..chunk_count {
|
||||
let ptr = src_bytes.as_ptr() as *const __m128i;
|
||||
for (chunk_index, chunk) in chunks.iter().enumerate() {
|
||||
// We don't know if the pointer is aligned to 16 bytes, so we
|
||||
// use `loadu`, which supports unaligned loading.
|
||||
let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) };
|
||||
let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) };
|
||||
|
||||
// For character in the chunk, see if its byte value is < 0, which
|
||||
// indicates that it's part of a UTF-8 char.
|
||||
@@ -123,7 +120,7 @@ cfg_match! {
|
||||
}
|
||||
|
||||
// There might still be a tail left to analyze
|
||||
let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
|
||||
let tail_start = src.len() - tail.len() + intra_chunk_offset;
|
||||
if tail_start < src.len() {
|
||||
analyze_source_file_generic(
|
||||
&src[tail_start..],
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#![feature(round_char_boundary)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(slice_as_chunks)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
||||
@@ -1877,8 +1877,6 @@ symbols! {
|
||||
simd_fma,
|
||||
simd_fmax,
|
||||
simd_fmin,
|
||||
simd_fpow,
|
||||
simd_fpowi,
|
||||
simd_fsin,
|
||||
simd_fsqrt,
|
||||
simd_gather,
|
||||
|
||||
@@ -2914,20 +2914,35 @@ impl Target {
|
||||
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
|
||||
// `__stdcall` only applies on x86 and on non-variadic functions:
|
||||
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
|
||||
System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
|
||||
Stdcall { unwind }
|
||||
System { unwind } => {
|
||||
if self.is_like_windows && self.arch == "x86" && !c_variadic {
|
||||
Stdcall { unwind }
|
||||
} else {
|
||||
C { unwind }
|
||||
}
|
||||
}
|
||||
|
||||
EfiApi => {
|
||||
if self.arch == "arm" {
|
||||
Aapcs { unwind: false }
|
||||
} else if self.arch == "x86_64" {
|
||||
Win64 { unwind: false }
|
||||
} else {
|
||||
C { unwind: false }
|
||||
}
|
||||
}
|
||||
System { unwind } => C { unwind },
|
||||
EfiApi if self.arch == "arm" => Aapcs { unwind: false },
|
||||
EfiApi if self.arch == "x86_64" => Win64 { unwind: false },
|
||||
EfiApi => C { unwind: false },
|
||||
|
||||
// See commentary in `is_abi_supported`.
|
||||
Stdcall { .. } | Thiscall { .. } if self.arch == "x86" => abi,
|
||||
Stdcall { unwind } | Thiscall { unwind } => C { unwind },
|
||||
Fastcall { .. } if self.arch == "x86" => abi,
|
||||
Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
|
||||
Fastcall { unwind } | Vectorcall { unwind } => C { unwind },
|
||||
Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => {
|
||||
if self.arch == "x86" { abi } else { C { unwind } }
|
||||
}
|
||||
Vectorcall { unwind } => {
|
||||
if ["x86", "x86_64"].contains(&&*self.arch) {
|
||||
abi
|
||||
} else {
|
||||
C { unwind }
|
||||
}
|
||||
}
|
||||
|
||||
// The Windows x64 calling convention we use for `extern "Rust"`
|
||||
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(cfg_version)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(iterator_try_reduce)]
|
||||
|
||||
@@ -131,8 +131,6 @@ pub struct TraitPredicate<I: Interner> {
|
||||
/// If polarity is Negative: we are proving that a negative impl of this trait
|
||||
/// exists. (Note that coherence also checks whether negative impls of supertraits
|
||||
/// exist via a series of predicates.)
|
||||
///
|
||||
/// If polarity is Reserved: that's a bug.
|
||||
pub polarity: PredicatePolarity,
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.147"
|
||||
version = "0.1.148"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170335a76fbcba350c3ea795c15df3b2c02934e35e502e82c4dd7837d4d0161"
|
||||
checksum = "26137996631d90d2727b905b480fdcf8c4479fdbce7afd7f8e3796d689b33cc2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
||||
@@ -12,7 +12,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core", public = true }
|
||||
compiler_builtins = { version = "=0.1.147", features = ['rustc-dep-of-std'] }
|
||||
compiler_builtins = { version = "=0.1.148", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
|
||||
|
||||
@@ -289,7 +289,7 @@ impl<K: Clone, V: Clone, A: Allocator + Clone> Clone for BTreeMap<K, V, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal functionality for `BTreeSet`.
|
||||
// Internal functionality for `BTreeSet`.
|
||||
impl<K, A: Allocator + Clone> BTreeMap<K, SetValZST, A> {
|
||||
pub(super) fn replace(&mut self, key: K) -> Option<K>
|
||||
where
|
||||
|
||||
@@ -1140,7 +1140,6 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
||||
/// Splitting a list into evens and odds, reusing the original list:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(extract_if)]
|
||||
/// use std::collections::LinkedList;
|
||||
///
|
||||
/// let mut numbers: LinkedList<u32> = LinkedList::new();
|
||||
@@ -1152,7 +1151,7 @@ impl<T, A: Allocator> LinkedList<T, A> {
|
||||
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]);
|
||||
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
|
||||
/// ```
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
@@ -1932,7 +1931,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> {
|
||||
}
|
||||
|
||||
/// An iterator produced by calling `extract_if` on LinkedList.
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct ExtractIf<
|
||||
'a,
|
||||
@@ -1947,7 +1946,7 @@ pub struct ExtractIf<
|
||||
old_len: usize,
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
@@ -1976,7 +1975,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("ExtractIf").field(&self.list).finish()
|
||||
|
||||
@@ -966,11 +966,8 @@ impl String {
|
||||
/// This is highly unsafe, due to the number of invariants that aren't
|
||||
/// checked:
|
||||
///
|
||||
/// * The memory at `buf` needs to have been previously allocated by the
|
||||
/// same allocator the standard library uses, with a required alignment of exactly 1.
|
||||
/// * `length` needs to be less than or equal to `capacity`.
|
||||
/// * `capacity` needs to be the correct value.
|
||||
/// * The first `length` bytes at `buf` need to be valid UTF-8.
|
||||
/// * all safety requirements for [`Vec::<u8>::from_raw_parts`].
|
||||
/// * all safety requirements for [`String::from_utf8_unchecked`].
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal data structures. For example, it is normally **not** safe to
|
||||
|
||||
@@ -12,12 +12,10 @@ use crate::alloc::{Allocator, Global};
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(extract_if)]
|
||||
///
|
||||
/// let mut v = vec![0, 1, 2];
|
||||
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
|
||||
/// ```
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[derive(Debug)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct ExtractIf<
|
||||
@@ -59,7 +57,7 @@ impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
@@ -95,7 +93,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
||||
@@ -66,7 +66,7 @@ use core::ptr::{self, NonNull};
|
||||
use core::slice::{self, SliceIndex};
|
||||
use core::{fmt, intrinsics};
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use self::extract_if::ExtractIf;
|
||||
use crate::alloc::{Allocator, Global};
|
||||
use crate::borrow::{Cow, ToOwned};
|
||||
@@ -355,11 +355,20 @@ mod spec_extend;
|
||||
/// and it may prove desirable to use a non-constant growth factor. Whatever
|
||||
/// strategy is used will of course guarantee *O*(1) amortized [`push`].
|
||||
///
|
||||
/// `vec![x; n]`, `vec![a, b, c, d]`, and
|
||||
/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
|
||||
/// with at least the requested capacity. If <code>[len] == [capacity]</code>,
|
||||
/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
|
||||
/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
|
||||
/// It is guaranteed, in order to respect the intentions of the programmer, that
|
||||
/// all of `vec![e_1, e_2, ..., e_n]`, `vec![x; n]`, and [`Vec::with_capacity(n)`] produce a `Vec`
|
||||
/// that requests an allocation of the exact size needed for precisely `n` elements from the allocator,
|
||||
/// and no other size (such as, for example: a size rounded up to the nearest power of 2).
|
||||
/// The allocator will return an allocation that is at least as large as requested, but it may be larger.
|
||||
///
|
||||
/// It is guaranteed that the [`Vec::capacity`] method returns a value that is at least the requested capacity
|
||||
/// and not more than the allocated capacity.
|
||||
///
|
||||
/// The method [`Vec::shrink_to_fit`] will attempt to discard excess capacity an allocator has given to a `Vec`.
|
||||
/// If <code>[len] == [capacity]</code>, then a `Vec<T>` can be converted
|
||||
/// to and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
|
||||
/// `Vec` exploits this fact as much as reasonable when implementing common conversions
|
||||
/// such as [`into_boxed_slice`].
|
||||
///
|
||||
/// `Vec` will not specifically overwrite any data that is removed from it,
|
||||
/// but also won't specifically preserve it. Its uninitialized memory is
|
||||
@@ -383,14 +392,17 @@ mod spec_extend;
|
||||
/// [`shrink_to`]: Vec::shrink_to
|
||||
/// [capacity]: Vec::capacity
|
||||
/// [`capacity`]: Vec::capacity
|
||||
/// [`Vec::capacity`]: Vec::capacity
|
||||
/// [mem::size_of::\<T>]: core::mem::size_of
|
||||
/// [len]: Vec::len
|
||||
/// [`len`]: Vec::len
|
||||
/// [`push`]: Vec::push
|
||||
/// [`insert`]: Vec::insert
|
||||
/// [`reserve`]: Vec::reserve
|
||||
/// [`Vec::with_capacity(n)`]: Vec::with_capacity
|
||||
/// [`MaybeUninit`]: core::mem::MaybeUninit
|
||||
/// [owned slice]: Box
|
||||
/// [`into_boxed_slice`]: Vec::into_boxed_slice
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")]
|
||||
#[rustc_insignificant_dtor]
|
||||
@@ -3684,7 +3696,6 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// Splitting an array into evens and odds, reusing the original allocation:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(extract_if)]
|
||||
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
|
||||
///
|
||||
/// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
@@ -3697,13 +3708,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// Using the range argument to only process a part of the vector:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(extract_if)]
|
||||
/// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2];
|
||||
/// let ones = items.extract_if(7.., |x| *x == 1).collect::<Vec<_>>();
|
||||
/// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]);
|
||||
/// assert_eq!(ones.len(), 3);
|
||||
/// ```
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#![feature(cow_is_borrowed)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(downcast_unchecked)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(hashmap_internals)]
|
||||
#![feature(linked_list_cursors)]
|
||||
@@ -29,7 +28,6 @@
|
||||
#![feature(string_remove_matches)]
|
||||
#![feature(const_btree_len)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_str_from_utf8)]
|
||||
#![feature(panic_update_hook)]
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
#![feature(test)]
|
||||
|
||||
@@ -1041,7 +1041,6 @@ impl<T> MaybeUninit<T> {
|
||||
|
||||
/// Deprecated version of [`slice::assume_init_ref`].
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[deprecated(
|
||||
note = "replaced by inherent assume_init_ref method; will eventually be removed",
|
||||
since = "1.83.0"
|
||||
@@ -1053,7 +1052,6 @@ impl<T> MaybeUninit<T> {
|
||||
|
||||
/// Deprecated version of [`slice::assume_init_mut`].
|
||||
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
|
||||
#[deprecated(
|
||||
note = "replaced by inherent assume_init_mut method; will eventually be removed",
|
||||
since = "1.83.0"
|
||||
@@ -1326,7 +1324,6 @@ impl<T> [MaybeUninit<T>] {
|
||||
///
|
||||
/// [`write_clone_of_slice`]: slice::write_clone_of_slice
|
||||
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
|
||||
#[rustc_const_unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
|
||||
pub const fn write_copy_of_slice(&mut self, src: &[T]) -> &mut [T]
|
||||
where
|
||||
T: Copy,
|
||||
|
||||
@@ -956,7 +956,6 @@ impl<T> [T] {
|
||||
/// [`swap`]: slice::swap
|
||||
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
|
||||
#[rustc_const_unstable(feature = "slice_swap_unchecked", issue = "88539")]
|
||||
pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
|
||||
assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
@@ -3734,6 +3733,7 @@ impl<T> [T] {
|
||||
#[inline]
|
||||
#[stable(feature = "copy_from_slice", since = "1.9.0")]
|
||||
#[rustc_const_unstable(feature = "const_copy_from_slice", issue = "131415")]
|
||||
#[rustc_const_stable_indirect]
|
||||
#[track_caller]
|
||||
pub const fn copy_from_slice(&mut self, src: &[T])
|
||||
where
|
||||
|
||||
@@ -126,7 +126,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
|
||||
/// See the docs for [`Utf8Error`] for more details on the kinds of
|
||||
/// errors that can be returned.
|
||||
#[stable(feature = "str_mut_extras", since = "1.20.0")]
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
#[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_diagnostic_item = "str_from_utf8_mut"]
|
||||
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
|
||||
// FIXME(const-hack): This should use `?` again, once it's `const`
|
||||
|
||||
@@ -265,7 +265,7 @@ impl str {
|
||||
/// See the docs for [`Utf8Error`] for more details on the kinds of
|
||||
/// errors that can be returned.
|
||||
#[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
#[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[rustc_diagnostic_item = "str_inherent_from_utf8_mut"]
|
||||
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
|
||||
converts::from_utf8_mut(v)
|
||||
|
||||
@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
|
||||
panic_unwind = { path = "../panic_unwind", optional = true }
|
||||
panic_abort = { path = "../panic_abort" }
|
||||
core = { path = "../core", public = true }
|
||||
compiler_builtins = { version = "=0.1.147" }
|
||||
compiler_builtins = { version = "=0.1.148" }
|
||||
unwind = { path = "../unwind" }
|
||||
hashbrown = { version = "0.15", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
|
||||
@@ -656,7 +656,6 @@ impl<K, V, S> HashMap<K, V, S> {
|
||||
/// Splitting a map into even and odd keys, reusing the original map:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_extract_if)]
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
|
||||
@@ -672,7 +671,7 @@ impl<K, V, S> HashMap<K, V, S> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
|
||||
where
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
@@ -1722,8 +1721,6 @@ impl<'a, K, V> Drain<'a, K, V> {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_extract_if)]
|
||||
///
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut map = HashMap::from([
|
||||
@@ -1731,7 +1728,7 @@ impl<'a, K, V> Drain<'a, K, V> {
|
||||
/// ]);
|
||||
/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
|
||||
/// ```
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct ExtractIf<'a, K, V, F>
|
||||
where
|
||||
@@ -2746,7 +2743,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
|
||||
where
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
@@ -2763,10 +2760,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
|
||||
where
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
|
||||
@@ -293,7 +293,6 @@ impl<T, S> HashSet<T, S> {
|
||||
/// Splitting a set into even and odd values, reusing the original set:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_extract_if)]
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut set: HashSet<i32> = (0..8).collect();
|
||||
@@ -309,7 +308,7 @@ impl<T, S> HashSet<T, S> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[rustc_lint_query_instability]
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
@@ -1385,15 +1384,13 @@ pub struct Drain<'a, K: 'a> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(hash_extract_if)]
|
||||
///
|
||||
/// use std::collections::HashSet;
|
||||
///
|
||||
/// let mut a = HashSet::from([1, 2, 3]);
|
||||
///
|
||||
/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
|
||||
/// ```
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub struct ExtractIf<'a, K, F>
|
||||
where
|
||||
F: FnMut(&K) -> bool,
|
||||
@@ -1676,7 +1673,7 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<K, F> Iterator for ExtractIf<'_, K, F>
|
||||
where
|
||||
F: FnMut(&K) -> bool,
|
||||
@@ -1693,10 +1690,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
|
||||
|
||||
#[unstable(feature = "hash_extract_if", issue = "59618")]
|
||||
#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
|
||||
where
|
||||
F: FnMut(&K) -> bool,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::abi;
|
||||
use super::abi::fileno;
|
||||
use crate::io;
|
||||
use crate::io::{self, BorrowedCursor};
|
||||
|
||||
pub struct Stdin;
|
||||
pub struct Stdout;
|
||||
@@ -16,6 +16,14 @@ impl io::Read for Stdin {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
Ok(unsafe { abi::sys_read(fileno::STDIN, buf.as_mut_ptr(), buf.len()) })
|
||||
}
|
||||
|
||||
fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
unsafe {
|
||||
let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity());
|
||||
buf.advance_unchecked(n);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
|
||||
@@ -88,9 +88,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.0"
|
||||
version = "1.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
|
||||
checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
@@ -37,7 +37,9 @@ test = false
|
||||
# Most of the time updating these dependencies requires modifications to the
|
||||
# bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
|
||||
# otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
|
||||
cc = "=1.2.0"
|
||||
#
|
||||
# Do not upgrade this crate unless https://github.com/rust-lang/cc-rs/issues/1317 is fixed.
|
||||
cc = "=1.1.22"
|
||||
cmake = "=0.1.48"
|
||||
|
||||
build_helper = { path = "../build_helper" }
|
||||
|
||||
@@ -776,6 +776,6 @@ if __name__ == "__main__":
|
||||
f.write(contents)
|
||||
|
||||
p("")
|
||||
p("run `python {}/x.py --help`".format(rust_dir))
|
||||
p("run `{} {}/x.py --help`".format(os.path.basename(sys.executable), rust_dir))
|
||||
if "GITHUB_ACTIONS" in os.environ:
|
||||
print("::endgroup::")
|
||||
|
||||
@@ -293,17 +293,27 @@ impl Step for Cargo {
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target });
|
||||
// If stage is explicitly set or not lower than 2, keep it. Otherwise, make sure it's at least 2
|
||||
// as tests for this step don't work with a lower stage.
|
||||
let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
|
||||
run.builder.top_stage
|
||||
} else {
|
||||
2
|
||||
};
|
||||
|
||||
run.builder.ensure(Cargo { stage, host: run.target });
|
||||
}
|
||||
|
||||
/// Runs `cargo test` for `cargo` packaged with Rust.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
if self.stage < 2 {
|
||||
eprintln!("WARNING: cargo tests on stage {} may not behave well.", self.stage);
|
||||
let stage = self.stage;
|
||||
|
||||
if stage < 2 {
|
||||
eprintln!("WARNING: cargo tests on stage {stage} may not behave well.");
|
||||
eprintln!("HELP: consider using stage 2");
|
||||
}
|
||||
|
||||
let compiler = builder.compiler(self.stage, self.host);
|
||||
let compiler = builder.compiler(stage, self.host);
|
||||
|
||||
let cargo = builder.ensure(tool::Cargo { compiler, target: self.host });
|
||||
let compiler = cargo.build_compiler;
|
||||
@@ -340,7 +350,7 @@ impl Step for Cargo {
|
||||
crates: vec!["cargo".into()],
|
||||
target: self.host.triple.to_string(),
|
||||
host: self.host.triple.to_string(),
|
||||
stage: self.stage,
|
||||
stage,
|
||||
},
|
||||
builder,
|
||||
);
|
||||
@@ -739,7 +749,15 @@ impl Step for Clippy {
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target });
|
||||
// If stage is explicitly set or not lower than 2, keep it. Otherwise, make sure it's at least 2
|
||||
// as tests for this step don't work with a lower stage.
|
||||
let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
|
||||
run.builder.top_stage
|
||||
} else {
|
||||
2
|
||||
};
|
||||
|
||||
run.builder.ensure(Clippy { stage, host: run.target });
|
||||
}
|
||||
|
||||
/// Runs `cargo test` for clippy.
|
||||
|
||||
@@ -218,6 +218,8 @@ pub struct Config {
|
||||
pub stderr_is_tty: bool,
|
||||
|
||||
pub on_fail: Option<String>,
|
||||
pub explicit_stage_from_cli: bool,
|
||||
pub explicit_stage_from_config: bool,
|
||||
pub stage: u32,
|
||||
pub keep_stage: Vec<u32>,
|
||||
pub keep_stage_std: Vec<u32>,
|
||||
@@ -2323,6 +2325,14 @@ impl Config {
|
||||
config.compiletest_diff_tool = compiletest_diff_tool;
|
||||
|
||||
let download_rustc = config.download_rustc_commit.is_some();
|
||||
config.explicit_stage_from_cli = flags.stage.is_some();
|
||||
config.explicit_stage_from_config = test_stage.is_some()
|
||||
|| build_stage.is_some()
|
||||
|| doc_stage.is_some()
|
||||
|| dist_stage.is_some()
|
||||
|| install_stage.is_some()
|
||||
|| check_stage.is_some()
|
||||
|| bench_stage.is_some();
|
||||
// See https://github.com/rust-lang/compiler-team/issues/326
|
||||
config.stage = match config.cmd {
|
||||
Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0),
|
||||
@@ -2392,6 +2402,10 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_explicit_stage(&self) -> bool {
|
||||
self.explicit_stage_from_cli || self.explicit_stage_from_config
|
||||
}
|
||||
|
||||
/// Runs a command, printing out nice contextual information if it fails.
|
||||
/// Exits if the command failed to execute at all, otherwise returns its
|
||||
/// `status.success()`.
|
||||
|
||||
@@ -454,3 +454,64 @@ fn check_rustc_if_unchanged_paths() {
|
||||
assert!(config.src.join(p).exists(), "{p} doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_explicit_stage() {
|
||||
let config = Config::parse_inner(
|
||||
Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
|
||||
|&_| {
|
||||
toml::from_str(
|
||||
r#"
|
||||
[build]
|
||||
test-stage = 1
|
||||
"#,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
assert!(!config.explicit_stage_from_cli);
|
||||
assert!(config.explicit_stage_from_config);
|
||||
assert!(config.is_explicit_stage());
|
||||
|
||||
let config = Config::parse_inner(
|
||||
Flags::parse(&[
|
||||
"check".to_owned(),
|
||||
"--stage=2".to_owned(),
|
||||
"--config=/does/not/exist".to_owned(),
|
||||
]),
|
||||
|&_| toml::from_str(""),
|
||||
);
|
||||
|
||||
assert!(config.explicit_stage_from_cli);
|
||||
assert!(!config.explicit_stage_from_config);
|
||||
assert!(config.is_explicit_stage());
|
||||
|
||||
let config = Config::parse_inner(
|
||||
Flags::parse(&[
|
||||
"check".to_owned(),
|
||||
"--stage=2".to_owned(),
|
||||
"--config=/does/not/exist".to_owned(),
|
||||
]),
|
||||
|&_| {
|
||||
toml::from_str(
|
||||
r#"
|
||||
[build]
|
||||
test-stage = 1
|
||||
"#,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
assert!(config.explicit_stage_from_cli);
|
||||
assert!(config.explicit_stage_from_config);
|
||||
assert!(config.is_explicit_stage());
|
||||
|
||||
let config = Config::parse_inner(
|
||||
Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]),
|
||||
|&_| toml::from_str(""),
|
||||
);
|
||||
|
||||
assert!(!config.explicit_stage_from_cli);
|
||||
assert!(!config.explicit_stage_from_config);
|
||||
assert!(!config.is_explicit_stage());
|
||||
}
|
||||
|
||||
@@ -154,7 +154,6 @@ pub fn get_closest_merge_commit(
|
||||
"rev-list",
|
||||
&format!("--author={}", config.git_merge_commit_email),
|
||||
"-n1",
|
||||
"--first-parent",
|
||||
&merge_base,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.20.2
|
||||
0.20.3
|
||||
Submodule src/tools/cargo updated: ce948f4616...1d1d646c06
@@ -1 +1 @@
|
||||
f5729cfed3c45e061e8a443677fc1d5ef9277df7
|
||||
cb06d12710575a0d7ff71d6fe108f3bcff4f9195
|
||||
|
||||
@@ -251,11 +251,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = apply_random_float_error_ulp(
|
||||
this,
|
||||
res,
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res,
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -286,11 +287,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = apply_random_float_error_ulp(
|
||||
this,
|
||||
res,
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res,
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#![feature(unqualified_local_imports)]
|
||||
#![feature(derive_coerce_pointee)]
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(extract_if)]
|
||||
// Configure clippy and other lints
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
|
||||
@@ -765,13 +765,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"erfcf" => f_host.erfc(),
|
||||
_ => bug!(),
|
||||
};
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = math::apply_random_float_error_ulp(
|
||||
this,
|
||||
res.to_soft(),
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res,
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -796,11 +798,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
};
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = math::apply_random_float_error_ulp(
|
||||
this,
|
||||
res,
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res,
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f1, f2]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -839,13 +842,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
"erfc" => f_host.erfc(),
|
||||
_ => bug!(),
|
||||
};
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = math::apply_random_float_error_ulp(
|
||||
this,
|
||||
res.to_soft(),
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res.to_soft(),
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -870,11 +875,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
};
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res = math::apply_random_float_error_ulp(
|
||||
this,
|
||||
res,
|
||||
4, // log2(16)
|
||||
);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(
|
||||
// this,
|
||||
// res,
|
||||
// 4, // log2(16)
|
||||
// );
|
||||
let res = this.adjust_nan(res, &[f1, f2]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -900,10 +906,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
// Using host floats (but it's fine, these operations do not have guaranteed precision).
|
||||
let (res, sign) = x.to_host().ln_gamma();
|
||||
this.write_int(sign, &signp)?;
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res =
|
||||
math::apply_random_float_error_ulp(this, res.to_soft(), 4 /* log2(16) */);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
|
||||
let res = this.adjust_nan(res, &[x]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
@@ -915,10 +922,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
// Using host floats (but it's fine, these operations do not have guaranteed precision).
|
||||
let (res, sign) = x.to_host().ln_gamma();
|
||||
this.write_int(sign, &signp)?;
|
||||
let res = res.to_soft();
|
||||
// Apply a relative error of 16ULP to introduce some non-determinism
|
||||
// simulating imprecise implementations and optimizations.
|
||||
let res =
|
||||
math::apply_random_float_error_ulp(this, res.to_soft(), 4 /* log2(16) */);
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
// let res = math::apply_random_float_error_ulp(this, res, 4 /* log2(16) */);
|
||||
let res = this.adjust_nan(res, &[x]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
@@ -1290,7 +1290,8 @@ fn test_non_determinism() {
|
||||
}
|
||||
}
|
||||
// We saw the same thing N times.
|
||||
panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
|
||||
// FIXME: temporarily disabled as it breaks std tests.
|
||||
//panic!("expected non-determinism, got {rounds} times the same result: {first:?}");
|
||||
}
|
||||
|
||||
macro_rules! test_operations_f {
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
//@ compile-flags: -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![feature(repr_simd, intrinsics)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x2(pub [f32; 2]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x4(pub [f32; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x8(pub [f32; 8]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x16(pub [f32; 16]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_fpow<T>(x: T, b: T) -> T;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_32x2(a: f32x2, b: f32x2) -> f32x2 {
|
||||
// CHECK: call <2 x float> @llvm.pow.v2f32
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_32x4(a: f32x4, b: f32x4) -> f32x4 {
|
||||
// CHECK: call <4 x float> @llvm.pow.v4f32
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_32x8(a: f32x8, b: f32x8) -> f32x8 {
|
||||
// CHECK: call <8 x float> @llvm.pow.v8f32
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_32x16(a: f32x16, b: f32x16) -> f32x16 {
|
||||
// CHECK: call <16 x float> @llvm.pow.v16f32
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x2(pub [f64; 2]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x4(pub [f64; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x8(pub [f64; 8]);
|
||||
|
||||
// CHECK-LABEL: @fpow_64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_64x4(a: f64x4, b: f64x4) -> f64x4 {
|
||||
// CHECK: call <4 x double> @llvm.pow.v4f64
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_64x2(a: f64x2, b: f64x2) -> f64x2 {
|
||||
// CHECK: call <2 x double> @llvm.pow.v2f64
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpow_64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpow_64x8(a: f64x8, b: f64x8) -> f64x8 {
|
||||
// CHECK: call <8 x double> @llvm.pow.v8f64
|
||||
simd_fpow(a, b)
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
//@ compile-flags: -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![feature(repr_simd, intrinsics)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x2(pub [f32; 2]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x4(pub [f32; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x8(pub [f32; 8]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f32x16(pub [f32; 16]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_fpowi<T>(x: T, b: i32) -> T;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_32x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_32x2(a: f32x2, b: i32) -> f32x2 {
|
||||
// CHECK: call <2 x float> @llvm.powi.v2f32
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_32x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_32x4(a: f32x4, b: i32) -> f32x4 {
|
||||
// CHECK: call <4 x float> @llvm.powi.v4f32
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_32x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_32x8(a: f32x8, b: i32) -> f32x8 {
|
||||
// CHECK: call <8 x float> @llvm.powi.v8f32
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_32x16
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_32x16(a: f32x16, b: i32) -> f32x16 {
|
||||
// CHECK: call <16 x float> @llvm.powi.v16f32
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x2(pub [f64; 2]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x4(pub [f64; 4]);
|
||||
|
||||
#[repr(simd)]
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub struct f64x8(pub [f64; 8]);
|
||||
|
||||
// CHECK-LABEL: @fpowi_64x4
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_64x4(a: f64x4, b: i32) -> f64x4 {
|
||||
// CHECK: call <4 x double> @llvm.powi.v4f64
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_64x2
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_64x2(a: f64x2, b: i32) -> f64x2 {
|
||||
// CHECK: call <2 x double> @llvm.powi.v2f64
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @fpowi_64x8
|
||||
#[no_mangle]
|
||||
pub unsafe fn fpowi_64x8(a: f64x8, b: i32) -> f64x8 {
|
||||
// CHECK: call <8 x double> @llvm.powi.v8f64
|
||||
simd_fpowi(a, b)
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
mod foo {
|
||||
#[link_section = ".rodata.STATIC"]
|
||||
#[cfg_attr(target_os = "linux", link_section = ".rodata.STATIC")]
|
||||
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,STATIC")]
|
||||
#[used]
|
||||
static STATIC: [u32; 10] = [1; 10];
|
||||
}
|
||||
|
||||
@@ -7,15 +7,20 @@
|
||||
// See https://github.com/rust-lang/rust/pull/95604
|
||||
// See https://github.com/rust-lang/rust/issues/47384
|
||||
|
||||
//@ only-linux
|
||||
// Reason: differences in object file formats on OSX and Windows
|
||||
// causes errors in the llvm_objdump step
|
||||
//@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step.
|
||||
//@ ignore-windows differences in object file formats causes errors in the llvm_objdump step.
|
||||
|
||||
use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc};
|
||||
use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc, target};
|
||||
|
||||
fn main() {
|
||||
rustc().crate_type("lib").input("lib.rs").run();
|
||||
rustc().crate_type("cdylib").link_args("-Tlinker.ld").input("main.rs").run();
|
||||
let mut main = rustc();
|
||||
main.crate_type("cdylib");
|
||||
if target().contains("linux") {
|
||||
main.link_args("-Tlinker.ld");
|
||||
}
|
||||
main.input("main.rs").run();
|
||||
|
||||
// Ensure `#[used]` and `KEEP`-ed section is there
|
||||
llvm_objdump()
|
||||
.arg("--full-contents")
|
||||
|
||||
@@ -26,6 +26,8 @@ click: ".example-wrap .copy-button"
|
||||
move-cursor-to: ".search-input"
|
||||
assert-count: (".example-wrap:not(:hover) .button-holder.keep-visible", 0)
|
||||
assert-css: (".example-wrap .copy-button", { "visibility": "hidden" })
|
||||
// Since we clicked on the copy button, the clipboard content should have been updated.
|
||||
assert-clipboard: 'println!("nothing fancy");\nprintln!("but with two lines!");'
|
||||
|
||||
define-function: (
|
||||
"check-buttons",
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
// Checks that the "copy path" button is not triggering JS error and its display
|
||||
// isn't broken.
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
|
||||
// isn't broken and the copied path is as expected.
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/foreign_impl_order/trait.Foo.html"
|
||||
|
||||
// We ensure that the clipboard is empty.
|
||||
assert-clipboard: ""
|
||||
|
||||
// First we store the size of the button before we click on it.
|
||||
store-size: ("#copy-path", {"width": width, "height": height})
|
||||
click: "#copy-path"
|
||||
// We wait for the new text to appear.
|
||||
wait-for: "#copy-path.clicked"
|
||||
// We check that the clipboard value is the expected one.
|
||||
assert-clipboard: "test_docs::foreign_impl_order::Foo"
|
||||
// We check that the size didn't change.
|
||||
assert-size: ("#copy-path.clicked", {"width": |width|, "height": |height|})
|
||||
// We wait for the button to turn back to its original state.
|
||||
|
||||
32
tests/ui/attributes/auxiliary/used_pre_main_constructor.rs
Normal file
32
tests/ui/attributes/auxiliary/used_pre_main_constructor.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! Add a constructor that runs pre-main, similar to what the `ctor` crate does.
|
||||
//!
|
||||
//! #[ctor]
|
||||
//! fn constructor() {
|
||||
//! println!("constructor");
|
||||
//! }
|
||||
|
||||
//@ no-prefer-dynamic explicitly test with crates that are built as an archive
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#[cfg_attr(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "illumos",
|
||||
target_os = "haiku"
|
||||
),
|
||||
link_section = ".init_array"
|
||||
)]
|
||||
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func,mod_init_funcs")]
|
||||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
|
||||
#[used]
|
||||
static CONSTRUCTOR: extern "C" fn() = constructor;
|
||||
|
||||
#[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")]
|
||||
extern "C" fn constructor() {
|
||||
println!("constructor");
|
||||
}
|
||||
16
tests/ui/attributes/used_with_archive.rs
Normal file
16
tests/ui/attributes/used_with_archive.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
//! Ensure that `#[used]` in archives are correctly registered.
|
||||
//!
|
||||
//! Regression test for https://github.com/rust-lang/rust/issues/133491.
|
||||
|
||||
//@ run-pass
|
||||
//@ check-run-results
|
||||
//@ aux-build: used_pre_main_constructor.rs
|
||||
|
||||
//@ ignore-wasm ctor doesn't work on WASM
|
||||
|
||||
// Make sure `rustc` links the archive, but intentionally do not import/use any items.
|
||||
extern crate used_pre_main_constructor as _;
|
||||
|
||||
fn main() {
|
||||
println!("main");
|
||||
}
|
||||
2
tests/ui/attributes/used_with_archive.run.stdout
Normal file
2
tests/ui/attributes/used_with_archive.run.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
constructor
|
||||
main
|
||||
@@ -1,3 +1,7 @@
|
||||
error: reached the recursion limit finding the struct tail for `K`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
|
||||
|
||||
error: reached the recursion limit finding the struct tail for `Bottom`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
|
||||
@@ -21,7 +25,7 @@ LL | let x: &Bottom = &t;
|
||||
= note: expected reference `&Bottom`
|
||||
found reference `&Top`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0055, E0308.
|
||||
For more information about an error, try `rustc --explain E0055`.
|
||||
|
||||
33
tests/ui/drop/lint-if-let-rescope-false-positives.rs
Normal file
33
tests/ui/drop/lint-if-let-rescope-false-positives.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
//@ edition: 2021
|
||||
//@ check-pass
|
||||
|
||||
#![deny(if_let_rescope)]
|
||||
|
||||
struct Drop;
|
||||
impl std::ops::Drop for Drop {
|
||||
fn drop(&mut self) {
|
||||
println!("drop")
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop {
|
||||
fn as_ref(&self) -> Option<i32> {
|
||||
Some(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn consume(_: impl Sized) -> Option<i32> { Some(1) }
|
||||
|
||||
fn main() {
|
||||
let drop = Drop;
|
||||
|
||||
// Make sure we don't drop if we don't actually make a temporary.
|
||||
if let None = drop.as_ref() {} else {}
|
||||
|
||||
// Make sure we don't lint if we consume the droppy value.
|
||||
if let None = consume(Drop) {} else {}
|
||||
|
||||
// Make sure we don't lint on field exprs of place exprs.
|
||||
let tup_place = (Drop, ());
|
||||
if let None = consume(tup_place.1) {} else {}
|
||||
}
|
||||
@@ -94,6 +94,12 @@ fn main() {
|
||||
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
|
||||
}
|
||||
|
||||
match Some((droppy(), ()).1) { Some(_value) => {} _ => {}}
|
||||
//~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
//~| HELP: the value is now dropped here in Edition 2024
|
||||
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
|
||||
|
||||
// We want to keep the `if let`s below as direct descendents of match arms,
|
||||
// so the formatting is suppressed.
|
||||
#[rustfmt::skip]
|
||||
|
||||
@@ -94,6 +94,12 @@ fn main() {
|
||||
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
|
||||
}
|
||||
|
||||
if let Some(_value) = Some((droppy(), ()).1) {} else {}
|
||||
//~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
//~| HELP: the value is now dropped here in Edition 2024
|
||||
//~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
|
||||
|
||||
// We want to keep the `if let`s below as direct descendents of match arms,
|
||||
// so the formatting is suppressed.
|
||||
#[rustfmt::skip]
|
||||
|
||||
@@ -175,5 +175,26 @@ LL - while (if let Some(_value) = droppy().get() { false } else { true }) {
|
||||
LL + while (match droppy().get() { Some(_value) => { false } _ => { true }}) {
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: `if let` assigns a shorter lifetime since Edition 2024
|
||||
--> $DIR/lint-if-let-rescope.rs:97:8
|
||||
|
|
||||
LL | if let Some(_value) = Some((droppy(), ()).1) {} else {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^--------------^^^
|
||||
| |
|
||||
| this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
help: the value is now dropped here in Edition 2024
|
||||
--> $DIR/lint-if-let-rescope.rs:97:51
|
||||
|
|
||||
LL | if let Some(_value) = Some((droppy(), ()).1) {} else {}
|
||||
| ^
|
||||
help: a `match` with a single arm can preserve the drop order up to Edition 2021
|
||||
|
|
||||
LL - if let Some(_value) = Some((droppy(), ()).1) {} else {}
|
||||
LL + match Some((droppy(), ()).1) { Some(_value) => {} _ => {}}
|
||||
|
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[rustc_force_inline]
|
||||
//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
|
||||
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
|
||||
pub fn bare() {
|
||||
}
|
||||
|
||||
#[rustc_force_inline = "the test requires it"]
|
||||
//~^ ERROR #![rustc_force_inline] forces a free function to be inlined
|
||||
//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
|
||||
pub fn justified() {
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
error[E0658]: #![rustc_force_inline] forces a free function to be inlined
|
||||
error[E0658]: #[rustc_force_inline] forces a free function to be inlined
|
||||
--> $DIR/gate.rs:4:1
|
||||
|
|
||||
LL | #[rustc_force_inline]
|
||||
@@ -7,7 +7,7 @@ LL | #[rustc_force_inline]
|
||||
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: #![rustc_force_inline] forces a free function to be inlined
|
||||
error[E0658]: #[rustc_force_inline] forces a free function to be inlined
|
||||
--> $DIR/gate.rs:9:1
|
||||
|
|
||||
LL | #[rustc_force_inline = "the test requires it"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ build-fail
|
||||
//@ check-fail
|
||||
//@ compile-flags: --crate-type lib -Cdebuginfo=2
|
||||
//@ error-pattern: the type has an unknown layout
|
||||
//@ error-pattern: recursion limit
|
||||
|
||||
#![recursion_limit = "10"]
|
||||
macro_rules! link {
|
||||
@@ -28,7 +28,6 @@ impl Bottom {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
link!(A, B);
|
||||
link!(B, C);
|
||||
link!(C, D);
|
||||
@@ -41,4 +40,4 @@ link!(I, J);
|
||||
link!(J, K);
|
||||
link!(K, Bottom);
|
||||
|
||||
fn main() { }
|
||||
fn main() {}
|
||||
|
||||
@@ -2,7 +2,5 @@ error: reached the recursion limit finding the struct tail for `Bottom`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]`
|
||||
|
||||
error: the type has an unknown layout
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -48,13 +48,6 @@ unsafe fn simd_flog10<T>(x: T) -> T;
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_flog2<T>(x: T) -> T;
|
||||
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_fpow<T>(x: T, y: T) -> T;
|
||||
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_fpowi<T>(x: T, y: i32) -> T;
|
||||
|
||||
|
||||
// rounding functions
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_ceil<T>(x: T) -> T;
|
||||
@@ -68,23 +61,21 @@ unsafe fn simd_round<T>(x: T) -> T;
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_trunc<T>(x: T) -> T;
|
||||
|
||||
|
||||
macro_rules! assert_approx_eq_f32 {
|
||||
($a:expr, $b:expr) => ({
|
||||
($a:expr, $b:expr) => {{
|
||||
let (a, b) = (&$a, &$b);
|
||||
assert!((*a - *b).abs() < 1.0e-6,
|
||||
"{} is not approximately equal to {}", *a, *b);
|
||||
})
|
||||
assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
|
||||
}};
|
||||
}
|
||||
macro_rules! assert_approx_eq {
|
||||
($a:expr, $b:expr) => ({
|
||||
($a:expr, $b:expr) => {{
|
||||
let a = $a;
|
||||
let b = $b;
|
||||
assert_approx_eq_f32!(a.0[0], b.0[0]);
|
||||
assert_approx_eq_f32!(a.0[1], b.0[1]);
|
||||
assert_approx_eq_f32!(a.0[2], b.0[2]);
|
||||
assert_approx_eq_f32!(a.0[3], b.0[3]);
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -125,12 +116,6 @@ fn main() {
|
||||
let r = simd_flog10(x);
|
||||
assert_approx_eq!(z, r);
|
||||
|
||||
let r = simd_fpow(h, x);
|
||||
assert_approx_eq!(h, r);
|
||||
|
||||
let r = simd_fpowi(h, 1);
|
||||
assert_approx_eq!(h, r);
|
||||
|
||||
let r = simd_fsin(z);
|
||||
assert_approx_eq!(z, r);
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Regression test for #129541
|
||||
|
||||
//@ revisions: unique multiple
|
||||
//@ check-pass
|
||||
//@ error-pattern: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
||||
|
||||
trait Bound {}
|
||||
trait Normalize {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! This test checks that we currently need to implement
|
||||
//! members, even if their where bounds don't hold for the impl type.
|
||||
//! This test checks that we do not need to implement
|
||||
//! members, whose `where Self: Sized` bounds don't hold for the impl type.
|
||||
|
||||
trait Foo {
|
||||
fn foo()
|
||||
@@ -15,12 +15,28 @@ impl Foo for () {
|
||||
impl Foo for i32 {}
|
||||
//~^ ERROR: not all trait items implemented, missing: `foo`
|
||||
|
||||
// Should be allowed
|
||||
impl Foo for dyn std::fmt::Debug {}
|
||||
//~^ ERROR: not all trait items implemented, missing: `foo`
|
||||
|
||||
#[deny(dead_code)]
|
||||
impl Foo for dyn std::fmt::Display {
|
||||
fn foo() {}
|
||||
//~^ ERROR this item cannot be used as its where bounds are not satisfied
|
||||
}
|
||||
|
||||
struct Struct {
|
||||
i: i32,
|
||||
tail: [u8],
|
||||
}
|
||||
|
||||
impl Foo for Struct {}
|
||||
|
||||
// Ensure we only allow known-unsized types to be skipped
|
||||
trait Trait {
|
||||
fn foo(self)
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
impl<T: ?Sized> Trait for T {}
|
||||
//~^ ERROR: not all trait items implemented, missing: `foo`
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -9,17 +9,29 @@ LL | | Self: Sized;
|
||||
LL | impl Foo for i32 {}
|
||||
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `foo`
|
||||
--> $DIR/trivial_impl_sized.rs:19:1
|
||||
error: this item cannot be used as its where bounds are not satisfied for the `Self` type
|
||||
--> $DIR/trivial_impl_sized.rs:22:5
|
||||
|
|
||||
LL | / fn foo()
|
||||
LL | fn foo() {}
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/trivial_impl_sized.rs:20:8
|
||||
|
|
||||
LL | #[deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0046]: not all trait items implemented, missing: `foo`
|
||||
--> $DIR/trivial_impl_sized.rs:39:1
|
||||
|
|
||||
LL | / fn foo(self)
|
||||
LL | | where
|
||||
LL | | Self: Sized;
|
||||
| |____________________- `foo` from trait
|
||||
...
|
||||
LL | impl Foo for dyn std::fmt::Debug {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
|
||||
LL | }
|
||||
LL | impl<T: ?Sized> Trait for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
||||
|
||||
7
tests/ui/typeck/auxiliary/derive-demo-issue-136343.rs
Normal file
7
tests/ui/typeck/auxiliary/derive-demo-issue-136343.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(Sample)]
|
||||
pub fn sample(_: TokenStream) -> TokenStream {
|
||||
"fn bad<T: Into<U>, U>(a: T) -> U { a }".parse().unwrap()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
//@ proc-macro: derive-demo-issue-136343.rs
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_demo_issue_136343;
|
||||
|
||||
#[derive(Sample)] //~ ERROR mismatched types
|
||||
struct Test;
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,19 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/invalid-sugg-for-derive-macro-issue-136343.rs:6:10
|
||||
|
|
||||
LL | #[derive(Sample)]
|
||||
| ^^^^^^
|
||||
| |
|
||||
| expected type parameter `U`, found type parameter `T`
|
||||
| expected `U` because of return type
|
||||
|
|
||||
= note: expected type parameter `U`
|
||||
found type parameter `T`
|
||||
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
|
||||
= note: the caller chooses a type for `U` which can be different from `T`
|
||||
= note: this error originates in the derive macro `Sample` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Reference in New Issue
Block a user