Merge branch 'master' into is-symlink-stabilization

This commit is contained in:
Max Wase 2021-10-13 01:33:12 +03:00 committed by GitHub
commit 3e0360f3d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
365 changed files with 4893 additions and 3106 deletions

View File

@ -89,6 +89,15 @@ gimli.debug = 0
miniz_oxide.debug = 0
object.debug = 0
# The only package that ever uses debug builds is bootstrap.
# We care a lot about bootstrap's compile times, so don't include debug info for
# dependencies, only bootstrap itself.
[profile.dev]
debug = 0
[profile.dev.package]
# Only use debuginfo=1 to further reduce compile times.
bootstrap.debug = 1
# We want the RLS to use the version of Cargo that we've got vendored in this
# repository to ensure that the same exact version of Cargo is used by both the
# RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository

View File

@ -64,7 +64,6 @@ Stabilised APIs
- [`VecDeque::shrink_to`]
- [`HashMap::shrink_to`]
- [`HashSet::shrink_to`]
- [`task::ready!`]
These APIs are now usable in const contexts:
@ -128,7 +127,6 @@ and related tools.
[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to
[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to
[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to
[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html
[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first
[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first

View File

@ -389,6 +389,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
// Change the exponent from 2^e to 10^e.
#[allow(clippy::comparison_chain)]
if exp == 0 {
// Nothing to do.
} else if exp > 0 {
@ -2526,6 +2527,7 @@ mod sig {
if *a_sign ^ b_sign {
let (reverse, loss);
#[allow(clippy::comparison_chain)]
if bits == 0 {
reverse = cmp(a_sig, b_sig) == Ordering::Less;
loss = Loss::ExactlyZero;

View File

@ -20,16 +20,6 @@
#[macro_use]
extern crate rustc_macros;
#[macro_export]
macro_rules! unwrap_or {
($opt:expr, $default:expr) => {
match $opt {
Some(x) => x,
None => $default,
}
};
}
pub mod util {
pub mod classify;
pub mod comments;

View File

@ -202,39 +202,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut used_input_regs = FxHashMap::default();
let mut used_output_regs = FxHashMap::default();
let mut required_features: Vec<&str> = vec![];
for (idx, &(ref op, op_sp)) in operands.iter().enumerate() {
if let Some(reg) = op.reg() {
// Make sure we don't accidentally carry features from the
// previous iteration.
required_features.clear();
let reg_class = reg.reg_class();
if reg_class == asm::InlineAsmRegClass::Err {
continue;
}
// We ignore target feature requirements for clobbers: if the
// feature is disabled then the compiler doesn't care what we
// do with the registers.
//
// Note that this is only possible for explicit register
// operands, which cannot be used in the asm string.
let is_clobber = matches!(
op,
hir::InlineAsmOperand::Out {
reg: asm::InlineAsmRegOrRegClass::Reg(_),
late: _,
expr: None
}
);
// Some register classes can only be used as clobbers. This
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
if reg_class.is_clobber_only(asm_arch.unwrap())
&& !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
&& !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
{
let msg = format!(
"register class `{}` can only be used as a clobber, \
@ -245,47 +226,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
continue;
}
if !is_clobber {
// Validate register classes against currently enabled target
// features. We check that at least one type is available for
// the current target.
for &(_, feature) in reg_class.supported_types(asm_arch.unwrap()) {
if let Some(feature) = feature {
if self.sess.target_features.contains(&Symbol::intern(feature)) {
required_features.clear();
break;
} else {
required_features.push(feature);
}
} else {
required_features.clear();
break;
}
}
// We are sorting primitive strs here and can use unstable sort here
required_features.sort_unstable();
required_features.dedup();
match &required_features[..] {
[] => {}
[feature] => {
let msg = format!(
"register class `{}` requires the `{}` target feature",
reg_class.name(),
feature
);
sess.struct_span_err(op_sp, &msg).emit();
}
features => {
let msg = format!(
"register class `{}` requires at least one target feature: {}",
reg_class.name(),
features.join(", ")
);
sess.struct_span_err(op_sp, &msg).emit();
}
}
}
// Check for conflicts between explicit register operands.
if let asm::InlineAsmRegOrRegClass::Reg(reg) = reg {
let (input, output) = match op {

View File

@ -1345,8 +1345,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
generics
.params
.iter()
.find(|p| def_id == self.resolver.local_def_id(p.id).to_def_id())
.is_some()
.any(|p| def_id == self.resolver.local_def_id(p.id).to_def_id())
}
// Either the `bounded_ty` is not a plain type parameter, or
// it's not found in the generic type parameters list.

View File

@ -201,7 +201,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
let bb_data = &self.body[bb];
debug_assert!(hi == bb_data.statements.len());
for &succ_bb in bb_data.terminator().successors() {
if self.visited.insert(succ_bb) == false {
if !self.visited.insert(succ_bb) {
if succ_bb == location.block && first_lo > 0 {
// `succ_bb` has been seen before. If it wasn't
// fully processed, add its first part to `stack`

View File

@ -972,8 +972,7 @@ fn suggest_ampmut<'tcx>(
if let Some(assignment_rhs_span) = opt_assignment_rhs_span {
if let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) {
let is_mutbl = |ty: &str| -> bool {
if ty.starts_with("mut") {
let rest = &ty[3..];
if let Some(rest) = ty.strip_prefix("mut") {
match rest.chars().next() {
// e.g. `&mut x`
Some(c) if c.is_whitespace() => true,

View File

@ -1153,28 +1153,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.convert_all(data);
}
/// Convenient wrapper around `relate_tys::relate_types` -- see
/// that fn for docs.
fn relate_types(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
relate_tys::relate_types(
self.infcx,
self.param_env,
a,
v,
b,
locations,
category,
self.borrowck_context,
)
}
/// Try to relate `sub <: sup`
fn sub_types(
&mut self,

View File

@ -1,5 +1,5 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, Ty};
@ -7,48 +7,38 @@ use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
use crate::type_check::{BorrowCheckContext, Locations};
use crate::type_check::{Locations, TypeChecker};
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
///
/// - "Covariant" `a <: b`
/// - "Invariant" `a == b`
/// - "Contravariant" `a :> b`
///
/// N.B., the type `a` is permitted to have unresolved inference
/// variables, but not the type `b`.
#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")]
pub(super) fn relate_types<'tcx>(
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
) -> Fallible<()> {
TypeRelating::new(
infcx,
NllTypeRelatingDelegate::new(
infcx,
borrowck_context,
param_env,
locations,
category,
UniverseInfo::relate(a, b),
),
v,
)
.relate(a, b)?;
Ok(())
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
///
/// - "Covariant" `a <: b`
/// - "Invariant" `a == b`
/// - "Contravariant" `a :> b`
///
/// N.B., the type `a` is permitted to have unresolved inference
/// variables, but not the type `b`.
#[instrument(skip(self), level = "debug")]
pub(super) fn relate_types(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
TypeRelating::new(
self.infcx,
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
v,
)
.relate(a, b)?;
Ok(())
}
}
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
infcx: &'me InferCtxt<'me, 'tcx>,
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
/// Where (and why) is this relation taking place?
locations: Locations,
@ -63,25 +53,24 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
fn new(
infcx: &'me InferCtxt<'me, 'tcx>,
borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
locations: Locations,
category: ConstraintCategory,
universe_info: UniverseInfo<'tcx>,
) -> Self {
Self { infcx, borrowck_context, param_env, locations, category, universe_info }
Self { type_checker, locations, category, universe_info }
}
}
impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
self.type_checker.param_env
}
fn create_next_universe(&mut self) -> ty::UniverseIndex {
let universe = self.infcx.create_next_universe();
self.borrowck_context
let universe = self.type_checker.infcx.create_next_universe();
self.type_checker
.borrowck_context
.constraints
.universe_causes
.insert(universe, self.universe_info.clone());
@ -90,15 +79,18 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
let origin = NllRegionVariableOrigin::Existential { from_forall };
self.infcx.next_nll_region_var(origin)
self.type_checker.infcx.next_nll_region_var(origin)
}
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
self.type_checker
.borrowck_context
.constraints
.placeholder_region(self.type_checker.infcx, placeholder)
}
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
self.infcx.next_nll_region_var_in_universe(
self.type_checker.infcx.next_nll_region_var_in_universe(
NllRegionVariableOrigin::Existential { from_forall: false },
universe,
)
@ -110,15 +102,17 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
sub: ty::Region<'tcx>,
info: ty::VarianceDiagInfo<'tcx>,
) {
let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
sup,
sub,
locations: self.locations,
category: self.category,
variance_info: info,
});
let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub);
let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup);
self.type_checker.borrowck_context.constraints.outlives_constraints.push(
OutlivesConstraint {
sup,
sub,
locations: self.locations,
category: self.category,
variance_info: info,
},
);
}
// We don't have to worry about the equality of consts during borrow checking

View File

@ -594,7 +594,7 @@ impl<'a> TraitDef<'a> {
GenericParamKind::Const { ty, kw_span, .. } => {
let const_nodefault_kind = GenericParamKind::Const {
ty: ty.clone(),
kw_span: kw_span.clone(),
kw_span: *kw_span,
// We can't have default values inside impl block
default: None,

View File

@ -2,7 +2,7 @@ use gccjit::RValue;
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
use rustc_middle::mir;
use rustc_middle::ty::{Instance, Ty};
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
use rustc_span::{SourceFile, Span, Symbol};
use rustc_target::abi::Size;
use rustc_target::abi::call::FnAbi;
@ -31,7 +31,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
}
impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _vtable: Self::Value) {
fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) {
// TODO(antoyo)
}

View File

@ -596,7 +596,7 @@ pub(crate) fn run_pass_manager(
// tools/lto/LTOCodeGenerator.cpp
debug!("running the pass manager");
unsafe {
if write::should_use_new_llvm_pass_manager(config) {
if write::should_use_new_llvm_pass_manager(cgcx, config) {
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
write::optimize_with_new_llvm_pass_manager(

View File

@ -377,10 +377,19 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
}
pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
pub(crate) fn should_use_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
config: &ModuleConfig,
) -> bool {
// The new pass manager is enabled by default for LLVM >= 13.
// This matches Clang, which also enables it since Clang 13.
config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0))
// FIXME: There are some perf issues with the new pass manager
// when targeting s390x, so it is temporarily disabled for that
// arch, see https://github.com/rust-lang/rust/issues/89609
config
.new_llvm_pass_manager
.unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0))
}
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
@ -482,7 +491,7 @@ pub(crate) unsafe fn optimize(
}
if let Some(opt_level) = config.opt_level {
if should_use_new_llvm_pass_manager(config) {
if should_use_new_llvm_pass_manager(cgcx, config) {
let opt_stage = match cgcx.lto {
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,

View File

@ -828,6 +828,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
let op = llvm::RealPredicate::from_generic(op);
unsafe { llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED) }
}

View File

@ -175,7 +175,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
// should use dllimport for functions.
if cx.use_dll_storage_attrs
&& tcx.is_dllimport_foreign_item(instance_def_id)
&& tcx.sess.target.env != "gnu"
&& !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
{
llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
}

View File

@ -2,7 +2,7 @@ use self::MemberDescriptionFactory::*;
use self::RecursiveTypeDescription::*;
use super::namespace::mangled_name_of_instance;
use super::type_names::compute_debuginfo_type_name;
use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
use super::utils::{
create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
};
@ -29,8 +29,9 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::{self, GeneratorLayout};
use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{
self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
};
use rustc_middle::{bug, span_bug};
use rustc_query_system::ich::NodeIdHashingMode;
use rustc_session::config::{self, DebugInfo};
@ -2591,11 +2592,45 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global
}
}
/// Generates LLVM debuginfo for a vtable.
fn vtable_type_metadata(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> &'ll DIType {
let tcx = cx.tcx;
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
let trait_ref = tcx.erase_regions(trait_ref);
tcx.vtable_entries(trait_ref)
} else {
COMMON_VTABLE_ENTRIES
};
// FIXME: We describe the vtable as an array of *const () pointers. The length of the array is
// correct - but we could create a more accurate description, e.g. by describing it
// as a struct where each field has a name that corresponds to the name of the method
// it points to.
// However, this is not entirely straightforward because there might be multiple
// methods with the same name if the vtable is for multiple traits. So for now we keep
// things simple instead of adding some ad-hoc disambiguation scheme.
let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
type_metadata(cx, vtable_type, rustc_span::DUMMY_SP)
}
/// Creates debug information for the given vtable, which is for the
/// given type.
///
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) {
pub fn create_vtable_metadata(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
vtable: &'ll Value,
) {
if cx.dbg_cx.is_none() {
return;
}
@ -2605,42 +2640,16 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &
return;
}
let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP);
let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref);
let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref);
unsafe {
// `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
// later on in `llvm/lib/IR/Value.cpp`.
let empty_array = create_DIArray(DIB(cx), &[]);
let name = "vtable";
// Create a new one each time. We don't want metadata caching
// here, because each vtable will refer to a unique containing
// type.
let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
DIB(cx),
NO_SCOPE_METADATA,
name.as_ptr().cast(),
name.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
Size::ZERO.bits(),
cx.tcx.data_layout.pointer_align.abi.bits() as u32,
DIFlags::FlagArtificial,
None,
empty_array,
0,
Some(type_metadata),
name.as_ptr().cast(),
name.len(),
);
let linkage_name = "";
llvm::LLVMRustDIBuilderCreateStaticVariable(
DIB(cx),
NO_SCOPE_METADATA,
name.as_ptr().cast(),
name.len(),
vtable_name.as_ptr().cast(),
vtable_name.len(),
linkage_name.as_ptr().cast(),
linkage_name.len(),
unknown_file_metadata(cx),

View File

@ -550,8 +550,13 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }
}
fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) {
metadata::create_vtable_metadata(self, ty, vtable)
fn create_vtable_metadata(
&self,
ty: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
vtable: Self::Value,
) {
metadata::create_vtable_metadata(self, ty, trait_ref, vtable)
}
fn extend_scope_to_file(

View File

@ -223,6 +223,33 @@ pub enum RealPredicate {
RealPredicateTrue = 15,
}
impl RealPredicate {
pub fn from_generic(realp: rustc_codegen_ssa::common::RealPredicate) -> Self {
match realp {
rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => {
RealPredicate::RealPredicateFalse
}
rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ,
rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT,
rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE,
rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT,
rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE,
rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE,
rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD,
rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO,
rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ,
rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT,
rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE,
rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT,
rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE,
rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE,
rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => {
RealPredicate::RealPredicateTrue
}
}
}
}
/// LLVMTypeKind
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)]

View File

@ -843,19 +843,18 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
let msg_bus = "clang: error: unable to execute command: Bus error: 10";
if out.contains(msg_segv) || out.contains(msg_bus) {
warn!(
?cmd, %out,
"looks like the linker segfaulted when we tried to call it, \
automatically retrying again. cmd = {:?}, out = {}.",
cmd, out,
automatically retrying again",
);
continue;
}
if is_illegal_instruction(&output.status) {
warn!(
?cmd, %out, status = %output.status,
"looks like the linker hit an illegal instruction when we \
tried to call it, automatically retrying again. cmd = {:?}, ]\
out = {}, status = {}.",
cmd, out, output.status,
tried to call it, automatically retrying again.",
);
continue;
}

View File

@ -446,6 +446,62 @@ fn push_debuginfo_type_name<'tcx>(
}
}
/// Computes a name for the global variable storing a vtable.
///
/// The name is of the form:
///
/// `<path::to::SomeType as path::to::SomeTrait>::{vtable}`
///
/// or, when generating C++-like names:
///
/// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
pub fn compute_debuginfo_vtable_name<'tcx>(
tcx: TyCtxt<'tcx>,
t: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> String {
let cpp_like_names = cpp_like_names(tcx);
let mut vtable_name = String::with_capacity(64);
if cpp_like_names {
vtable_name.push_str("impl$<");
} else {
vtable_name.push('<');
}
let mut visited = FxHashSet::default();
push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
if cpp_like_names {
vtable_name.push_str(", ");
} else {
vtable_name.push_str(" as ");
}
if let Some(trait_ref) = trait_ref {
push_item_name(tcx, trait_ref.skip_binder().def_id, true, &mut vtable_name);
visited.clear();
push_generic_params_internal(
tcx,
trait_ref.skip_binder().substs,
&mut vtable_name,
&mut visited,
);
} else {
vtable_name.push_str("_");
}
push_close_angle_bracket(cpp_like_names, &mut vtable_name);
let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" };
vtable_name.reserve_exact(suffix.len());
vtable_name.push_str(suffix);
vtable_name
}
pub fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
let def_key = tcx.def_key(def_id);
if qualified {

View File

@ -78,7 +78,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
let align = cx.data_layout().pointer_align.abi;
let vtable = cx.static_addr_of(vtable_const, align, Some("vtable"));
cx.create_vtable_metadata(ty, vtable);
cx.create_vtable_metadata(ty, trait_ref, vtable);
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
vtable
}

View File

@ -1,13 +1,18 @@
use super::BackendTypes;
use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc_middle::mir;
use rustc_middle::ty::{Instance, Ty};
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
use rustc_span::{SourceFile, Span, Symbol};
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Size;
pub trait DebugInfoMethods<'tcx>: BackendTypes {
fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value);
fn create_vtable_metadata(
&self,
ty: Ty<'tcx>,
trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
vtable: Self::Value,
);
/// Creates the function-specific debug context.
///

View File

@ -14,7 +14,7 @@ const BASE_64: &[u8; MAX_BASE as usize] =
#[inline]
pub fn push_str(mut n: u128, base: usize, output: &mut String) {
debug_assert!(base >= 2 && base <= MAX_BASE);
debug_assert!((2..=MAX_BASE).contains(&base));
let mut s = [0u8; 128];
let mut index = 0;

View File

@ -206,17 +206,11 @@ impl<N: Debug, E: Debug> Graph<N, E> {
AdjacentEdges { graph: self, direction, next: first_edge }
}
pub fn successor_nodes<'a>(
&'a self,
source: NodeIndex,
) -> impl Iterator<Item = NodeIndex> + 'a {
pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
self.outgoing_edges(source).targets()
}
pub fn predecessor_nodes<'a>(
&'a self,
target: NodeIndex,
) -> impl Iterator<Item = NodeIndex> + 'a {
pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ {
self.incoming_edges(target).sources()
}

View File

@ -48,7 +48,7 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
let node = frame.node;
visited[node] = true;
while let Some(successor) = frame.iter.next() {
for successor in frame.iter.by_ref() {
if !visited[successor] {
stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
continue 'recurse;
@ -112,7 +112,7 @@ where
/// This is equivalent to just invoke `next` repeatedly until
/// you get a `None` result.
pub fn complete_search(&mut self) {
while let Some(_) = self.next() {}
for _ in self {}
}
/// Returns true if node has been visited thus far.

View File

@ -390,7 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> {
.map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
.collect();
self.compress(|_| assert!(false));
self.compress(|_| unreachable!());
errors
}
@ -612,7 +612,7 @@ impl<O: ForestObligation> ObligationForest<O> {
fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
let orig_nodes_len = self.nodes.len();
let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
debug_assert!(node_rewrites.is_empty());
assert!(node_rewrites.is_empty());
node_rewrites.extend(0..orig_nodes_len);
let mut dead_nodes = 0;
@ -623,13 +623,13 @@ impl<O: ForestObligation> ObligationForest<O> {
// self.nodes[0..index - dead_nodes] are the first remaining nodes
// self.nodes[index - dead_nodes..index] are all dead
// self.nodes[index..] are unchanged
for index in 0..orig_nodes_len {
for (index, node_rewrite) in node_rewrites.iter_mut().enumerate() {
let node = &self.nodes[index];
match node.state.get() {
NodeState::Pending | NodeState::Waiting => {
if dead_nodes > 0 {
self.nodes.swap(index, index - dead_nodes);
node_rewrites[index] -= dead_nodes;
*node_rewrite -= dead_nodes;
}
}
NodeState::Done => {
@ -646,7 +646,7 @@ impl<O: ForestObligation> ObligationForest<O> {
}
// Extract the success stories.
outcome_cb(&node.obligation);
node_rewrites[index] = orig_nodes_len;
*node_rewrite = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Error => {
@ -655,7 +655,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// check against.
self.active_cache.remove(&node.obligation.as_cache_key());
self.insert_into_error_cache(index);
node_rewrites[index] = orig_nodes_len;
*node_rewrite = orig_nodes_len;
dead_nodes += 1;
}
NodeState::Success => unreachable!(),

View File

@ -205,10 +205,10 @@ impl<K: Ord, V> SortedMap<K, V> {
R: RangeBounds<K>,
{
let start = match range.start_bound() {
Bound::Included(ref k) => match self.lookup_index_for(k) {
Bound::Included(k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Bound::Excluded(k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
@ -216,11 +216,11 @@ impl<K: Ord, V> SortedMap<K, V> {
};
let end = match range.end_bound() {
Bound::Included(ref k) => match self.lookup_index_for(k) {
Bound::Included(k) => match self.lookup_index_for(k) {
Ok(index) => index + 1,
Err(index) => index,
},
Bound::Excluded(ref k) => match self.lookup_index_for(k) {
Bound::Excluded(k) => match self.lookup_index_for(k) {
Ok(index) | Err(index) => index,
},
Bound::Unbounded => self.data.len(),

View File

@ -75,7 +75,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
pub fn get_by_key(&'a self, key: K) -> impl 'a + Iterator<Item = &'a V> {
pub fn get_by_key(&self, key: K) -> impl Iterator<Item = &V> {
self.get_by_key_enumerated(key).map(|(_, v)| v)
}
@ -84,7 +84,7 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> {
///
/// If there are multiple items that are equivalent to `key`, they will be yielded in
/// insertion order.
pub fn get_by_key_enumerated(&'a self, key: K) -> impl '_ + Iterator<Item = (I, &V)> {
pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator<Item = (I, &V)> {
let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key);
self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| {
let (k, v) = &self.items[i];

View File

@ -257,11 +257,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
pub fn remove(&mut self, key: &K) -> Option<V> {
match self {
SsoHashMap::Array(array) => {
if let Some(index) = array.iter().position(|(k, _v)| k == key) {
Some(array.swap_remove(index).1)
} else {
None
}
array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
}
SsoHashMap::Map(map) => map.remove(key),
}
@ -272,11 +268,7 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> {
match self {
SsoHashMap::Array(array) => {
if let Some(index) = array.iter().position(|(k, _v)| k == key) {
Some(array.swap_remove(index))
} else {
None
}
array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index))
}
SsoHashMap::Map(map) => map.remove_entry(key),
}
@ -423,14 +415,14 @@ impl<K, V> IntoIterator for SsoHashMap<K, V> {
/// adapts Item of array reference iterator to Item of hashmap reference iterator.
#[inline(always)]
fn adapt_array_ref_it<K, V>(pair: &'a (K, V)) -> (&'a K, &'a V) {
fn adapt_array_ref_it<K, V>(pair: &(K, V)) -> (&K, &V) {
let (a, b) = pair;
(a, b)
}
/// adapts Item of array mut reference iterator to Item of hashmap mut reference iterator.
#[inline(always)]
fn adapt_array_mut_it<K, V>(pair: &'a mut (K, V)) -> (&'a K, &'a mut V) {
fn adapt_array_mut_it<K, V>(pair: &mut (K, V)) -> (&K, &mut V) {
let (a, b) = pair;
(a, b)
}

View File

@ -75,7 +75,7 @@ impl<T> SsoHashSet<T> {
/// An iterator visiting all elements in arbitrary order.
/// The iterator element type is `&'a T`.
#[inline]
pub fn iter(&'a self) -> impl Iterator<Item = &'a T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.into_iter()
}

View File

@ -229,14 +229,14 @@ impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
impl<CTX> HashStable<CTX> for f32 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let val: u32 = unsafe { ::std::mem::transmute(*self) };
let val: u32 = self.to_bits();
val.hash_stable(ctx, hasher);
}
}
impl<CTX> HashStable<CTX> for f64 {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let val: u64 = unsafe { ::std::mem::transmute(*self) };
let val: u64 = self.to_bits();
val.hash_stable(ctx, hasher);
}
}

View File

@ -5,6 +5,7 @@ const RED_ZONE: usize = 100 * 1024; // 100k
// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then
// on. This flag has performance relevant characteristics. Don't set it too high.
#[allow(clippy::identity_op)]
const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB
/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations

View File

@ -34,7 +34,7 @@ impl<T> Steal<T> {
#[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
let borrow = self.value.borrow();
if let None = &*borrow {
if borrow.is_none() {
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
}
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())

View File

@ -48,7 +48,7 @@ impl<T: PartialEq> TinyList<T> {
#[inline]
pub fn contains(&self, data: &T) -> bool {
let mut elem = self.head.as_ref();
while let Some(ref e) = elem {
while let Some(e) = elem {
if &e.data == data {
return true;
}

View File

@ -2,8 +2,8 @@ use rustc_index::vec::{Idx, IndexVec};
pub fn iter<Ls>(
first: Option<Ls::LinkIndex>,
links: &'a Ls,
) -> impl Iterator<Item = Ls::LinkIndex> + 'a
links: &Ls,
) -> impl Iterator<Item = Ls::LinkIndex> + '_
where
Ls: Links,
{

View File

@ -1253,12 +1253,16 @@ pub fn init_rustc_env_logger() {
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
// Don't register a dispatcher if there's no filter to print anything
match std::env::var(env) {
Err(_) => return,
Ok(s) if s.is_empty() => return,
Ok(_) => {}
}
use tracing_subscriber::{
filter::{self, EnvFilter, LevelFilter},
layer::SubscriberExt,
};
let filter = match std::env::var(env) {
Ok(env) => EnvFilter::new(env),
_ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
};
let color_logs = match std::env::var(String::from(env) + "_COLOR") {
Ok(value) => match value.as_ref() {
"always" => true,
@ -1278,7 +1282,7 @@ pub fn init_env_logger(env: &str) {
"non-Unicode log color value: expected one of always, never, or auto",
),
};
let filter = tracing_subscriber::EnvFilter::from_env(env);
let layer = tracing_tree::HierarchicalLayer::default()
.with_writer(io::stderr)
.with_indent_lines(true)
@ -1288,7 +1292,6 @@ pub fn init_env_logger(env: &str) {
#[cfg(parallel_compiler)]
let layer = layer.with_thread_ids(true).with_thread_names(true);
use tracing_subscriber::layer::SubscriberExt;
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
}

View File

@ -242,6 +242,7 @@ E0468: include_str!("./error_codes/E0468.md"),
E0469: include_str!("./error_codes/E0469.md"),
E0477: include_str!("./error_codes/E0477.md"),
E0478: include_str!("./error_codes/E0478.md"),
E0482: include_str!("./error_codes/E0482.md"),
E0491: include_str!("./error_codes/E0491.md"),
E0492: include_str!("./error_codes/E0492.md"),
E0493: include_str!("./error_codes/E0493.md"),
@ -599,7 +600,6 @@ E0785: include_str!("./error_codes/E0785.md"),
// E0479, // the type `..` (provided as the value of a type parameter) is...
// E0480, // lifetime of method receiver does not outlive the method call
// E0481, // lifetime of function argument does not outlive the function call
E0482, // lifetime of return value does not outlive the function call
// E0483, // lifetime of operand does not outlive the operation
// E0484, // reference is not valid at the time of borrow
// E0485, // automatically reference is not valid at the time of borrow

View File

@ -0,0 +1,73 @@
A lifetime of a returned value does not outlive the function call.
Erroneous code example:
```compile_fail,E0482
fn prefix<'a>(
words: impl Iterator<Item = &'a str>
) -> impl Iterator<Item = String> { // error!
words.map(|v| format!("foo-{}", v))
}
```
To fix this error, make the lifetime of the returned value explicit:
```
fn prefix<'a>(
words: impl Iterator<Item = &'a str> + 'a
) -> impl Iterator<Item = String> + 'a { // ok!
words.map(|v| format!("foo-{}", v))
}
```
The [`impl Trait`] feature in this example uses an implicit `'static` lifetime
restriction in the returned type. However the type implementing the `Iterator`
passed to the function lives just as long as `'a`, which is not long enough.
The solution involves adding lifetime bound to both function argument and
the return value to make sure that the values inside the iterator
are not dropped when the function goes out of the scope.
An alternative solution would be to guarantee that the `Item` references
in the iterator are alive for the whole lifetime of the program.
```
fn prefix(
words: impl Iterator<Item = &'static str>
) -> impl Iterator<Item = String> { // ok!
words.map(|v| format!("foo-{}", v))
}
```
A similar lifetime problem might arise when returning closures:
```compile_fail,E0482
fn foo(
x: &mut Vec<i32>
) -> impl FnMut(&mut Vec<i32>) -> &[i32] { // error!
|y| {
y.append(x);
y
}
}
```
Analogically, a solution here is to use explicit return lifetime
and move the ownership of the variable to the closure.
```
fn foo<'a>(
x: &'a mut Vec<i32>
) -> impl FnMut(&mut Vec<i32>) -> &[i32] + 'a { // ok!
move |y| {
y.append(x);
y
}
}
```
To better understand the lifetime treatment in the [`impl Trait`],
please see the [RFC 1951].
[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html
[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html

View File

@ -2308,7 +2308,7 @@ pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
let found = match sm.span_to_snippet(sp) {
Ok(snippet) => snippet,
Err(e) => {
warn!("Invalid span {:?}. Err={:?}", sp, e);
warn!(error = ?e, "Invalid span {:?}", sp);
return false;
}
};

View File

@ -288,7 +288,7 @@ declare_features! (
(accepted, member_constraints, "1.54.0", Some(61997), None),
/// Allows bindings in the subpattern of a binding pattern.
/// For example, you can write `x @ Some(y)`.
(accepted, bindings_after_at, "1.54.0", Some(65490), None),
(accepted, bindings_after_at, "1.56.0", Some(65490), None),
/// Allows calling `transmute` in const fn
(accepted, const_fn_transmute, "1.56.0", Some(53605), None),
/// Allows accessing fields of unions inside `const` functions.

View File

@ -678,6 +678,9 @@ declare_features! (
/// Allows `#[doc(cfg_hide(...))]`.
(active, doc_cfg_hide, "1.57.0", Some(43781), None),
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------

View File

@ -512,7 +512,7 @@ impl<'a> LabelText<'a> {
pub fn to_dot_string(&self) -> String {
match *self {
LabelStr(ref s) => format!("\"{}\"", s.escape_default()),
EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)),
EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(s)),
HtmlStr(ref s) => format!("<{}>", s),
}
}

View File

@ -2293,6 +2293,13 @@ impl<'hir> InlineAsmOperand<'hir> {
Self::Const { .. } | Self::Sym { .. } => None,
}
}
pub fn is_clobber(&self) -> bool {
matches!(
self,
InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(_), late: _, expr: None }
)
}
}
#[derive(Debug, HashStable_Generic)]

View File

@ -990,9 +990,8 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
pub fn insert_all_into_row(&mut self, row: R) {
assert!(row.index() < self.num_rows);
let (start, end) = self.range(row);
let words = &mut self.words[..];
for index in start..end {
words[index] = !0;
for word in self.words[start..end].iter_mut() {
*word = !0;
}
self.clear_excess_bits(row);
}
@ -1144,7 +1143,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
/// Iterates through all the columns set to true in a given row of
/// the matrix.
pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
pub fn iter(&self, row: R) -> impl Iterator<Item = C> + '_ {
self.row(row).into_iter().flat_map(|r| r.iter())
}

View File

@ -634,18 +634,15 @@ impl<I: Idx, T> IndexVec<I, T> {
}
#[inline]
pub fn drain<'a, R: RangeBounds<usize>>(
&'a mut self,
range: R,
) -> impl Iterator<Item = T> + 'a {
pub fn drain<R: RangeBounds<usize>>(&mut self, range: R) -> impl Iterator<Item = T> + '_ {
self.raw.drain(range)
}
#[inline]
pub fn drain_enumerated<'a, R: RangeBounds<usize>>(
&'a mut self,
pub fn drain_enumerated<R: RangeBounds<usize>>(
&mut self,
range: R,
) -> impl Iterator<Item = (I, T)> + 'a {
) -> impl Iterator<Item = (I, T)> + '_ {
self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
}
@ -741,6 +738,12 @@ impl<I: Idx, T> IndexVec<I, Option<T>> {
self.ensure_contains_elem(index, || None);
self[index].get_or_insert_with(value)
}
#[inline]
pub fn remove(&mut self, index: I) -> Option<T> {
self.ensure_contains_elem(index, || None);
self[index].take()
}
}
impl<I: Idx, T: Clone> IndexVec<I, T> {

View File

@ -2060,14 +2060,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
expected: exp_found.expected.print_only_trait_path(),
found: exp_found.found.print_only_trait_path(),
};
self.expected_found_str(pretty_exp_found)
match self.expected_found_str(pretty_exp_found) {
Some((expected, found)) if expected == found => {
self.expected_found_str(exp_found)
}
ret => ret,
}
}
infer::PolyTraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(),
found: exp_found.found.print_only_trait_path(),
};
self.expected_found_str(pretty_exp_found)
match self.expected_found_str(pretty_exp_found) {
Some((expected, found)) if expected == found => {
self.expected_found_str(exp_found)
}
ret => ret,
}
}
}
}

View File

@ -130,8 +130,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
.tcx()
.sess
.struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
err.span_label(impl_sp, &format!("found"));
err.span_label(trait_sp, &format!("expected"));
err.span_label(impl_sp, "found");
err.span_label(trait_sp, "expected");
err.emit();
}

View File

@ -68,11 +68,10 @@ pub enum EscapeError {
impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
match self {
EscapeError::UnskippedWhitespaceWarning => false,
EscapeError::MultipleSkippedLinesWarning => false,
_ => true,
}
!matches!(
self,
EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
)
}
}
@ -330,7 +329,7 @@ where
callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
}
let tail = &tail[first_non_space..];
if let Some(c) = tail.chars().nth(0) {
if let Some(c) = tail.chars().next() {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
let end = start + first_non_space + c.len_utf8() + 1;

View File

@ -0,0 +1,106 @@
use crate::{context::LintContext, LateContext, LateLintPass};
use rustc_hir as hir;
use rustc_middle::ty::{fold::TypeFoldable, Ty};
use rustc_span::{symbol::sym, Span};
declare_lint! {
/// The `enum_intrinsics_non_enums` lint detects calls to
/// intrinsic functions that require an enum ([`core::mem::discriminant`],
/// [`core::mem::variant_count`]), but are called with a non-enum type.
///
/// [`core::mem::discriminant`]: https://doc.rust-lang.org/core/mem/fn.discriminant.html
/// [`core::mem::variant_count`]: https://doc.rust-lang.org/core/mem/fn.variant_count.html
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(enum_intrinsics_non_enums)]
/// core::mem::discriminant::<i32>(&123);
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In order to accept any enum, the `mem::discriminant` and
/// `mem::variant_count` functions are generic over a type `T`.
/// This makes it technically possible for `T` to be a non-enum,
/// in which case the return value is unspecified.
///
/// This lint prevents such incorrect usage of these functions.
ENUM_INTRINSICS_NON_ENUMS,
Deny,
"detects calls to `core::mem::discriminant` and `core::mem::variant_count` with non-enum types"
}
declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
fn is_non_enum(t: Ty<'_>) -> bool {
!t.is_enum() && !t.potentially_needs_subst()
}
fn enforce_mem_discriminant(
cx: &LateContext<'_>,
func_expr: &hir::Expr<'_>,
expr_span: Span,
args_span: Span,
) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
builder
.build(
"the return value of `mem::discriminant` is \
unspecified when called with a non-enum type",
)
.span_note(
args_span,
&format!(
"the argument to `discriminant` should be a \
reference to an enum, but it was passed \
a reference to a `{}`, which is not an enum.",
ty_param,
),
)
.emit();
});
}
}
fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
if is_non_enum(ty_param) {
cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
builder
.build(
"the return value of `mem::variant_count` is \
unspecified when called with a non-enum type",
)
.note(&format!(
"the type parameter of `variant_count` should \
be an enum, but it was instantiated with \
the type `{}`, which is not an enum.",
ty_param,
))
.emit();
});
}
}
impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
if let hir::ExprKind::Path(ref qpath) = func.kind {
if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
enforce_mem_discriminant(cx, func, expr.span, args[0].span);
} else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
enforce_mem_variant_count(cx, func, expr.span);
}
}
}
}
}
}

View File

@ -1,7 +1,6 @@
use crate::context::{CheckLintNameResult, LintStore};
use crate::late::unerased_lint_store;
use rustc_ast as ast;
use rustc_ast::unwrap_or;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@ -233,7 +232,10 @@ impl<'s> LintLevelsBuilder<'s> {
Some(lvl) => lvl,
};
let mut metas = unwrap_or!(attr.meta_item_list(), continue);
let mut metas = match attr.meta_item_list() {
Some(x) => x,
None => continue,
};
if metas.is_empty() {
// FIXME (#55112): issue unused-attributes lint for `#[level()]`

View File

@ -47,6 +47,7 @@ mod array_into_iter;
pub mod builtin;
mod context;
mod early;
mod enum_intrinsics_non_enums;
mod internal;
mod late;
mod levels;
@ -76,6 +77,7 @@ use rustc_span::Span;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
use internal::*;
use methods::*;
use non_ascii_idents::*;
@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
NonPanicFmt: NonPanicFmt,
NoopMethodCall: NoopMethodCall,
EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
InvalidAtomicOrdering: InvalidAtomicOrdering,
NamedAsmLabels: NamedAsmLabels,
]

View File

@ -230,8 +230,7 @@ fn check_panic_str<'tcx>(
Err(_) => (None, None),
};
let mut fmt_parser =
Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
let mut fmt_parser = Parser::new(fmt, style, snippet.clone(), false, ParseMode::Format);
let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
if n_arguments > 0 && fmt_parser.errors.is_empty() {

View File

@ -6,6 +6,7 @@
use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
declare_lint! {
/// The `forbidden_lint_groups` lint detects violations of
@ -3476,6 +3477,8 @@ declare_lint! {
/// }
///
/// // in crate B
/// #![feature(non_exhaustive_omitted_patterns_lint)]
///
/// match Bar::A {
/// Bar::A => {},
/// #[warn(non_exhaustive_omitted_patterns)]
@ -3512,6 +3515,7 @@ declare_lint! {
pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
Allow,
"detect when patterns of types marked `non_exhaustive` are missed",
@feature_gate = sym::non_exhaustive_omitted_patterns_lint;
}
declare_lint! {

View File

@ -24,11 +24,9 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
}
if meta.path().is_ident("project") {
if let Meta::List(list) = meta {
if let Some(nested) = list.nested.iter().next() {
if let NestedMeta::Meta(meta) = nested {
attrs.project = meta.path().get_ident().cloned();
any_attr = true;
}
if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
attrs.project = meta.path().get_ident().cloned();
any_attr = true;
}
}
}

View File

@ -349,14 +349,14 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
let field_binding = &info.binding.binding;
let option_ty = option_inner_ty(&info.ty);
let option_ty = option_inner_ty(info.ty);
let generated_code = self.generate_non_option_field_code(
attr,
FieldInfo {
vis: info.vis,
binding: info.binding,
ty: option_ty.unwrap_or(&info.ty),
ty: option_ty.unwrap_or(info.ty),
span: info.span,
},
)?;
@ -388,7 +388,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
let formatted_str = self.build_format(&s.value(), attr.span());
match name {
"message" => {
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
if type_matches_path(info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.set_span(*#field_binding);
#diag.set_primary_message(#formatted_str);
@ -401,7 +401,7 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
}
}
"label" => {
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
if type_matches_path(info.ty, &["rustc_span", "Span"]) {
quote! {
#diag.span_label(*#field_binding, #formatted_str);
}

View File

@ -363,7 +363,7 @@ impl Collector<'tcx> {
.collect::<Vec<_>>();
if existing.is_empty() {
// Add if not found
let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
let new_name: Option<&str> = passed_lib.new_name.as_deref();
let lib = NativeLib {
name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
kind: passed_lib.kind,

View File

@ -63,6 +63,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_query_system::dep_graph::FingerprintStyle;
use rustc_span::symbol::Symbol;
use std::hash::Hash;
@ -89,9 +90,9 @@ pub struct DepKindStruct {
/// Whether the query key can be recovered from the hashed fingerprint.
/// See [DepNodeParams] trait for the behaviour of each key type.
// FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key
// FIXME: Make this a simple boolean once DepNodeParams::fingerprint_style
// can be made a specialized associated const.
can_reconstruct_query_key: fn() -> bool,
fingerprint_style: fn() -> FingerprintStyle,
}
impl std::ops::Deref for DepKind {
@ -103,14 +104,14 @@ impl std::ops::Deref for DepKind {
impl DepKind {
#[inline(always)]
pub fn can_reconstruct_query_key(&self) -> bool {
pub fn fingerprint_style(&self) -> FingerprintStyle {
// Only fetch the DepKindStruct once.
let data: &DepKindStruct = &**self;
if data.is_anon {
return false;
return FingerprintStyle::Opaque;
}
(data.can_reconstruct_query_key)()
(data.fingerprint_style)()
}
}
@ -151,6 +152,7 @@ macro_rules! contains_eval_always_attr {
pub mod dep_kind {
use super::*;
use crate::ty::query::query_keys;
use rustc_query_system::dep_graph::FingerprintStyle;
// We use this for most things when incr. comp. is turned off.
pub const Null: DepKindStruct = DepKindStruct {
@ -158,7 +160,7 @@ pub mod dep_kind {
is_anon: false,
is_eval_always: false,
can_reconstruct_query_key: || true,
fingerprint_style: || FingerprintStyle::Unit,
};
pub const TraitSelect: DepKindStruct = DepKindStruct {
@ -166,7 +168,7 @@ pub mod dep_kind {
is_anon: true,
is_eval_always: false,
can_reconstruct_query_key: || true,
fingerprint_style: || FingerprintStyle::Unit,
};
pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
@ -174,7 +176,7 @@ pub mod dep_kind {
is_anon: false,
is_eval_always: false,
can_reconstruct_query_key: || false,
fingerprint_style: || FingerprintStyle::Opaque,
};
pub const CompileMonoItem: DepKindStruct = DepKindStruct {
@ -182,7 +184,7 @@ pub mod dep_kind {
is_anon: false,
is_eval_always: false,
can_reconstruct_query_key: || false,
fingerprint_style: || FingerprintStyle::Opaque,
};
macro_rules! define_query_dep_kinds {
@ -196,16 +198,16 @@ pub mod dep_kind {
const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
fn fingerprint_style() -> rustc_query_system::dep_graph::FingerprintStyle {
<query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
::can_reconstruct_query_key()
::fingerprint_style()
}
DepKindStruct {
has_params,
is_anon,
is_eval_always,
can_reconstruct_query_key,
fingerprint_style,
}
};)*
);
@ -320,7 +322,7 @@ impl DepNodeExt for DepNode {
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
debug_assert!(kind.can_reconstruct_query_key() && kind.has_params);
debug_assert!(kind.fingerprint_style() == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
}
@ -335,7 +337,7 @@ impl DepNodeExt for DepNode {
/// refers to something from the previous compilation session that
/// has been removed.
fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
if self.kind.can_reconstruct_query_key() {
if self.kind.fingerprint_style() == FingerprintStyle::DefPathHash {
Some(
tcx.on_disk_cache
.as_ref()?
@ -350,14 +352,16 @@ impl DepNodeExt for DepNode {
fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
if !kind.can_reconstruct_query_key() {
return Err(());
}
if kind.has_params {
Ok(DepNode::from_def_path_hash(def_path_hash, kind))
} else {
Ok(DepNode::new_no_params(kind))
match kind.fingerprint_style() {
FingerprintStyle::Opaque => Err(()),
FingerprintStyle::Unit => {
if !kind.has_params {
Ok(DepNode::new_no_params(kind))
} else {
Err(())
}
}
FingerprintStyle::DefPathHash => Ok(DepNode::from_def_path_hash(def_path_hash, kind)),
}
}
@ -369,8 +373,8 @@ impl DepNodeExt for DepNode {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Unit
}
fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
@ -384,8 +388,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
}
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
@ -403,8 +407,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
}
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
@ -422,8 +426,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
}
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
@ -442,8 +446,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
false
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
}
// We actually would not need to specialize the implementation of this
@ -467,8 +471,8 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
false
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
}
// We actually would not need to specialize the implementation of this

View File

@ -25,8 +25,8 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
const NULL: Self = DepKind::Null;
#[inline(always)]
fn can_reconstruct_query_key(&self) -> bool {
DepKind::can_reconstruct_query_key(self)
fn fingerprint_style(&self) -> rustc_query_system::dep_graph::FingerprintStyle {
DepKind::fingerprint_style(self)
}
#[inline(always)]

View File

@ -264,14 +264,14 @@ impl EvaluationResult {
/// Indicates that trait evaluation caused overflow and in which pass.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
pub enum OverflowError {
Cannonical,
Canonical,
ErrorReporting,
}
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
match overflow_error {
OverflowError::Cannonical => SelectionError::Overflow,
OverflowError::Canonical => SelectionError::Overflow,
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
}
}

View File

@ -986,7 +986,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let niche = if def.repr.hide_niche() {
None
} else {
Niche::from_scalar(dl, Size::ZERO, scalar.clone())
Niche::from_scalar(dl, Size::ZERO, *scalar)
};
if let Some(niche) = niche {
match st.largest_niche {
@ -2273,7 +2273,7 @@ where
) -> TyMaybeWithLayout<'tcx> {
let tcx = cx.tcx();
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
let layout = Layout::scalar(cx, tag.clone());
let layout = Layout::scalar(cx, tag);
TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
};
@ -3012,7 +3012,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
};
let target = &self.tcx.sess.target;
let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl");
let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
let linux_s390x_gnu_like =
target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
@ -3110,7 +3110,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
if arg.layout.is_zst() {
// For some forsaken reason, x86_64-pc-windows-gnu
// doesn't ignore zero-sized struct arguments.
// The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl}.
// The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
if is_return
|| rust_abi
|| (!win_x64_gnu

View File

@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Call {
func: exchange_malloc,
args: vec![Operand::Move(size), Operand::Move(align)],
destination: Some((Place::from(storage), success)),
destination: Some((storage, success)),
cleanup: None,
from_hir_call: false,
fn_span: expr_span,
@ -153,7 +153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// Transmute `*mut u8` to the box (thus far, uninitialized):
let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty);
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value.ty);
this.cfg.push_assign(block, source_info, Place::from(result), box_);
// initialize the box contents:

View File

@ -1068,9 +1068,7 @@ impl<'tcx> SplitWildcard<'tcx> {
Missing {
nonexhaustive_enum_missing_real_variants: self
.iter_missing(pcx)
.filter(|c| !c.is_non_exhaustive())
.next()
.is_some(),
.any(|c| !c.is_non_exhaustive()),
}
} else {
Missing { nonexhaustive_enum_missing_real_variants: false }

View File

@ -289,7 +289,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
flow_state: &BitSet<Local>,
call: PeekCall,
) {
warn!("peek_at: place={:?}", place);
info!(?place, "peek_at");
let local = if let Some(l) = place.as_local() {
l
} else {
@ -311,7 +311,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
flow_state: &BitSet<Local>,
call: PeekCall,
) {
warn!("peek_at: place={:?}", place);
info!(?place, "peek_at");
let local = if let Some(l) = place.as_local() {
l
} else {

View File

@ -263,7 +263,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
}
// check that the value being matched on is the same. The
if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() {
if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) {
trace!("NO: values being matched on are not the same");
return None;
}

View File

@ -111,8 +111,7 @@ impl<'a, 'tcx> Patcher<'a, 'tcx> {
Operand::Copy(place) | Operand::Move(place) => {
// create new local
let ty = operand.ty(self.local_decls, self.tcx);
let local_decl =
LocalDecl::with_source_info(ty, statement.source_info.clone());
let local_decl = LocalDecl::with_source_info(ty, statement.source_info);
let local = self.local_decls.push(local_decl);
// make it live
let mut make_live_statement = statement.clone();

View File

@ -1096,7 +1096,7 @@ impl<'a> Parser<'a> {
(Err(ref mut err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
let name = pprust::path_to_string(&path);
snapshot.bump(); // `(`
match snapshot.parse_struct_fields(path.clone(), false, token::Paren) {
match snapshot.parse_struct_fields(path, false, token::Paren) {
Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => {
// We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
// `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.

View File

@ -1767,8 +1767,7 @@ impl CheckAttrVisitor<'tcx> {
fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if target != Target::MacroDef {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!("`#[macro_export]` only has an effect on macro definitions"))
.emit();
lint.build("`#[macro_export]` only has an effect on macro definitions").emit();
});
}
}

View File

@ -8,7 +8,6 @@
//! through, but errors for structured control flow in a `const` should be emitted here.
use rustc_attr as attr;
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
@ -83,32 +82,41 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
let _: Option<_> = try {
if let hir::ItemKind::Impl(ref imp) = item.kind {
if let hir::Constness::Const = imp.constness {
let did = imp.of_trait.as_ref()?.trait_def_id()?;
let mut to_implement = FxHashSet::default();
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
let ancestors = self
.tcx
.trait_def(trait_def_id)
.ancestors(self.tcx, item.def_id.to_def_id())
.ok()?;
let mut to_implement = Vec::new();
for did in self.tcx.associated_item_def_ids(did) {
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
{
if let ty::AssocItem {
kind: ty::AssocKind::Fn, ident, defaultness, ..
} = self.tcx.associated_item(*did)
} = trait_item
{
// we can ignore functions that do not have default bodies:
// if those are unimplemented it will be catched by typeck.
if defaultness.has_value()
&& !self.tcx.has_attr(*did, sym::default_method_body_is_const)
if !defaultness.has_value()
|| self
.tcx
.has_attr(trait_item.def_id, sym::default_method_body_is_const)
{
to_implement.insert(ident);
continue;
}
let is_implemented = ancestors
.leaf_def(self.tcx, trait_item.ident, trait_item.kind)
.map(|node_item| !node_item.defining_node.is_from_trait())
.unwrap_or(false);
if !is_implemented {
to_implement.push(ident.to_string());
}
}
}
for it in imp
.items
.iter()
.filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. }))
{
to_implement.remove(&it.ident);
}
// all nonconst trait functions (not marked with #[default_method_body_is_const])
// must be implemented
if !to_implement.is_empty() {
@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<
item.span,
"const trait implementations may not use non-const default functions",
)
.note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::<Vec<_>>().join("`, `")))
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
.emit();
}
}

View File

@ -141,6 +141,7 @@ impl ExprVisitor<'tcx> {
template: &[InlineAsmTemplatePiece],
is_input: bool,
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
target_features: &[Symbol],
) -> Option<InlineAsmType> {
// Check the type against the allowed types for inline asm.
let ty = self.typeck_results.expr_ty_adjusted(expr);
@ -283,17 +284,20 @@ impl ExprVisitor<'tcx> {
};
// Check whether the selected type requires a target feature. Note that
// this is different from the feature check we did earlier in AST
// lowering. While AST lowering checked that this register class is
// usable at all with the currently enabled features, some types may
// only be usable with a register class when a certain feature is
// enabled. We check this here since it depends on the results of typeck.
// this is different from the feature check we did earlier. While the
// previous check checked that this register class is usable at all
// with the currently enabled features, some types may only be usable
// with a register class when a certain feature is enabled. We check
// this here since it depends on the results of typeck.
//
// Also note that this check isn't run when the operand type is never
// (!). In that case we still need the earlier check in AST lowering to
// verify that the register class is usable at all.
// (!). In that case we still need the earlier check to verify that the
// register class is usable at all.
if let Some(feature) = feature {
if !self.tcx.sess.target_features.contains(&Symbol::intern(feature)) {
let feat_sym = Symbol::intern(feature);
if !self.tcx.sess.target_features.contains(&feat_sym)
&& !target_features.contains(&feat_sym)
{
let msg = &format!("`{}` target feature is not enabled", feature);
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(&format!(
@ -349,23 +353,122 @@ impl ExprVisitor<'tcx> {
Some(asm_ty)
}
fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
for (idx, (op, _)) in asm.operands.iter().enumerate() {
fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
let hir = self.tcx.hir();
let enclosing_id = hir.enclosing_body_owner(hir_id);
let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id();
let attrs = self.tcx.codegen_fn_attrs(enclosing_def_id);
for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
// Validate register classes against currently enabled target
// features. We check that at least one type is available for
// the enabled features.
//
// We ignore target feature requirements for clobbers: if the
// feature is disabled then the compiler doesn't care what we
// do with the registers.
//
// Note that this is only possible for explicit register
// operands, which cannot be used in the asm string.
if let Some(reg) = op.reg() {
if !op.is_clobber() {
let mut missing_required_features = vec![];
let reg_class = reg.reg_class();
for &(_, feature) in reg_class.supported_types(self.tcx.sess.asm_arch.unwrap())
{
match feature {
Some(feature) => {
let feat_sym = Symbol::intern(feature);
if self.tcx.sess.target_features.contains(&feat_sym)
|| attrs.target_features.contains(&feat_sym)
{
missing_required_features.clear();
break;
} else {
missing_required_features.push(feature);
}
}
None => {
missing_required_features.clear();
break;
}
}
}
// We are sorting primitive strs here and can use unstable sort here
missing_required_features.sort_unstable();
missing_required_features.dedup();
match &missing_required_features[..] {
[] => {}
[feature] => {
let msg = format!(
"register class `{}` requires the `{}` target feature",
reg_class.name(),
feature
);
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
// register isn't enabled, don't do more checks
continue;
}
features => {
let msg = format!(
"register class `{}` requires at least one of the following target features: {}",
reg_class.name(),
features.join(", ")
);
self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
// register isn't enabled, don't do more checks
continue;
}
}
}
}
match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
true,
None,
&attrs.target_features,
);
}
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
if let Some(expr) = expr {
self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
false,
None,
&attrs.target_features,
);
}
}
hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
self.check_asm_operand_type(
idx,
reg,
expr,
asm.template,
false,
None,
&attrs.target_features,
);
}
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
let in_ty =
self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
let in_ty = self.check_asm_operand_type(
idx,
reg,
in_expr,
asm.template,
true,
None,
&attrs.target_features,
);
if let Some(out_expr) = out_expr {
self.check_asm_operand_type(
idx,
@ -374,6 +477,7 @@ impl ExprVisitor<'tcx> {
asm.template,
false,
Some((in_expr, in_ty)),
&attrs.target_features,
);
}
}
@ -422,7 +526,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> {
}
}
hir::ExprKind::InlineAsm(asm) => self.check_asm(asm),
hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id),
_ => {}
}

View File

@ -428,6 +428,7 @@ macro_rules! define_queries {
use rustc_middle::ty::query::query_keys;
use rustc_query_system::dep_graph::DepNodeParams;
use rustc_query_system::query::{force_query, QueryDescription};
use rustc_query_system::dep_graph::FingerprintStyle;
// We use this for most things when incr. comp. is turned off.
pub const Null: QueryStruct = QueryStruct {
@ -454,9 +455,9 @@ macro_rules! define_queries {
const is_anon: bool = is_anon!([$($modifiers)*]);
#[inline(always)]
fn can_reconstruct_query_key() -> bool {
fn fingerprint_style() -> FingerprintStyle {
<query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
::can_reconstruct_query_key()
::fingerprint_style()
}
fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
@ -472,7 +473,7 @@ macro_rules! define_queries {
return
}
if !can_reconstruct_query_key() {
if !fingerprint_style().reconstructible() {
return
}

View File

@ -5,8 +5,6 @@ use rustc_query_system::query::{QueryCache, QueryCacheStore};
use std::any::type_name;
use std::mem;
#[cfg(debug_assertions)]
use std::sync::atomic::Ordering;
trait KeyStats {
fn key_stats(&self, stats: &mut QueryStats);
@ -27,7 +25,6 @@ impl KeyStats for DefId {
#[derive(Clone)]
struct QueryStats {
name: &'static str,
cache_hits: usize,
key_size: usize,
key_type: &'static str,
value_size: usize,
@ -42,10 +39,6 @@ where
{
let mut stats = QueryStats {
name,
#[cfg(debug_assertions)]
cache_hits: map.cache_hits.load(Ordering::Relaxed),
#[cfg(not(debug_assertions))]
cache_hits: 0,
key_size: mem::size_of::<C::Key>(),
key_type: type_name::<C::Key>(),
value_size: mem::size_of::<C::Value>(),
@ -63,12 +56,6 @@ where
pub fn print_stats(tcx: TyCtxt<'_>) {
let queries = query_stats(tcx);
if cfg!(debug_assertions) {
let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
let results: usize = queries.iter().map(|s| s.entry_count).sum();
eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
}
let mut query_key_sizes = queries.clone();
query_key_sizes.sort_by_key(|q| q.key_size);
eprintln!("\nLarge query keys:");
@ -83,20 +70,6 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
}
if cfg!(debug_assertions) {
let mut query_cache_hits = queries.clone();
query_cache_hits.sort_by_key(|q| q.cache_hits);
eprintln!("\nQuery cache hits:");
for q in query_cache_hits.iter().rev() {
eprintln!(
" {} - {} ({}%)",
q.name,
q.cache_hits,
q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64
);
}
}
let mut query_value_count = queries.clone();
query_value_count.sort_by_key(|q| q.entry_count);
eprintln!("\nQuery value count:");

View File

@ -42,7 +42,7 @@
//! `DefId` it was computed from. In other cases, too much information gets
//! lost during fingerprint computation.
use super::{DepContext, DepKind};
use super::{DepContext, DepKind, FingerprintStyle};
use crate::ich::StableHashingContext;
use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
@ -75,7 +75,7 @@ impl<K: DepKind> DepNode<K> {
#[cfg(debug_assertions)]
{
if !kind.can_reconstruct_query_key()
if !kind.fingerprint_style().reconstructible()
&& (tcx.sess().opts.debugging_opts.incremental_info
|| tcx.sess().opts.debugging_opts.query_dep_graph)
{
@ -94,7 +94,7 @@ impl<K: DepKind> fmt::Debug for DepNode<K> {
}
pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
fn can_reconstruct_query_key() -> bool;
fn fingerprint_style() -> FingerprintStyle;
/// This method turns the parameters of a DepNodeConstructor into an opaque
/// Fingerprint to be used in DepNode.
@ -111,7 +111,7 @@ pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
/// This method tries to recover the query key from the given `DepNode`,
/// something which is needed when forcing `DepNode`s during red-green
/// evaluation. The query system will only call this method if
/// `can_reconstruct_query_key()` is `true`.
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
/// It is always valid to return `None` here, in which case incremental
/// compilation will treat the query as having changed instead of forcing it.
fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
@ -122,8 +122,8 @@ where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
#[inline]
default fn can_reconstruct_query_key() -> bool {
false
default fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
}
default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {

View File

@ -50,6 +50,27 @@ impl<T: DepContext> HasDepContext for T {
}
}
/// Describes the contents of the fingerprint generated by a given query.
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
/// Query key was `()` or equivalent, so fingerprint is just zero.
Unit,
/// Some opaque hash.
Opaque,
}
impl FingerprintStyle {
#[inline]
pub fn reconstructible(self) -> bool {
match self {
FingerprintStyle::DefPathHash | FingerprintStyle::Unit => true,
FingerprintStyle::Opaque => false,
}
}
}
/// Describe the different families of dependency nodes.
pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
const NULL: Self;
@ -73,5 +94,5 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder>
where
OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
fn can_reconstruct_query_key(&self) -> bool;
fn fingerprint_style(&self) -> FingerprintStyle;
}

View File

@ -26,24 +26,15 @@ use std::hash::{Hash, Hasher};
use std::mem;
use std::num::NonZeroU32;
use std::ptr;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct QueryCacheStore<C: QueryCache> {
cache: C,
shards: Sharded<C::Sharded>,
#[cfg(debug_assertions)]
pub cache_hits: AtomicUsize,
}
impl<C: QueryCache + Default> Default for QueryCacheStore<C> {
fn default() -> Self {
Self {
cache: C::default(),
shards: Default::default(),
#[cfg(debug_assertions)]
cache_hits: AtomicUsize::new(0),
}
Self { cache: C::default(), shards: Default::default() }
}
}
@ -377,10 +368,6 @@ where
if unlikely!(tcx.profiler().enabled()) {
tcx.profiler().query_cache_hit(index.into());
}
#[cfg(debug_assertions)]
{
cache.cache_hits.fetch_add(1, Ordering::Relaxed);
}
tcx.dep_graph().read_index(index);
on_hit(value)
})
@ -429,10 +416,6 @@ where
if unlikely!(tcx.dep_context().profiler().enabled()) {
tcx.dep_context().profiler().query_cache_hit(index.into());
}
#[cfg(debug_assertions)]
{
cache.cache_hits.fetch_add(1, Ordering::Relaxed);
}
query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
(v, Some(index))
@ -540,7 +523,7 @@ where
// We always expect to find a cached result for things that
// can be forced from `DepNode`.
debug_assert!(
!dep_node.kind.can_reconstruct_query_key() || result.is_some(),
!dep_node.kind.fingerprint_style().reconstructible() || result.is_some(),
"missing on-disk cache entry for {:?}",
dep_node
);
@ -705,10 +688,6 @@ where
if unlikely!(tcx.dep_context().profiler().enabled()) {
tcx.dep_context().profiler().query_cache_hit(index.into());
}
#[cfg(debug_assertions)]
{
cache.cache_hits.fetch_add(1, Ordering::Relaxed);
}
});
let lookup = match cached {
@ -778,7 +757,7 @@ where
return false;
}
if !<Q::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
if !<Q::Key as DepNodeParams<CTX::DepContext>>::fingerprint_style().reconstructible() {
return false;
}

View File

@ -9,7 +9,6 @@ use crate::{BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak};
use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
use rustc_ast::unwrap_or;
use rustc_ast::NodeId;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::ptr_key::PtrKey;
@ -349,10 +348,10 @@ impl<'a> Resolver<'a> {
if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
continue;
}
let module = unwrap_or!(
single_import.imported_module.get(),
return Err((Undetermined, Weak::No))
);
let module = match single_import.imported_module.get() {
Some(x) => x,
None => return Err((Undetermined, Weak::No)),
};
let ident = match single_import.kind {
ImportKind::Single { source, .. } => source,
_ => unreachable!(),

View File

@ -500,8 +500,8 @@ impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] {
d.read_seq(|d, len| {
assert!(len == N);
let mut v = [0u8; N];
for i in 0..len {
v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
for x in &mut v {
*x = d.read_seq_elt(|d| Decodable::decode(d))?;
}
Ok(v)
})

View File

@ -816,6 +816,7 @@ symbols! {
mem_size_of,
mem_size_of_val,
mem_uninitialized,
mem_variant_count,
mem_zeroed,
member_constraints,
memory,
@ -893,6 +894,7 @@ symbols! {
nomem,
non_ascii_idents,
non_exhaustive,
non_exhaustive_omitted_patterns_lint,
non_modrs_mods,
none_error,
nontemporal_store,

View File

@ -0,0 +1,24 @@
use crate::spec::{Target, TargetOptions};
// This target is for uclibc Linux on ARMv7 without NEON or
// thumb-mode. See the thumbv7neon variant for enabling both.
pub fn target() -> Target {
let base = super::linux_uclibc_base::opts();
Target {
llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
arch: "arm".to_string(),
options: TargetOptions {
// Info about features at https://wiki.debian.org/ArmHardFloatPort
features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
cpu: "generic".to_string(),
max_atomic_width: Some(64),
mcount: "_mcount".to_string(),
abi: "eabihf".to_string(),
..base
},
}
}

View File

@ -952,6 +952,8 @@ supported_targets! {
("bpfel-unknown-none", bpfel_unknown_none),
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
}
/// Warnings encountered when parsing the target `json`.

View File

@ -278,14 +278,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
if self.is_poly == false {
if !self.is_poly {
visit::walk_expr(self, expr)
}
}
fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
if self.is_poly == false {
if !self.is_poly {
visit::walk_pat(self, pat);
}
}
@ -298,7 +298,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
visit::walk_expr(&mut is_poly_vis, &body[body_id]);
debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
if is_poly_vis.is_poly == false {
if !is_poly_vis.is_poly {
return Ok(None);
}

View File

@ -704,7 +704,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
.filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
.collect();
never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::Send).unwrap());
if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
never_suggest_borrow.push(def_id);
}
let param_env = obligation.param_env;
let trait_ref = poly_trait_ref.skip_binder();

View File

@ -83,10 +83,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
) -> EvaluationResult {
match self.evaluate_obligation(obligation) {
Ok(result) => result,
Err(OverflowError::Cannonical) => {
Err(OverflowError::Canonical) => {
let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
OverflowError::Cannonical => {
OverflowError::Canonical => {
span_bug!(
obligation.cause.span,
"Overflow should be caught earlier in standard query mode: {:?}, {:?}",

View File

@ -161,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
}
Ok(_) => Ok(None),
Err(OverflowError::Cannonical) => Err(Overflow),
Err(OverflowError::Canonical) => Err(Overflow),
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
})
.flat_map(Result::transpose)

View File

@ -900,7 +900,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError::Cannonical),
Err(Overflow) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
Err(..) => Ok(EvaluatedToErr),
}
@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.infcx.report_overflow_error(error_obligation, true);
}
TraitQueryMode::Canonical => {
return Err(OverflowError::Cannonical);
return Err(OverflowError::Canonical);
}
}
}

View File

@ -892,7 +892,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
ty::BoundRegionKind::BrNamed(def_id, _name) => {
if self.named_parameters.iter().find(|d| **d == def_id).is_none() {
if !self.named_parameters.iter().any(|d| *d == def_id) {
self.named_parameters.push(def_id);
}
}

View File

@ -329,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let obligation = Obligation::new(
ObligationCause::dummy_with_span(callee_expr.span),
self.param_env,
predicate.clone(),
*predicate,
);
let result = self.infcx.evaluate_obligation(&obligation);
self.tcx

View File

@ -431,7 +431,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.sess
.source_map()
.span_to_snippet(self.expr.span)
.map_or(false, |snip| snip.starts_with("("));
.map_or(false, |snip| snip.starts_with('('));
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).

View File

@ -1887,7 +1887,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let expr_snippet =
self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new());
let is_wrapped = expr_snippet.starts_with("(") && expr_snippet.ends_with(")");
let is_wrapped = expr_snippet.starts_with('(') && expr_snippet.ends_with(')');
let after_open = expr.span.lo() + rustc_span::BytePos(1);
let before_close = expr.span.hi() - rustc_span::BytePos(1);

View File

@ -753,17 +753,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
let impl_ty = impl_ty.subst(self.tcx, impl_substs);
debug!("impl_ty: {:?}", impl_ty);
// Determine the receiver type that the method itself expects.
let xform_tys = self.xform_self_ty(&item, impl_ty, impl_substs);
let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, impl_ty, impl_substs);
debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty);
// We can't use normalize_associated_types_in as it will pollute the
// fcx's fulfillment context after this probe is over.
// Note: we only normalize `xform_self_ty` here since the normalization
// of the return type can lead to inference results that prohibit
// valid canidates from being found, see issue #85671
// FIXME Postponing the normalization of the return type likely only hides a deeper bug,
// which might be caused by the `param_env` itself. The clauses of the `param_env`
// maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized,
// see isssue #89650
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let selcx = &mut traits::SelectionContext::new(self.fcx);
let traits::Normalized { value: (xform_self_ty, xform_ret_ty), obligations } =
traits::normalize(selcx, self.param_env, cause, xform_tys);
let traits::Normalized { value: xform_self_ty, obligations } =
traits::normalize(selcx, self.param_env, cause, xform_self_ty);
debug!(
"assemble_inherent_impl_probe: xform_self_ty = {:?}/{:?}",
"assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}",
xform_self_ty, xform_ret_ty
);
@ -1420,6 +1430,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
};
let mut result = ProbeResult::Match;
let mut xform_ret_ty = probe.xform_ret_ty;
debug!(?xform_ret_ty);
let selcx = &mut traits::SelectionContext::new(self);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
@ -1428,7 +1441,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
InherentImplCandidate(substs, ref ref_obligations) => {
InherentImplCandidate(ref substs, ref ref_obligations) => {
// `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`,
// see the reasons mentioned in the comments in `assemble_inherent_impl_probe`
// for why this is necessary
let traits::Normalized {
value: normalized_xform_ret_ty,
obligations: normalization_obligations,
} = traits::normalize(selcx, self.param_env, cause.clone(), probe.xform_ret_ty);
xform_ret_ty = normalized_xform_ret_ty;
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
// Check whether the impl imposes obligations we have to worry about.
let impl_def_id = probe.item.container.id();
let impl_bounds = self.tcx.predicates_of(impl_def_id);
@ -1442,7 +1465,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let candidate_obligations = impl_obligations
.chain(norm_obligations.into_iter())
.chain(ref_obligations.iter().cloned());
.chain(ref_obligations.iter().cloned())
.chain(normalization_obligations.into_iter());
// Evaluate those obligations to see if they might possibly hold.
for o in candidate_obligations {
let o = self.resolve_vars_if_possible(o);
@ -1527,9 +1552,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
if let ProbeResult::Match = result {
if let (Some(return_ty), Some(xform_ret_ty)) =
(self.return_type, probe.xform_ret_ty)
{
if let (Some(return_ty), Some(xform_ret_ty)) = (self.return_type, xform_ret_ty) {
let xform_ret_ty = self.resolve_vars_if_possible(xform_ret_ty);
debug!(
"comparing return_ty {:?} with xform ret ty {:?}",
@ -1669,6 +1692,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.static_candidates.push(source);
}
#[instrument(level = "debug", skip(self))]
fn xform_self_ty(
&self,
item: &ty::AssocItem,
@ -1683,9 +1707,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
#[instrument(level = "debug", skip(self))]
fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<'tcx> {
let fn_sig = self.tcx.fn_sig(method);
debug!("xform_self_ty(fn_sig={:?}, substs={:?})", fn_sig, substs);
debug!(?fn_sig);
assert!(!substs.has_escaping_bound_vars());

View File

@ -413,7 +413,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
}
hir::ExprKind::Match(ref discr, arms, _) => {
self.link_match(discr, &arms[..]);
self.link_match(discr, arms);
intravisit::walk_expr(self, expr);
}

View File

@ -65,6 +65,7 @@ use std::iter;
enum PlaceAncestryRelation {
Ancestor,
Descendant,
SamePlace,
Divergent,
}
@ -564,7 +565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for possible_ancestor in min_cap_list.iter_mut() {
match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
// current place is descendant of possible_ancestor
PlaceAncestryRelation::Descendant => {
PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
ancestor_found = true;
let backup_path_expr_id = possible_ancestor.info.path_expr_id;
@ -2278,15 +2279,17 @@ fn determine_place_ancestry_relation(
let projections_b = &place_b.projections;
let same_initial_projections =
iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a == proj_b);
iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a.kind == proj_b.kind);
if same_initial_projections {
use std::cmp::Ordering;
// First min(n, m) projections are the same
// Select Ancestor/Descendant
if projections_b.len() >= projections_a.len() {
PlaceAncestryRelation::Ancestor
} else {
PlaceAncestryRelation::Descendant
match projections_b.len().cmp(&projections_a.len()) {
Ordering::Greater => PlaceAncestryRelation::Ancestor,
Ordering::Equal => PlaceAncestryRelation::SamePlace,
Ordering::Less => PlaceAncestryRelation::Descendant,
}
} else {
PlaceAncestryRelation::Divergent

View File

@ -3,6 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Symbol;
use rustc_trait_selection::traits::{self, SkipLeakCheck};
@ -158,14 +159,18 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
// This is advantageous to running the algorithm over the
// entire graph when there are many connected regions.
rustc_index::newtype_index! {
pub struct RegionId {
ENCODABLE = custom
}
}
struct ConnectedRegion {
idents: SmallVec<[Symbol; 8]>,
impl_blocks: FxHashSet<usize>,
}
// Highest connected region id
let mut highest_region_id = 0;
let mut connected_regions: IndexVec<RegionId, _> = Default::default();
// Reverse map from the Symbol to the connected region id.
let mut connected_region_ids = FxHashMap::default();
let mut connected_regions = FxHashMap::default();
for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() {
if impl_items.len() == 0 {
@ -173,7 +178,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
}
// First obtain a list of existing connected region ids
let mut idents_to_add = SmallVec::<[Symbol; 8]>::new();
let ids = impl_items
let mut ids = impl_items
.in_definition_order()
.filter_map(|item| {
let entry = connected_region_ids.entry(item.ident.name);
@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
None
}
})
.collect::<FxHashSet<usize>>();
match ids.len() {
0 | 1 => {
let id_to_set = if ids.is_empty() {
// Create a new connected region
let region = ConnectedRegion {
.collect::<SmallVec<[RegionId; 8]>>();
// Sort the id list so that the algorithm is deterministic
ids.sort_unstable();
let ids = ids;
match &ids[..] {
// Create a new connected region
[] => {
let id_to_set = connected_regions.next_index();
// Update the connected region ids
for ident in &idents_to_add {
connected_region_ids.insert(*ident, id_to_set);
}
connected_regions.insert(
id_to_set,
ConnectedRegion {
idents: idents_to_add,
impl_blocks: std::iter::once(i).collect(),
};
connected_regions.insert(highest_region_id, region);
(highest_region_id, highest_region_id += 1).0
} else {
// Take the only id inside the list
let id_to_set = *ids.iter().next().unwrap();
let region = connected_regions.get_mut(&id_to_set).unwrap();
region.impl_blocks.insert(i);
region.idents.extend_from_slice(&idents_to_add);
id_to_set
};
let (_id, region) = connected_regions.iter().next().unwrap();
},
);
}
// Take the only id inside the list
&[id_to_set] => {
let region = connected_regions[id_to_set].as_mut().unwrap();
region.impl_blocks.insert(i);
region.idents.extend_from_slice(&idents_to_add);
// Update the connected region ids
for ident in region.idents.iter() {
for ident in &idents_to_add {
connected_region_ids.insert(*ident, id_to_set);
}
}
_ => {
// We have multiple connected regions to merge.
// In the worst case this might add impl blocks
// one by one and can thus be O(n^2) in the size
// of the resulting final connected region, but
// this is no issue as the final step to check
// for overlaps runs in O(n^2) as well.
// Take the smallest id from the list
let id_to_set = *ids.iter().min().unwrap();
// Sort the id list so that the algorithm is deterministic
let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>();
ids.sort_unstable();
let mut region = connected_regions.remove(&id_to_set).unwrap();
region.idents.extend_from_slice(&idents_to_add);
// We have multiple connected regions to merge.
// In the worst case this might add impl blocks
// one by one and can thus be O(n^2) in the size
// of the resulting final connected region, but
// this is no issue as the final step to check
// for overlaps runs in O(n^2) as well.
&[id_to_set, ..] => {
let mut region = connected_regions.remove(id_to_set).unwrap();
region.impl_blocks.insert(i);
region.idents.extend_from_slice(&idents_to_add);
// Update the connected region ids
for ident in &idents_to_add {
connected_region_ids.insert(*ident, id_to_set);
}
// Remove other regions from ids.
for &id in ids.iter() {
if id == id_to_set {
continue;
}
let r = connected_regions.remove(&id).unwrap();
// Update the connected region ids
let r = connected_regions.remove(id).unwrap();
for ident in r.idents.iter() {
connected_region_ids.insert(*ident, id_to_set);
}
region.idents.extend_from_slice(&r.idents);
region.impl_blocks.extend(r.impl_blocks);
}
connected_regions.insert(id_to_set, region);
}
}
@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
let avg = impls.len() / connected_regions.len();
let s = connected_regions
.iter()
.map(|r| r.1.impl_blocks.len() as isize - avg as isize)
.flatten()
.map(|r| r.impl_blocks.len() as isize - avg as isize)
.map(|v| v.abs() as usize)
.sum::<usize>();
s / connected_regions.len()
},
connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap()
connected_regions
.iter()
.flatten()
.map(|r| r.impl_blocks.len())
.max()
.unwrap()
);
// List of connected regions is built. Now, run the overlap check
// for each pair of impl blocks in the same connected region.
for (_id, region) in connected_regions.into_iter() {
for region in connected_regions.into_iter().flatten() {
let mut impl_blocks =
region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
impl_blocks.sort_unstable();

View File

@ -63,6 +63,7 @@ This API is completely unstable and subject to change.
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(iter_zip)]
#![feature(min_specialization)]
#![feature(nll)]
#![feature(try_blocks)]
#![feature(never_type)]

View File

@ -187,6 +187,7 @@ impl<T> Box<T> {
#[cfg(not(no_global_oom_handling))]
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn new(x: T) -> Self {
box x
}
@ -211,6 +212,7 @@ impl<T> Box<T> {
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
#[inline]
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
Self::new_uninit_in(Global)
@ -237,6 +239,7 @@ impl<T> Box<T> {
#[cfg(not(no_global_oom_handling))]
#[inline]
#[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
Self::new_zeroed_in(Global)
}
@ -245,6 +248,7 @@ impl<T> Box<T> {
/// `x` will be pinned in memory and unable to be moved.
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "pin", since = "1.33.0")]
#[must_use]
#[inline(always)]
pub fn pin(x: T) -> Pin<Box<T>> {
(box x).into()
@ -339,6 +343,7 @@ impl<T, A: Allocator> Box<T, A> {
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
#[inline]
pub fn new_in(x: T, alloc: A) -> Self {
let mut boxed = Self::new_uninit_in(alloc);
@ -395,6 +400,7 @@ impl<T, A: Allocator> Box<T, A> {
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(not(no_global_oom_handling))]
#[must_use]
// #[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
let layout = Layout::new::<mem::MaybeUninit<T>>();
@ -459,6 +465,7 @@ impl<T, A: Allocator> Box<T, A> {
#[unstable(feature = "allocator_api", issue = "32838")]
#[cfg(not(no_global_oom_handling))]
// #[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
let layout = Layout::new::<mem::MaybeUninit<T>>();
// NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
@ -503,6 +510,7 @@ impl<T, A: Allocator> Box<T, A> {
/// `x` will be pinned in memory and unable to be moved.
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
#[inline(always)]
pub fn pin_in(x: T, alloc: A) -> Pin<Self>
where
@ -561,6 +569,7 @@ impl<T> Box<[T]> {
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
unsafe { RawVec::with_capacity(len).into_box(len) }
}
@ -585,6 +594,7 @@ impl<T> Box<[T]> {
/// [zeroed]: mem::MaybeUninit::zeroed
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
}
@ -681,6 +691,7 @@ impl<T, A: Allocator> Box<[T], A> {
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
unsafe { RawVec::with_capacity_in(len, alloc).into_box(len) }
}
@ -708,6 +719,7 @@ impl<T, A: Allocator> Box<[T], A> {
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) }
}
@ -1277,6 +1289,7 @@ impl<T> From<T> for Box<T> {
/// from the stack into it.
///
/// # Examples
///
/// ```rust
/// let x = 5;
/// let boxed = Box::new(5);
@ -1330,6 +1343,12 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl<T: Copy> From<Cow<'_, [T]>> for Box<[T]> {
/// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
///
/// When `cow` is the `Cow::Borrowed` variant, this
/// conversion allocates on the heap and copies the
/// underlying slice. Otherwise, it will try to reuse the owned
/// `Vec`'s allocation.
#[inline]
fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
match cow {
@ -1348,6 +1367,7 @@ impl From<&str> for Box<str> {
/// and performs a copy of `s`.
///
/// # Examples
///
/// ```rust
/// let boxed: Box<str> = Box::from("hello");
/// println!("{}", boxed);
@ -1361,6 +1381,29 @@ impl From<&str> for Box<str> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, str>> for Box<str> {
/// Converts a `Cow<'_, str>` into a `Box<str>`
///
/// When `cow` is the `Cow::Borrowed` variant, this
/// conversion allocates on the heap and copies the
/// underlying `str`. Otherwise, it will try to reuse the owned
/// `String`'s allocation.
///
/// # Examples
///
/// ```rust
/// use std::borrow::Cow;
///
/// let unboxed = Cow::Borrowed("hello");
/// let boxed: Box<str> = Box::from(unboxed);
/// println!("{}", boxed);
/// ```
///
/// ```rust
/// # use std::borrow::Cow;
/// let unboxed = Cow::Owned("hello".to_string());
/// let boxed: Box<str> = Box::from(unboxed);
/// println!("{}", boxed);
/// ```
#[inline]
fn from(cow: Cow<'_, str>) -> Box<str> {
match cow {
@ -1403,6 +1446,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
/// This conversion moves the array to newly heap-allocated memory.
///
/// # Examples
///
/// ```rust
/// let boxed: Box<[u8]> = Box::from([4, 2]);
/// println!("{:?}", boxed);
@ -1416,6 +1460,15 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
type Error = Box<[T]>;
/// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
///
/// The conversion occurs in-place and does not require a
/// new memory allocation.
///
/// # Errors
///
/// Returns the old `Box<[T]>` in the `Err` variant if
/// `boxed_slice.len()` does not equal `N`.
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
if boxed_slice.len() == N {
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })

View File

@ -364,6 +364,7 @@ impl<T: Ord> BinaryHeap<T> {
/// heap.push(4);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn new() -> BinaryHeap<T> {
BinaryHeap { data: vec![] }
}
@ -383,6 +384,7 @@ impl<T: Ord> BinaryHeap<T> {
/// heap.push(4);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use]
pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
BinaryHeap { data: Vec::with_capacity(capacity) }
}
@ -848,6 +850,7 @@ impl<T> BinaryHeap<T> {
///
/// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
IntoIterSorted { inner: self }
@ -1006,6 +1009,7 @@ impl<T> BinaryHeap<T> {
///
/// io::sink().write(heap.as_slice()).unwrap();
/// ```
#[must_use]
#[unstable(feature = "binary_heap_as_slice", issue = "83659")]
pub fn as_slice(&self) -> &[T] {
self.data.as_slice()
@ -1028,6 +1032,7 @@ impl<T> BinaryHeap<T> {
/// println!("{}", x);
/// }
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
pub fn into_vec(self) -> Vec<T> {
self.into()

View File

@ -502,6 +502,7 @@ impl<K, V> BTreeMap<K, V> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
#[must_use]
pub const fn new() -> BTreeMap<K, V> {
BTreeMap { root: None, length: 0 }
}
@ -1264,6 +1265,7 @@ impl<K, V> BTreeMap<K, V> {
/// assert_eq!(keys, [1, 2]);
/// ```
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
@ -1286,6 +1288,7 @@ impl<K, V> BTreeMap<K, V> {
/// assert_eq!(values, ["hello", "goodbye"]);
/// ```
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }

View File

@ -448,6 +448,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
/// }
/// assert_eq!(map["poneyland"], 22);
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_mut(self) -> &'a mut V {
self.handle.into_val_mut()

View File

@ -1755,20 +1755,20 @@ fn test_send() {
#[test]
fn test_ord_absence() {
fn map<K>(mut map: BTreeMap<K, ()>) {
map.is_empty();
map.len();
let _ = map.is_empty();
let _ = map.len();
map.clear();
map.iter();
map.iter_mut();
map.keys();
map.values();
map.values_mut();
let _ = map.iter();
let _ = map.iter_mut();
let _ = map.keys();
let _ = map.values();
let _ = map.values_mut();
if true {
map.into_values();
let _ = map.into_values();
} else if true {
map.into_iter();
let _ = map.into_iter();
} else {
map.into_keys();
let _ = map.into_keys();
}
}

View File

@ -248,6 +248,7 @@ impl<T> BTreeSet<T> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
#[must_use]
pub const fn new() -> BTreeSet<T> {
BTreeSet { map: BTreeMap::new() }
}
@ -534,6 +535,7 @@ impl<T> BTreeSet<T> {
/// b.insert(1);
/// assert_eq!(a.is_disjoint(&b), false);
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_disjoint(&self, other: &BTreeSet<T>) -> bool
where
@ -559,6 +561,7 @@ impl<T> BTreeSet<T> {
/// set.insert(4);
/// assert_eq!(set.is_subset(&sup), false);
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_subset(&self, other: &BTreeSet<T>) -> bool
where
@ -638,6 +641,7 @@ impl<T> BTreeSet<T> {
/// set.insert(2);
/// assert_eq!(set.is_superset(&sub), true);
/// ```
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_superset(&self, other: &BTreeSet<T>) -> bool
where

Some files were not shown because too many files have changed in this diff Show More