mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-23 04:14:28 +00:00
Merge from rustc
This commit is contained in:
commit
adb446cc07
@ -67,12 +67,6 @@ pub struct FormatArguments {
|
||||
names: FxHashMap<Symbol, usize>,
|
||||
}
|
||||
|
||||
// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Sync for FormatArguments {}
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Send for FormatArguments {}
|
||||
|
||||
impl FormatArguments {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -886,6 +886,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
.universal_regions()
|
||||
.defining_ty
|
||||
.upvar_tys()
|
||||
.iter()
|
||||
.position(|ty| self.any_param_predicate_mentions(&predicates, ty, region))
|
||||
{
|
||||
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
|
||||
|
@ -43,7 +43,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
fr: RegionVid,
|
||||
) -> Option<usize> {
|
||||
let upvar_index =
|
||||
self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| {
|
||||
self.universal_regions().defining_ty.upvar_tys().iter().position(|upvar_ty| {
|
||||
debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}");
|
||||
tcx.any_free_region_meets(&upvar_ty, |r| {
|
||||
let r = r.as_var();
|
||||
@ -52,7 +52,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
})
|
||||
})?;
|
||||
|
||||
let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index);
|
||||
let upvar_ty = self.universal_regions().defining_ty.upvar_tys().get(upvar_index);
|
||||
|
||||
debug!(
|
||||
"get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}",
|
||||
|
@ -90,11 +90,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
) {
|
||||
self.prove_predicate(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
},
|
||||
ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive },
|
||||
))),
|
||||
locations,
|
||||
category,
|
||||
|
@ -791,25 +791,20 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
(adt_def.variant(FIRST_VARIANT), args)
|
||||
}
|
||||
ty::Closure(_, args) => {
|
||||
return match args
|
||||
.as_closure()
|
||||
.tupled_upvars_ty()
|
||||
.tuple_fields()
|
||||
.get(field.index())
|
||||
{
|
||||
return match args.as_closure().upvar_tys().get(field.index()) {
|
||||
Some(&ty) => Ok(ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_closure().upvar_tys().count(),
|
||||
field_count: args.as_closure().upvar_tys().len(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
ty::Generator(_, args, _) => {
|
||||
// Only prefix fields (upvars and current state) are
|
||||
// accessible without a variant index.
|
||||
return match args.as_generator().prefix_tys().nth(field.index()) {
|
||||
Some(ty) => Ok(ty),
|
||||
return match args.as_generator().prefix_tys().get(field.index()) {
|
||||
Some(ty) => Ok(*ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_generator().prefix_tys().count(),
|
||||
field_count: args.as_generator().prefix_tys().len(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
@ -1772,10 +1767,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
AggregateKind::Closure(_, args) => {
|
||||
match args.as_closure().upvar_tys().nth(field_index.as_usize()) {
|
||||
Some(ty) => Ok(ty),
|
||||
match args.as_closure().upvar_tys().get(field_index.as_usize()) {
|
||||
Some(ty) => Ok(*ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_closure().upvar_tys().count(),
|
||||
field_count: args.as_closure().upvar_tys().len(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -1783,10 +1778,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// It doesn't make sense to look at a field beyond the prefix;
|
||||
// these require a variant index, and are not initialized in
|
||||
// aggregate rvalues.
|
||||
match args.as_generator().prefix_tys().nth(field_index.as_usize()) {
|
||||
Some(ty) => Ok(ty),
|
||||
match args.as_generator().prefix_tys().get(field_index.as_usize()) {
|
||||
Some(ty) => Ok(*ty),
|
||||
None => Err(FieldAccessError::OutOfRange {
|
||||
field_count: args.as_generator().prefix_tys().count(),
|
||||
field_count: args.as_generator().prefix_tys().len(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
//! The code in this file doesn't *do anything* with those results; it
|
||||
//! just returns them for other code to use.
|
||||
|
||||
use either::Either;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
@ -115,14 +114,12 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
/// not a closure or generator, there are no upvars, and hence it
|
||||
/// will be an empty list. The order of types in this list will
|
||||
/// match up with the upvar order in the HIR, typesystem, and MIR.
|
||||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
|
||||
pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
|
||||
match self {
|
||||
DefiningTy::Closure(_, args) => Either::Left(args.as_closure().upvar_tys()),
|
||||
DefiningTy::Generator(_, args, _) => {
|
||||
Either::Right(Either::Left(args.as_generator().upvar_tys()))
|
||||
}
|
||||
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
||||
DefiningTy::Generator(_, args, _) => args.as_generator().upvar_tys(),
|
||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
||||
Either::Right(Either::Right(iter::empty()))
|
||||
ty::List::empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -85,3 +85,197 @@ impl CounterExpression {
|
||||
Self { kind, lhs, rhs }
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum RegionKind {
|
||||
/// A CodeRegion associates some code with a counter
|
||||
CodeRegion = 0,
|
||||
|
||||
/// An ExpansionRegion represents a file expansion region that associates
|
||||
/// a source range with the expansion of a virtual source file, such as
|
||||
/// for a macro instantiation or #include file.
|
||||
ExpansionRegion = 1,
|
||||
|
||||
/// A SkippedRegion represents a source range with code that was skipped
|
||||
/// by a preprocessor or similar means.
|
||||
SkippedRegion = 2,
|
||||
|
||||
/// A GapRegion is like a CodeRegion, but its count is only set as the
|
||||
/// line execution count when its the only region in the line.
|
||||
GapRegion = 3,
|
||||
|
||||
/// A BranchRegion represents leaf-level boolean expressions and is
|
||||
/// associated with two counters, each representing the number of times the
|
||||
/// expression evaluates to true or false.
|
||||
BranchRegion = 4,
|
||||
}
|
||||
|
||||
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
|
||||
/// coverage map, in accordance with the
|
||||
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
|
||||
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
|
||||
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
|
||||
/// array", encoded separately), and source location (start and end positions of the represented
|
||||
/// code region).
|
||||
///
|
||||
/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegion`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CounterMappingRegion {
|
||||
/// The counter type and type-dependent counter data, if any.
|
||||
counter: Counter,
|
||||
|
||||
/// If the `RegionKind` is a `BranchRegion`, this represents the counter
|
||||
/// for the false branch of the region.
|
||||
false_counter: Counter,
|
||||
|
||||
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
|
||||
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
|
||||
/// that, in turn, are used to look up the filename for this region.
|
||||
file_id: u32,
|
||||
|
||||
/// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
|
||||
/// the mapping regions created as a result of macro expansion, by checking if their file id
|
||||
/// matches the expanded file id.
|
||||
expanded_file_id: u32,
|
||||
|
||||
/// 1-based starting line of the mapping region.
|
||||
start_line: u32,
|
||||
|
||||
/// 1-based starting column of the mapping region.
|
||||
start_col: u32,
|
||||
|
||||
/// 1-based ending line of the mapping region.
|
||||
end_line: u32,
|
||||
|
||||
/// 1-based ending column of the mapping region. If the high bit is set, the current
|
||||
/// mapping region is a gap area.
|
||||
end_col: u32,
|
||||
|
||||
kind: RegionKind,
|
||||
}
|
||||
|
||||
impl CounterMappingRegion {
|
||||
pub(crate) fn code_region(
|
||||
counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::CodeRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn branch_region(
|
||||
counter: Counter,
|
||||
false_counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::BranchRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn expansion_region(
|
||||
file_id: u32,
|
||||
expanded_file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::zero(),
|
||||
false_counter: Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::ExpansionRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn skipped_region(
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::zero(),
|
||||
false_counter: Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::SkippedRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn gap_region(
|
||||
counter: Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col: (1_u32 << 31) | end_col,
|
||||
kind: RegionKind::GapRegion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub use super::ffi::*;
|
||||
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
|
||||
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::bug;
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo;
|
||||
use crate::coverageinfo::map_data::{Counter, CounterExpression};
|
||||
use crate::coverageinfo::ffi::{Counter, CounterExpression, CounterMappingRegion};
|
||||
use crate::llvm;
|
||||
|
||||
use llvm::coverageinfo::CounterMappingRegion;
|
||||
use rustc_codegen_ssa::traits::ConstMethods;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
@ -3,10 +3,10 @@ use crate::llvm;
|
||||
use crate::abi::Abi;
|
||||
use crate::builder::Builder;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::map_data::{CounterExpression, FunctionCoverage};
|
||||
use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
|
||||
use crate::coverageinfo::map_data::FunctionCoverage;
|
||||
|
||||
use libc::c_uint;
|
||||
use llvm::coverageinfo::CounterMappingRegion;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeMethods, BuilderMethods, ConstMethods, CoverageInfoBuilderMethods, MiscMethods,
|
||||
StaticMethods,
|
||||
@ -27,7 +27,7 @@ use rustc_middle::ty::Ty;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::CString;
|
||||
|
||||
mod ffi;
|
||||
pub(crate) mod ffi;
|
||||
pub(crate) mod map_data;
|
||||
pub mod mapgen;
|
||||
|
||||
|
@ -990,14 +990,8 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
||||
closure_or_generator_di_node: &'ll DIType,
|
||||
) -> SmallVec<&'ll DIType> {
|
||||
let (&def_id, up_var_tys) = match closure_or_generator_ty.kind() {
|
||||
ty::Generator(def_id, args, _) => {
|
||||
let upvar_tys: SmallVec<_> = args.as_generator().prefix_tys().collect();
|
||||
(def_id, upvar_tys)
|
||||
}
|
||||
ty::Closure(def_id, args) => {
|
||||
let upvar_tys: SmallVec<_> = args.as_closure().upvar_tys().collect();
|
||||
(def_id, upvar_tys)
|
||||
}
|
||||
ty::Generator(def_id, args, _) => (def_id, args.as_generator().prefix_tys()),
|
||||
ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
|
||||
_ => {
|
||||
bug!(
|
||||
"build_upvar_field_di_nodes() called with non-closure-or-generator-type: {:?}",
|
||||
@ -1007,9 +1001,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
up_var_tys
|
||||
.iter()
|
||||
.all(|&t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
|
||||
up_var_tys.iter().all(|t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
|
||||
);
|
||||
|
||||
let capture_names = cx.tcx.closure_saved_names_of_captured_variables(def_id);
|
||||
|
@ -379,6 +379,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
|
||||
// Fields that are common to all states
|
||||
let common_fields: SmallVec<_> = generator_args
|
||||
.prefix_tys()
|
||||
.iter()
|
||||
.zip(common_upvar_names)
|
||||
.enumerate()
|
||||
.map(|(index, (upvar_ty, upvar_name))| {
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use crate::coverageinfo::map_data as coverage_map;
|
||||
|
||||
use super::debuginfo::{
|
||||
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
|
||||
DIFile, DIFlags, DIGlobalVariableExpression, DILexicalBlock, DILocation, DINameSpace,
|
||||
@ -688,204 +686,6 @@ extern "C" {
|
||||
pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
|
||||
pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
|
||||
|
||||
pub mod coverageinfo {
|
||||
use super::coverage_map;
|
||||
|
||||
/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub enum RegionKind {
|
||||
/// A CodeRegion associates some code with a counter
|
||||
CodeRegion = 0,
|
||||
|
||||
/// An ExpansionRegion represents a file expansion region that associates
|
||||
/// a source range with the expansion of a virtual source file, such as
|
||||
/// for a macro instantiation or #include file.
|
||||
ExpansionRegion = 1,
|
||||
|
||||
/// A SkippedRegion represents a source range with code that was skipped
|
||||
/// by a preprocessor or similar means.
|
||||
SkippedRegion = 2,
|
||||
|
||||
/// A GapRegion is like a CodeRegion, but its count is only set as the
|
||||
/// line execution count when its the only region in the line.
|
||||
GapRegion = 3,
|
||||
|
||||
/// A BranchRegion represents leaf-level boolean expressions and is
|
||||
/// associated with two counters, each representing the number of times the
|
||||
/// expression evaluates to true or false.
|
||||
BranchRegion = 4,
|
||||
}
|
||||
|
||||
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
|
||||
/// coverage map, in accordance with the
|
||||
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
|
||||
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
|
||||
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
|
||||
/// array", encoded separately), and source location (start and end positions of the represented
|
||||
/// code region).
|
||||
///
|
||||
/// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCounterMappingRegion`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CounterMappingRegion {
|
||||
/// The counter type and type-dependent counter data, if any.
|
||||
counter: coverage_map::Counter,
|
||||
|
||||
/// If the `RegionKind` is a `BranchRegion`, this represents the counter
|
||||
/// for the false branch of the region.
|
||||
false_counter: coverage_map::Counter,
|
||||
|
||||
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
|
||||
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
|
||||
/// that, in turn, are used to look up the filename for this region.
|
||||
file_id: u32,
|
||||
|
||||
/// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find
|
||||
/// the mapping regions created as a result of macro expansion, by checking if their file id
|
||||
/// matches the expanded file id.
|
||||
expanded_file_id: u32,
|
||||
|
||||
/// 1-based starting line of the mapping region.
|
||||
start_line: u32,
|
||||
|
||||
/// 1-based starting column of the mapping region.
|
||||
start_col: u32,
|
||||
|
||||
/// 1-based ending line of the mapping region.
|
||||
end_line: u32,
|
||||
|
||||
/// 1-based ending column of the mapping region. If the high bit is set, the current
|
||||
/// mapping region is a gap area.
|
||||
end_col: u32,
|
||||
|
||||
kind: RegionKind,
|
||||
}
|
||||
|
||||
impl CounterMappingRegion {
|
||||
pub(crate) fn code_region(
|
||||
counter: coverage_map::Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: coverage_map::Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::CodeRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn branch_region(
|
||||
counter: coverage_map::Counter,
|
||||
false_counter: coverage_map::Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::BranchRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn expansion_region(
|
||||
file_id: u32,
|
||||
expanded_file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: coverage_map::Counter::zero(),
|
||||
false_counter: coverage_map::Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::ExpansionRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn skipped_region(
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: coverage_map::Counter::zero(),
|
||||
false_counter: coverage_map::Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col,
|
||||
kind: RegionKind::SkippedRegion,
|
||||
}
|
||||
}
|
||||
|
||||
// This function might be used in the future; the LLVM API is still evolving, as is coverage
|
||||
// support.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn gap_region(
|
||||
counter: coverage_map::Counter,
|
||||
file_id: u32,
|
||||
start_line: u32,
|
||||
start_col: u32,
|
||||
end_line: u32,
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: coverage_map::Counter::zero(),
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
start_col,
|
||||
end_line,
|
||||
end_col: (1_u32 << 31) | end_col,
|
||||
kind: RegionKind::GapRegion,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod debuginfo {
|
||||
use super::{InvariantOpaque, Metadata};
|
||||
use bitflags::bitflags;
|
||||
@ -1911,9 +1711,9 @@ extern "C" {
|
||||
pub fn LLVMRustCoverageWriteMappingToBuffer(
|
||||
VirtualFileMappingIDs: *const c_uint,
|
||||
NumVirtualFileMappingIDs: c_uint,
|
||||
Expressions: *const coverage_map::CounterExpression,
|
||||
Expressions: *const crate::coverageinfo::ffi::CounterExpression,
|
||||
NumExpressions: c_uint,
|
||||
MappingRegions: *const coverageinfo::CounterMappingRegion,
|
||||
MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion,
|
||||
NumMappingRegions: c_uint,
|
||||
BufferOut: &RustString,
|
||||
);
|
||||
|
@ -282,7 +282,7 @@ const_eval_pointer_out_of_bounds =
|
||||
*[many] bytes
|
||||
} starting at offset {$ptr_offset} is out-of-bounds
|
||||
const_eval_pointer_use_after_free =
|
||||
pointer to {$allocation} was dereferenced after this allocation got freed
|
||||
{$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
|
||||
const_eval_ptr_as_bytes_1 =
|
||||
this code performed an operation that depends on the underlying bytes representing a pointer
|
||||
const_eval_ptr_as_bytes_2 =
|
||||
|
@ -214,9 +214,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||
// &str or &&str
|
||||
assert!(args.len() == 1);
|
||||
|
||||
let mut msg_place = self.deref_operand(&args[0])?;
|
||||
let mut msg_place = self.deref_pointer(&args[0])?;
|
||||
while msg_place.layout.ty.is_ref() {
|
||||
msg_place = self.deref_operand(&msg_place)?;
|
||||
msg_place = self.deref_pointer(&msg_place)?;
|
||||
}
|
||||
|
||||
let msg = Symbol::intern(self.read_str(&msg_place)?);
|
||||
|
@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
||||
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
|
||||
ty::Ref(_, _, _) => {
|
||||
let Ok(derefd_place)= ecx.deref_operand(place) else {
|
||||
let Ok(derefd_place)= ecx.deref_pointer(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
debug!(?derefd_place);
|
||||
|
@ -492,7 +492,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
|
||||
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
|
||||
UnterminatedCString(_) => const_eval_unterminated_c_string,
|
||||
PointerUseAfterFree(_) => const_eval_pointer_use_after_free,
|
||||
PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
|
||||
PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
|
||||
PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
|
||||
DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
|
||||
@ -545,8 +545,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
||||
builder.set_arg("pointer", ptr);
|
||||
}
|
||||
PointerUseAfterFree(allocation) => {
|
||||
builder.set_arg("allocation", allocation);
|
||||
PointerUseAfterFree(alloc_id, msg) => {
|
||||
builder
|
||||
.set_arg("alloc_id", alloc_id)
|
||||
.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
|
||||
}
|
||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
|
||||
builder
|
||||
|
@ -144,7 +144,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
sym::min_align_of_val | sym::size_of_val => {
|
||||
// Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
|
||||
// Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
|
||||
// dereferenceable!
|
||||
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
|
||||
let (size, align) = self
|
||||
@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.write_scalar(val, dest)?;
|
||||
}
|
||||
sym::discriminant_value => {
|
||||
let place = self.deref_operand(&args[0])?;
|
||||
let place = self.deref_pointer(&args[0])?;
|
||||
let variant = self.read_discriminant(&place)?;
|
||||
let discr = self.discriminant_for_variant(place.layout, variant)?;
|
||||
self.write_scalar(discr, dest)?;
|
||||
|
@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
kind = "static_mem"
|
||||
)
|
||||
}
|
||||
None => err_ub!(PointerUseAfterFree(alloc_id)),
|
||||
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
|
||||
}
|
||||
.into());
|
||||
};
|
||||
@ -380,7 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
M::enforce_alignment(self),
|
||||
CheckInAllocMsg::MemoryAccessTest,
|
||||
|alloc_id, offset, prov| {
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
|
||||
let (size, align) = self
|
||||
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
|
||||
Ok((size, align, (alloc_id, offset, prov)))
|
||||
},
|
||||
)
|
||||
@ -404,7 +405,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
CheckAlignment::Error,
|
||||
msg,
|
||||
|alloc_id, _, _| {
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
|
||||
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
|
||||
Ok((size, align, ()))
|
||||
},
|
||||
)?;
|
||||
@ -414,7 +415,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
|
||||
/// to the allocation it points to. Supports both shared and mutable references, as the actual
|
||||
/// checking is offloaded to a helper closure. `align` defines whether and which alignment check
|
||||
/// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
|
||||
/// is done.
|
||||
///
|
||||
/// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
|
||||
fn check_and_deref_ptr<T>(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
@ -515,7 +518,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
|
||||
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
|
||||
None => throw_ub!(PointerUseAfterFree(id)),
|
||||
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
|
||||
Some(GlobalAlloc::Static(def_id)) => {
|
||||
assert!(self.tcx.is_static(def_id));
|
||||
assert!(!self.tcx.is_thread_local_static(def_id));
|
||||
@ -761,11 +764,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the size and alignment of a live allocation.
|
||||
pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> {
|
||||
/// Obtain the size and alignment of a *live* allocation.
|
||||
fn get_live_alloc_size_and_align(
|
||||
&self,
|
||||
id: AllocId,
|
||||
msg: CheckInAllocMsg,
|
||||
) -> InterpResult<'tcx, (Size, Align)> {
|
||||
let (size, align, kind) = self.get_alloc_info(id);
|
||||
if matches!(kind, AllocKind::Dead) {
|
||||
throw_ub!(PointerUseAfterFree(id))
|
||||
throw_ub!(PointerUseAfterFree(id, msg))
|
||||
}
|
||||
Ok((size, align))
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ where
|
||||
///
|
||||
/// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
|
||||
/// want to ever use the place for memory access!
|
||||
/// Generally prefer `deref_operand`.
|
||||
/// Generally prefer `deref_pointer`.
|
||||
pub fn ref_to_mplace(
|
||||
&self,
|
||||
val: &ImmTy<'tcx, M::Provenance>,
|
||||
@ -439,8 +439,9 @@ where
|
||||
}
|
||||
|
||||
/// Take an operand, representing a pointer, and dereference it to a place.
|
||||
/// Corresponds to the `*` operator in Rust.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn deref_operand(
|
||||
pub fn deref_pointer(
|
||||
&self,
|
||||
src: &impl Readable<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
|
@ -290,7 +290,7 @@ where
|
||||
OpaqueCast(ty) => base.transmute(self.layout_of(ty)?, self)?,
|
||||
Field(field, _) => self.project_field(base, field.index())?,
|
||||
Downcast(_, variant) => self.project_downcast(base, variant)?,
|
||||
Deref => self.deref_operand(&base.to_op(self)?)?.into(),
|
||||
Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
|
||||
Index(local) => {
|
||||
let layout = self.layout_of(self.tcx.types.usize)?;
|
||||
let n = self.local_to_op(self.frame(), local, Some(layout))?;
|
||||
|
@ -224,8 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
Len(place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let op = self.place_to_op(&src)?;
|
||||
let len = op.len(self)?;
|
||||
let len = src.len(self)?;
|
||||
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
|
||||
}
|
||||
|
||||
|
@ -661,7 +661,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let receiver_place = loop {
|
||||
match receiver.layout.ty.kind() {
|
||||
ty::Ref(..) | ty::RawPtr(..) => {
|
||||
// We do *not* use `deref_operand` here: we don't want to conceptually
|
||||
// We do *not* use `deref_pointer` here: we don't want to conceptually
|
||||
// create a place that must be dereferenceable, since the receiver might
|
||||
// be a raw pointer and (for `*const dyn Trait`) we don't need to
|
||||
// actually access memory to resolve this method.
|
||||
|
@ -345,6 +345,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
value: &OpTy<'tcx, M::Provenance>,
|
||||
ptr_kind: PointerKind,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Not using `deref_pointer` since we do the dereferenceable check ourselves below.
|
||||
let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?;
|
||||
// Handle wide pointers.
|
||||
// Check metadata early, for better diagnostics
|
||||
@ -515,9 +516,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||
Ok(true)
|
||||
}
|
||||
ty::RawPtr(..) => {
|
||||
// We are conservative with uninit for integers, but try to
|
||||
// actually enforce the strict rules for raw pointers (mostly because
|
||||
// that lets us re-use `ref_to_mplace`).
|
||||
let place =
|
||||
self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?;
|
||||
if place.layout.is_unsized() {
|
||||
|
@ -746,6 +746,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
|
||||
// Attempting to call a trait method?
|
||||
// FIXME(effects) do we need this?
|
||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||
trace!("attempting to call a trait method");
|
||||
if !self.tcx.features().const_trait_impl {
|
||||
@ -761,7 +762,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
}
|
||||
|
||||
let trait_ref = TraitRef::from_method(tcx, trait_id, fn_args);
|
||||
let trait_ref = trait_ref.with_constness(ty::BoundConstness::ConstIfConst);
|
||||
let obligation =
|
||||
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
|
||||
|
||||
|
@ -155,12 +155,12 @@ impl Qualif for NeedsNonConstDrop {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME(effects) constness
|
||||
let obligation = Obligation::new(
|
||||
cx.tcx,
|
||||
ObligationCause::dummy_with_span(cx.body.span),
|
||||
cx.param_env,
|
||||
ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty])
|
||||
.with_constness(ty::BoundConstness::ConstIfConst),
|
||||
ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty]),
|
||||
);
|
||||
|
||||
let infcx = cx.tcx.infer_ctxt().build();
|
||||
|
@ -630,7 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
ty::Closure(_, args) => {
|
||||
let args = args.as_closure();
|
||||
let Some(f_ty) = args.upvar_tys().nth(f.as_usize()) else {
|
||||
let Some(&f_ty) = args.upvar_tys().get(f.as_usize()) else {
|
||||
fail_out_of_bounds(self, location);
|
||||
return;
|
||||
};
|
||||
@ -667,7 +667,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
|
||||
f_ty.ty
|
||||
} else {
|
||||
let Some(f_ty) = args.as_generator().prefix_tys().nth(f.index()) else {
|
||||
let Some(&f_ty) = args.as_generator().prefix_tys().get(f.index())
|
||||
else {
|
||||
fail_out_of_bounds(self, location);
|
||||
return;
|
||||
};
|
||||
|
@ -713,7 +713,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
);
|
||||
|
||||
debug!(?poly_trait_ref, ?assoc_bindings);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, constness, polarity);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
|
||||
|
||||
let mut dup_bindings = FxHashMap::default();
|
||||
for binding in &assoc_bindings {
|
||||
|
@ -62,11 +62,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
match bound_pred.skip_binder() {
|
||||
ty::ClauseKind::Trait(trait_pred) => {
|
||||
assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
|
||||
trait_bounds.push((
|
||||
bound_pred.rebind(trait_pred.trait_ref),
|
||||
span,
|
||||
trait_pred.constness,
|
||||
));
|
||||
trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
|
||||
}
|
||||
ty::ClauseKind::Projection(proj) => {
|
||||
projection_bounds.push((bound_pred.rebind(proj), span));
|
||||
@ -86,7 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
// Expand trait aliases recursively and check that only one regular (non-auto) trait
|
||||
// is used and no 'maybe' bounds are used.
|
||||
let expanded_traits =
|
||||
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
|
||||
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
|
||||
|
||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
|
||||
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
|
||||
@ -126,7 +122,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||
let trait_alias_span = trait_bounds
|
||||
.iter()
|
||||
.map(|&(trait_ref, _, _)| trait_ref.def_id())
|
||||
.map(|&(trait_ref, _)| trait_ref.def_id())
|
||||
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
|
||||
.map(|trait_ref| tcx.def_span(trait_ref));
|
||||
let reported =
|
||||
@ -157,10 +153,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
|
||||
let regular_traits_refs_spans = trait_bounds
|
||||
.into_iter()
|
||||
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
|
||||
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
|
||||
assert_eq!(constness, ty::BoundConstness::NotConst);
|
||||
for (base_trait_ref, span) in regular_traits_refs_spans {
|
||||
let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
|
||||
for pred in traits::elaborate(tcx, [base_pred]) {
|
||||
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
|
||||
|
@ -42,13 +42,12 @@ impl<'tcx> Bounds<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) {
|
||||
self.clauses.push((
|
||||
trait_ref
|
||||
.map_bound(|trait_ref| {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity })
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
|
||||
})
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
|
@ -194,7 +194,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
|
||||
match (tcx.impl_polarity(def_id), impl_.polarity) {
|
||||
(ty::ImplPolarity::Positive, _) => {
|
||||
check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness);
|
||||
check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
|
||||
}
|
||||
(ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
|
||||
// FIXME(#27579): what amount of WF checking do we need for neg impls?
|
||||
@ -1191,7 +1191,6 @@ fn check_impl<'tcx>(
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
ast_self_ty: &hir::Ty<'_>,
|
||||
ast_trait_ref: &Option<hir::TraitRef<'_>>,
|
||||
constness: hir::Constness,
|
||||
) {
|
||||
enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
|
||||
match ast_trait_ref {
|
||||
@ -1205,14 +1204,8 @@ fn check_impl<'tcx>(
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
trait_ref,
|
||||
);
|
||||
let trait_pred = ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: match constness {
|
||||
hir::Constness::Const => ty::BoundConstness::ConstIfConst,
|
||||
hir::Constness::NotConst => ty::BoundConstness::NotConst,
|
||||
},
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
};
|
||||
let trait_pred =
|
||||
ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive };
|
||||
let mut obligations = traits::wf::trait_obligations(
|
||||
wfcx.infcx,
|
||||
wfcx.param_env,
|
||||
|
@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||
|
||||
/// Returns a list of all type predicates (explicit and implicit) for the definition with
|
||||
@ -37,17 +37,10 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
|
||||
// from the trait itself that *shouldn't* be shown as the source of
|
||||
// an obligation and instead be skipped. Otherwise we'd use
|
||||
// `tcx.def_span(def_id);`
|
||||
|
||||
let constness = if tcx.has_attr(def_id, sym::const_trait) {
|
||||
ty::BoundConstness::ConstIfConst
|
||||
} else {
|
||||
ty::BoundConstness::NotConst
|
||||
};
|
||||
|
||||
let span = rustc_span::DUMMY_SP;
|
||||
result.predicates =
|
||||
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
|
||||
ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
|
||||
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
|
||||
span,
|
||||
))));
|
||||
}
|
||||
@ -204,7 +197,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
// (see below). Recall that a default impl is not itself an impl, but rather a
|
||||
// set of defaults that can be incorporated into another impl.
|
||||
if let Some(trait_ref) = is_default_impl_trait {
|
||||
predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
|
||||
predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id)));
|
||||
}
|
||||
|
||||
// Collect the region predicates that were declared inline as
|
||||
@ -777,8 +770,7 @@ pub(super) fn type_param_predicates(
|
||||
if param_id == item_hir_id {
|
||||
let identity_trait_ref =
|
||||
ty::TraitRef::identity(tcx, item_def_id.to_def_id());
|
||||
extend =
|
||||
Some((identity_trait_ref.without_const().to_predicate(tcx), item.span));
|
||||
extend = Some((identity_trait_ref.to_predicate(tcx), item.span));
|
||||
}
|
||||
generics
|
||||
}
|
||||
|
@ -431,45 +431,13 @@ fn check_predicates<'tcx>(
|
||||
///
|
||||
/// So we make that check in this function and try to raise a helpful error message.
|
||||
fn trait_predicates_eq<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
predicate1: ty::Predicate<'tcx>,
|
||||
predicate2: ty::Predicate<'tcx>,
|
||||
span: Span,
|
||||
_span: Span,
|
||||
) -> bool {
|
||||
let pred1_kind = predicate1.kind().skip_binder();
|
||||
let pred2_kind = predicate2.kind().skip_binder();
|
||||
let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) {
|
||||
(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)),
|
||||
) => (pred1, pred2),
|
||||
// Just use plain syntactic equivalence if either of the predicates aren't
|
||||
// trait predicates or have bound vars.
|
||||
_ => return predicate1 == predicate2,
|
||||
};
|
||||
|
||||
let predicates_equal_modulo_constness = {
|
||||
let pred1_unconsted =
|
||||
ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred1 };
|
||||
let pred2_unconsted =
|
||||
ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..trait_pred2 };
|
||||
pred1_unconsted == pred2_unconsted
|
||||
};
|
||||
|
||||
if !predicates_equal_modulo_constness {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the predicate on the specializing impl is at least as const as
|
||||
// the one on the base.
|
||||
match (trait_pred2.constness, trait_pred1.constness) {
|
||||
(ty::BoundConstness::ConstIfConst, ty::BoundConstness::NotConst) => {
|
||||
tcx.sess.emit_err(errors::MissingTildeConst { span });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
true
|
||||
// FIXME(effects)
|
||||
predicate1 == predicate2
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
@ -482,7 +450,6 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||
// items.
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
polarity: _,
|
||||
})) => {
|
||||
if !matches!(
|
||||
@ -536,7 +503,6 @@ fn trait_predicate_kind<'tcx>(
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
polarity: _,
|
||||
})) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
|
||||
|
@ -156,7 +156,6 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||
match pred.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef { def_id: _, args, .. },
|
||||
constness: _,
|
||||
polarity: _,
|
||||
}) => {
|
||||
for subst in &args[1..] {
|
||||
|
@ -2988,7 +2988,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref: impl_trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
}),
|
||||
|derived| {
|
||||
traits::ImplDerivedObligation(Box::new(
|
||||
|
@ -1461,10 +1461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
param_env,
|
||||
bounds,
|
||||
) {
|
||||
// N.B. We are remapping all predicates to non-const since we don't know if we just
|
||||
// want them as function pointers or we are calling them from a const-context. The
|
||||
// actual checking will occur in `rustc_const_eval::transform::check_consts`.
|
||||
self.register_predicate(obligation.without_const(self.tcx));
|
||||
self.register_predicate(obligation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1856,19 +1856,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if self.adjust_fulfillment_error_for_expr_obligation(error)
|
||||
|| before_span != error.obligation.cause.span
|
||||
{
|
||||
// Store both the predicate and the predicate *without constness*
|
||||
// since sometimes we instantiate and check both of these in a
|
||||
// method call, for example.
|
||||
remap_cause.insert((
|
||||
before_span,
|
||||
error.obligation.predicate,
|
||||
error.obligation.cause.clone(),
|
||||
));
|
||||
remap_cause.insert((
|
||||
before_span,
|
||||
error.obligation.predicate.without_const(self.tcx),
|
||||
error.obligation.cause.clone(),
|
||||
));
|
||||
} else {
|
||||
// If it failed to be adjusted once around, it may be adjusted
|
||||
// via the "remap cause" mapping the second time...
|
||||
|
@ -341,15 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Construct an obligation
|
||||
let poly_trait_ref = ty::Binder::dummy(trait_ref);
|
||||
(
|
||||
traits::Obligation::new(
|
||||
self.tcx,
|
||||
cause,
|
||||
self.param_env,
|
||||
poly_trait_ref.without_const(),
|
||||
),
|
||||
args,
|
||||
)
|
||||
(traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args)
|
||||
}
|
||||
|
||||
/// `lookup_method_in_trait` is used for overloaded operators.
|
||||
|
@ -1599,8 +1599,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let predicate =
|
||||
ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
|
||||
let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx);
|
||||
parent_pred = Some(predicate);
|
||||
let obligation =
|
||||
traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate);
|
||||
|
@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
poly_trait_ref.without_const(),
|
||||
poly_trait_ref,
|
||||
);
|
||||
self.predicate_may_hold(&obligation)
|
||||
})
|
||||
|
@ -448,7 +448,9 @@ where
|
||||
ty::Closure(_, ref args) => {
|
||||
// Skip lifetime parameters of the enclosing item(s)
|
||||
|
||||
args.as_closure().tupled_upvars_ty().visit_with(self);
|
||||
for upvar in args.as_closure().upvar_tys() {
|
||||
upvar.visit_with(self);
|
||||
}
|
||||
args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
|
||||
}
|
||||
|
||||
@ -456,7 +458,9 @@ where
|
||||
// Skip lifetime parameters of the enclosing item(s)
|
||||
// Also skip the witness type, because that has no free regions.
|
||||
|
||||
args.as_generator().tupled_upvars_ty().visit_with(self);
|
||||
for upvar in args.as_generator().upvar_tys() {
|
||||
upvar.visit_with(self);
|
||||
}
|
||||
args.as_generator().return_ty().visit_with(self);
|
||||
args.as_generator().yield_ty().visit_with(self);
|
||||
args.as_generator().resume_ty().visit_with(self);
|
||||
|
@ -25,7 +25,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||
cause,
|
||||
recursion_depth: 0,
|
||||
param_env,
|
||||
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx),
|
||||
predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -77,13 +77,6 @@ impl<'tcx> PredicateObligation<'tcx> {
|
||||
recursion_depth: self.recursion_depth,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> PredicateObligation<'tcx> {
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = self.predicate.kind().skip_binder() && trait_pred.is_const_if_const() {
|
||||
self.predicate = tcx.mk_predicate(self.predicate.kind().map_bound(|_| ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred.without_const()))));
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PolyTraitObligation<'tcx> {
|
||||
|
@ -264,11 +264,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
|
||||
};
|
||||
|
||||
let obligations =
|
||||
predicates.predicates.iter().enumerate().map(|(index, &(mut clause, span))| {
|
||||
// when parent predicate is non-const, elaborate it to non-const predicates.
|
||||
if data.constness == ty::BoundConstness::NotConst {
|
||||
clause = clause.without_const(tcx);
|
||||
}
|
||||
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
|
||||
elaboratable.child_with_derived_cause(
|
||||
clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
|
||||
span,
|
||||
|
@ -318,7 +318,11 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
|
||||
|
||||
lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
|
||||
|
||||
lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
|
||||
|
@ -218,7 +218,7 @@ late_lint_methods!(
|
||||
BoxPointers: BoxPointers,
|
||||
PathStatements: PathStatements,
|
||||
LetUnderscore: LetUnderscore,
|
||||
InvalidReferenceCasting: InvalidReferenceCasting,
|
||||
InvalidReferenceCasting: InvalidReferenceCasting::default(),
|
||||
// Depends on referenced function signatures in expressions
|
||||
UnusedResults: UnusedResults,
|
||||
NonUpperCaseGlobals: NonUpperCaseGlobals,
|
||||
|
@ -745,8 +745,18 @@ pub enum InvalidFromUtf8Diag {
|
||||
|
||||
// reference_casting.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_reference_casting)]
|
||||
pub struct InvalidReferenceCastingDiag;
|
||||
pub enum InvalidReferenceCastingDiag {
|
||||
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||
BorrowAsMut {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
},
|
||||
#[diag(lint_invalid_reference_casting_assign_to_ref)]
|
||||
AssignToRef {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
},
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
|
@ -1,7 +1,8 @@
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, QPath, StmtKind, UnOp};
|
||||
use rustc_middle::ty::{self, TypeAndMut};
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
|
||||
|
||||
@ -12,7 +13,6 @@ declare_lint! {
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![deny(invalid_reference_casting)]
|
||||
/// fn x(r: &i32) {
|
||||
/// unsafe {
|
||||
/// *(r as *const i32 as *mut i32) += 1;
|
||||
@ -30,46 +30,103 @@ declare_lint! {
|
||||
/// `UnsafeCell` is the only way to obtain aliasable data that is considered
|
||||
/// mutable.
|
||||
INVALID_REFERENCE_CASTING,
|
||||
Allow,
|
||||
Deny,
|
||||
"casts of `&T` to `&mut T` without interior mutability"
|
||||
}
|
||||
|
||||
declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
|
||||
#[derive(Default)]
|
||||
pub struct InvalidReferenceCasting {
|
||||
casted: FxHashMap<HirId, Span>,
|
||||
}
|
||||
|
||||
impl_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) {
|
||||
let StmtKind::Local(local) = stmt.kind else {
|
||||
return;
|
||||
};
|
||||
let Local { init: Some(init), els: None, .. } = local else {
|
||||
return;
|
||||
};
|
||||
|
||||
let e = e.peel_blocks();
|
||||
let e = if let ExprKind::Cast(e, t) = e.kind
|
||||
&& let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind {
|
||||
e
|
||||
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
|
||||
if is_cast_from_const_to_mut(cx, init) {
|
||||
self.casted.insert(local.pat.hir_id, init.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
// &mut <expr>
|
||||
let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
|
||||
expr
|
||||
// <expr> = ...
|
||||
} else if let ExprKind::Assign(expr, _, _) = expr.kind {
|
||||
expr
|
||||
// <expr> += ...
|
||||
} else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
|
||||
expr
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let e = e.peel_blocks();
|
||||
let e = if let ExprKind::Cast(e, t) = e.kind
|
||||
&& let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind {
|
||||
e
|
||||
} else if let ExprKind::Call(path, [arg]) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
|
||||
arg
|
||||
let ExprKind::Unary(UnOp::Deref, e) = &inner.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
let orig_cast = if is_cast_from_const_to_mut(cx, e) {
|
||||
None
|
||||
} else if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind
|
||||
&& let Res::Local(hir_id) = &path.res
|
||||
&& let Some(orig_cast) = self.casted.get(hir_id) {
|
||||
Some(*orig_cast)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let e = e.peel_blocks();
|
||||
if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() {
|
||||
cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag);
|
||||
}
|
||||
cx.emit_spanned_lint(
|
||||
INVALID_REFERENCE_CASTING,
|
||||
expr.span,
|
||||
if matches!(expr.kind, ExprKind::AddrOf(..)) {
|
||||
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
|
||||
} else {
|
||||
InvalidReferenceCastingDiag::AssignToRef { orig_cast }
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
|
||||
let e = e.peel_blocks();
|
||||
|
||||
// <expr> as *mut ...
|
||||
let e = if let ExprKind::Cast(e, t) = e.kind
|
||||
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
|
||||
e
|
||||
// <expr>.cast_mut()
|
||||
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
|
||||
expr
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let e = e.peel_blocks();
|
||||
|
||||
// <expr> as *const ...
|
||||
let e = if let ExprKind::Cast(e, t) = e.kind
|
||||
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
|
||||
e
|
||||
// ptr::from_ref(<expr>)
|
||||
} else if let ExprKind::Call(path, [arg]) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
|
||||
arg
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let e = e.peel_blocks();
|
||||
matches!(cx.typeck_results().node_type(e.hir_id).kind(), ty::Ref(_, _, Mutability::Not))
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ metadata_conflicting_alloc_error_handler =
|
||||
metadata_conflicting_global_alloc =
|
||||
the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
|
||||
|
||||
metadata_consider_adding_std =
|
||||
consider adding the standard library to the sysroot with `x build library --target {$locator_triple}`
|
||||
|
||||
metadata_consider_building_std =
|
||||
consider building the standard library from source with `cargo build -Zbuild-std`
|
||||
|
||||
|
@ -623,6 +623,7 @@ pub struct CannotFindCrate {
|
||||
pub is_nightly_build: bool,
|
||||
pub profiler_runtime: Symbol,
|
||||
pub locator_triple: TargetTriple,
|
||||
pub is_ui_testing: bool,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for CannotFindCrate {
|
||||
@ -646,12 +647,19 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
|
||||
} else {
|
||||
diag.note(fluent::metadata_target_no_std_support);
|
||||
}
|
||||
// NOTE: this suggests using rustup, even though the user may not have it installed.
|
||||
// That's because they could choose to install it; or this may give them a hint which
|
||||
// target they need to install from their distro.
|
||||
|
||||
if self.missing_core {
|
||||
diag.help(fluent::metadata_consider_downloading_target);
|
||||
if env!("CFG_RELEASE_CHANNEL") == "dev" && !self.is_ui_testing {
|
||||
// Note: Emits the nicer suggestion only for the dev channel.
|
||||
diag.help(fluent::metadata_consider_adding_std);
|
||||
} else {
|
||||
// NOTE: this suggests using rustup, even though the user may not have it installed.
|
||||
// That's because they could choose to install it; or this may give them a hint which
|
||||
// target they need to install from their distro.
|
||||
diag.help(fluent::metadata_consider_downloading_target);
|
||||
}
|
||||
}
|
||||
|
||||
// Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
|
||||
// NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
|
||||
// If it's not a dummy, that means someone added `extern crate std` explicitly and
|
||||
|
@ -1130,6 +1130,7 @@ impl CrateError {
|
||||
is_nightly_build: sess.is_nightly_build(),
|
||||
profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
|
||||
locator_triple: locator.triple,
|
||||
is_ui_testing: sess.opts.unstable_opts.ui_testing,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1146,6 +1147,7 @@ impl CrateError {
|
||||
is_nightly_build: sess.is_nightly_build(),
|
||||
profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
|
||||
locator_triple: sess.opts.target_triple.clone(),
|
||||
is_ui_testing: sess.opts.unstable_opts.ui_testing,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -282,8 +282,8 @@ pub enum UndefinedBehaviorInfo<'a> {
|
||||
InvalidMeta(InvalidMetaKind),
|
||||
/// Reading a C string that does not end within its allocation.
|
||||
UnterminatedCString(Pointer),
|
||||
/// Dereferencing a dangling pointer after it got freed.
|
||||
PointerUseAfterFree(AllocId),
|
||||
/// Using a pointer after it got freed.
|
||||
PointerUseAfterFree(AllocId, CheckInAllocMsg),
|
||||
/// Used a pointer outside the bounds it is valid for.
|
||||
/// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
|
||||
PointerOutOfBounds {
|
||||
|
@ -911,7 +911,7 @@ where
|
||||
if i == tag_field {
|
||||
return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
|
||||
}
|
||||
TyMaybeWithLayout::Ty(args.as_generator().prefix_tys().nth(i).unwrap())
|
||||
TyMaybeWithLayout::Ty(args.as_generator().prefix_tys()[i])
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -498,11 +498,9 @@ impl<'tcx> Predicate<'tcx> {
|
||||
.map_bound(|kind| match kind {
|
||||
PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref,
|
||||
constness,
|
||||
polarity,
|
||||
})) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref,
|
||||
constness,
|
||||
polarity: polarity.flip()?,
|
||||
}))),
|
||||
|
||||
@ -513,19 +511,6 @@ impl<'tcx> Predicate<'tcx> {
|
||||
Some(tcx.mk_predicate(kind))
|
||||
}
|
||||
|
||||
pub fn without_const(mut self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
if let PredicateKind::Clause(ClauseKind::Trait(TraitPredicate { trait_ref, constness, polarity })) = self.kind().skip_binder()
|
||||
&& constness != BoundConstness::NotConst
|
||||
{
|
||||
self = tcx.mk_predicate(self.kind().rebind(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref,
|
||||
constness: BoundConstness::NotConst,
|
||||
polarity,
|
||||
}))));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
match self.kind().skip_binder() {
|
||||
@ -629,10 +614,6 @@ impl<'tcx> Clause<'tcx> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn without_const(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
|
||||
self.as_predicate().without_const(tcx).expect_clause()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
@ -852,8 +833,6 @@ impl<'tcx> Clause<'tcx> {
|
||||
pub struct TraitPredicate<'tcx> {
|
||||
pub trait_ref: TraitRef<'tcx>,
|
||||
|
||||
pub constness: BoundConstness,
|
||||
|
||||
/// If polarity is Positive: we are proving that the trait is implemented.
|
||||
///
|
||||
/// If polarity is Negative: we are proving that a negative impl of this trait
|
||||
@ -878,24 +857,6 @@ impl<'tcx> TraitPredicate<'tcx> {
|
||||
pub fn self_ty(self) -> Ty<'tcx> {
|
||||
self.trait_ref.self_ty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const_if_const(self) -> bool {
|
||||
self.constness == BoundConstness::ConstIfConst
|
||||
}
|
||||
|
||||
pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool {
|
||||
match (self.constness, constness) {
|
||||
(BoundConstness::NotConst, _)
|
||||
| (BoundConstness::ConstIfConst, hir::Constness::Const) => true,
|
||||
(BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn without_const(mut self) -> Self {
|
||||
self.constness = BoundConstness::NotConst;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
@ -908,11 +869,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
|
||||
self.map_bound(|trait_ref| trait_ref.self_ty())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_const_if_const(self) -> bool {
|
||||
self.skip_binder().is_const_if_const()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn polarity(self) -> ImplPolarity {
|
||||
self.skip_binder().polarity
|
||||
@ -1287,7 +1243,7 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
|
||||
impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
|
||||
self.without_const()
|
||||
TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1328,7 +1284,6 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
|
||||
fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
|
||||
self.map_bound(|trait_ref| TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
})
|
||||
}
|
||||
@ -1826,24 +1781,6 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that
|
||||
// the constness of trait bounds is being propagated correctly.
|
||||
impl<'tcx> PolyTraitRef<'tcx> {
|
||||
#[inline]
|
||||
pub fn with_constness(self, constness: BoundConstness) -> PolyTraitPredicate<'tcx> {
|
||||
self.map_bound(|trait_ref| ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
|
||||
self.with_constness(BoundConstness::NotConst)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
||||
#[derive(HashStable, Lift)]
|
||||
pub struct ParamEnvAnd<'tcx, T> {
|
||||
|
@ -827,7 +827,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
if !args.as_generator().is_valid() {
|
||||
p!("unavailable");
|
||||
} else {
|
||||
self = self.comma_sep(args.as_generator().upvar_tys())?;
|
||||
self = self.comma_sep(args.as_generator().upvar_tys().iter())?;
|
||||
}
|
||||
p!(")");
|
||||
|
||||
@ -900,7 +900,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||
print(args.as_closure().sig_as_fn_ptr_ty())
|
||||
);
|
||||
p!(" upvar_tys=(");
|
||||
self = self.comma_sep(args.as_closure().upvar_tys())?;
|
||||
self = self.comma_sep(args.as_closure().upvar_tys().iter())?;
|
||||
p!(")");
|
||||
}
|
||||
}
|
||||
@ -2806,10 +2806,7 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
TraitPredPrintModifiersAndPath<'tcx> {
|
||||
if let ty::BoundConstness::ConstIfConst = self.0.constness {
|
||||
p!("~const ")
|
||||
}
|
||||
|
||||
// FIXME(effects) print `~const` here
|
||||
if let ty::ImplPolarity::Negative = self.0.polarity {
|
||||
p!("!")
|
||||
}
|
||||
@ -2843,9 +2840,7 @@ define_print_and_forward_display! {
|
||||
|
||||
ty::TraitPredicate<'tcx> {
|
||||
p!(print(self.trait_ref.self_ty()), ": ");
|
||||
if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
|
||||
p!("~const ");
|
||||
}
|
||||
// FIXME(effects) print `~const` here
|
||||
if let ty::ImplPolarity::Negative = self.polarity {
|
||||
p!("!");
|
||||
}
|
||||
|
@ -826,7 +826,6 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
|
||||
) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> {
|
||||
Ok(ty::TraitPredicate {
|
||||
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
|
||||
constness: relation.relate(a.constness, b.constness)?,
|
||||
polarity: relation.relate(a.polarity, b.polarity)?,
|
||||
})
|
||||
}
|
||||
|
@ -172,9 +172,7 @@ impl fmt::Debug for ty::ParamConst {
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let ty::BoundConstness::ConstIfConst = self.constness {
|
||||
write!(f, "~const ")?;
|
||||
}
|
||||
// FIXME(effects) printing?
|
||||
write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
|
||||
}
|
||||
}
|
||||
|
@ -296,15 +296,13 @@ impl<'tcx> ClosureArgs<'tcx> {
|
||||
/// In case there was a type error in figuring out the types of the captured path, an
|
||||
/// empty iterator is returned.
|
||||
#[inline]
|
||||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
|
||||
pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
|
||||
match self.tupled_upvars_ty().kind() {
|
||||
TyKind::Error(_) => None,
|
||||
TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
|
||||
TyKind::Error(_) => ty::List::empty(),
|
||||
TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
|
||||
TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
|
||||
ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
|
||||
}
|
||||
.into_iter()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Returns the tuple type representing the upvars for this closure.
|
||||
@ -436,15 +434,13 @@ impl<'tcx> GeneratorArgs<'tcx> {
|
||||
/// In case there was a type error in figuring out the types of the captured path, an
|
||||
/// empty iterator is returned.
|
||||
#[inline]
|
||||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
|
||||
pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
|
||||
match self.tupled_upvars_ty().kind() {
|
||||
TyKind::Error(_) => None,
|
||||
TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
|
||||
TyKind::Error(_) => ty::List::empty(),
|
||||
TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
|
||||
TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
|
||||
ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
|
||||
}
|
||||
.into_iter()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Returns the tuple type representing the upvars for this generator.
|
||||
@ -576,7 +572,7 @@ impl<'tcx> GeneratorArgs<'tcx> {
|
||||
/// This is the types of the fields of a generator which are not stored in a
|
||||
/// variant.
|
||||
#[inline]
|
||||
pub fn prefix_tys(self) -> impl Iterator<Item = Ty<'tcx>> {
|
||||
pub fn prefix_tys(self) -> &'tcx List<Ty<'tcx>> {
|
||||
self.upvar_tys()
|
||||
}
|
||||
}
|
||||
@ -592,20 +588,18 @@ impl<'tcx> UpvarArgs<'tcx> {
|
||||
/// In case there was a type error in figuring out the types of the captured path, an
|
||||
/// empty iterator is returned.
|
||||
#[inline]
|
||||
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
|
||||
pub fn upvar_tys(self) -> &'tcx List<Ty<'tcx>> {
|
||||
let tupled_tys = match self {
|
||||
UpvarArgs::Closure(args) => args.as_closure().tupled_upvars_ty(),
|
||||
UpvarArgs::Generator(args) => args.as_generator().tupled_upvars_ty(),
|
||||
};
|
||||
|
||||
match tupled_tys.kind() {
|
||||
TyKind::Error(_) => None,
|
||||
TyKind::Tuple(..) => Some(self.tupled_upvars_ty().tuple_fields()),
|
||||
TyKind::Error(_) => ty::List::empty(),
|
||||
TyKind::Tuple(..) => self.tupled_upvars_ty().tuple_fields(),
|
||||
TyKind::Infer(_) => bug!("upvar_tys called before capture types are inferred"),
|
||||
ty => bug!("Unexpected representation of upvar types tuple {:?}", ty),
|
||||
}
|
||||
.into_iter()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -728,7 +722,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
|
||||
use crate::ty::ToPredicate;
|
||||
match self.skip_binder() {
|
||||
ExistentialPredicate::Trait(tr) => {
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx)
|
||||
self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
|
||||
@ -743,7 +737,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
|
||||
let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
|
||||
ty::TraitRef::new(tcx, did, err_args)
|
||||
};
|
||||
self.rebind(trait_ref).without_const().to_predicate(tcx)
|
||||
self.rebind(trait_ref).to_predicate(tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -875,18 +869,6 @@ impl<'tcx> TraitRef<'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts this trait ref to a trait predicate with a given `constness` and a positive polarity.
|
||||
#[inline]
|
||||
pub fn with_constness(self, constness: ty::BoundConstness) -> ty::TraitPredicate<'tcx> {
|
||||
ty::TraitPredicate { trait_ref: self, constness, polarity: ty::ImplPolarity::Positive }
|
||||
}
|
||||
|
||||
/// Converts this trait ref to a trait predicate without `const` and a positive polarity.
|
||||
#[inline]
|
||||
pub fn without_const(self) -> ty::TraitPredicate<'tcx> {
|
||||
self.with_constness(ty::BoundConstness::NotConst)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn self_ty(&self) -> Ty<'tcx> {
|
||||
self.args.type_at(0)
|
||||
|
@ -860,20 +860,14 @@ where
|
||||
fn open_drop(&mut self) -> BasicBlock {
|
||||
let ty = self.place_ty(self.place);
|
||||
match ty.kind() {
|
||||
ty::Closure(_, args) => {
|
||||
let tys: Vec<_> = args.as_closure().upvar_tys().collect();
|
||||
self.open_drop_for_tuple(&tys)
|
||||
}
|
||||
ty::Closure(_, args) => self.open_drop_for_tuple(&args.as_closure().upvar_tys()),
|
||||
// Note that `elaborate_drops` only drops the upvars of a generator,
|
||||
// and this is ok because `open_drop` here can only be reached
|
||||
// within that own generator's resume function.
|
||||
// This should only happen for the self argument on the resume function.
|
||||
// It effectively only contains upvars until the generator transformation runs.
|
||||
// See librustc_body/transform/generator.rs for more details.
|
||||
ty::Generator(_, args, _) => {
|
||||
let tys: Vec<_> = args.as_generator().upvar_tys().collect();
|
||||
self.open_drop_for_tuple(&tys)
|
||||
}
|
||||
ty::Generator(_, args, _) => self.open_drop_for_tuple(&args.as_generator().upvar_tys()),
|
||||
ty::Tuple(fields) => self.open_drop_for_tuple(fields),
|
||||
ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
|
||||
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
|
||||
|
@ -856,7 +856,7 @@ fn sanitize_witness<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
witness: Ty<'tcx>,
|
||||
upvars: Vec<Ty<'tcx>>,
|
||||
upvars: &'tcx ty::List<Ty<'tcx>>,
|
||||
layout: &GeneratorLayout<'tcx>,
|
||||
) {
|
||||
let did = body.source.def_id();
|
||||
@ -1471,7 +1471,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||
let args = args.as_generator();
|
||||
(
|
||||
args.discr_ty(tcx),
|
||||
args.upvar_tys().collect::<Vec<_>>(),
|
||||
args.upvar_tys(),
|
||||
args.witness(),
|
||||
movability == hir::Movability::Movable,
|
||||
)
|
||||
|
@ -147,7 +147,7 @@ where
|
||||
|
||||
fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness: _, polarity: _ }) => {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
|
||||
self.visit_trait(trait_ref)
|
||||
}
|
||||
ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
|
||||
|
@ -72,7 +72,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
cause: traits::ObligationCause::dummy(),
|
||||
param_env,
|
||||
recursion_depth: 0,
|
||||
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
|
||||
predicate: ty::Binder::dummy(trait_ref).to_predicate(self.tcx),
|
||||
};
|
||||
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
|
||||
}
|
||||
|
@ -727,7 +727,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
self.tcx(),
|
||||
ty::TraitPredicate {
|
||||
trait_ref: self_trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
},
|
||||
);
|
||||
|
@ -97,7 +97,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
orig_env,
|
||||
ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: if polarity {
|
||||
ImplPolarity::Positive
|
||||
} else {
|
||||
@ -260,7 +259,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
|
||||
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
// Auto traits are positive
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}));
|
||||
|
@ -97,7 +97,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
|
||||
cause,
|
||||
recursion_depth: 0,
|
||||
param_env,
|
||||
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
|
||||
predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,6 @@ pub trait InferCtxtExt<'tcx> {
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
|
||||
}
|
||||
@ -356,7 +355,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
|
||||
self.commit_if_ok(|_| {
|
||||
@ -372,12 +370,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
span: DUMMY_SP,
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
});
|
||||
// FIXME(effects)
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
|
||||
let obligation = Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty.rebind(ty::TraitPredicate { trait_ref, constness, polarity }),
|
||||
ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
|
||||
);
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
ocx.register_obligation(obligation);
|
||||
@ -689,8 +688,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
let trait_predicate = bound_predicate.rebind(trait_predicate);
|
||||
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
||||
|
||||
let predicate_is_const = ty::BoundConstness::ConstIfConst
|
||||
== trait_predicate.skip_binder().constness;
|
||||
// FIXME(effects)
|
||||
let predicate_is_const = false;
|
||||
|
||||
if self.tcx.sess.has_errors().is_some()
|
||||
&& trait_predicate.references_error()
|
||||
@ -1909,9 +1908,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
.all_impls(trait_pred.def_id())
|
||||
.filter_map(|def_id| {
|
||||
if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
|
||||
|| !trait_pred
|
||||
.skip_binder()
|
||||
.is_constness_satisfied_by(self.tcx.constness(def_id))
|
||||
|| !self.tcx.is_user_visible_dep(def_id.krate)
|
||||
{
|
||||
return None;
|
||||
@ -2996,7 +2992,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
|
||||
obligation.param_env,
|
||||
trait_ref.self_ty(),
|
||||
trait_predicate.skip_binder().constness,
|
||||
trait_predicate.skip_binder().polarity,
|
||||
)
|
||||
{
|
||||
@ -3099,14 +3094,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
fn maybe_add_note_for_unsatisfied_const(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
_obligation: &PredicateObligation<'tcx>,
|
||||
_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
_trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
_err: &mut Diagnostic,
|
||||
_span: Span,
|
||||
) -> UnsatisfiedConst {
|
||||
let mut unsatisfied_const = UnsatisfiedConst(false);
|
||||
if trait_predicate.is_const_if_const() {
|
||||
let unsatisfied_const = UnsatisfiedConst(false);
|
||||
// FIXME(effects)
|
||||
/* if trait_predicate.is_const_if_const() {
|
||||
let non_const_predicate = trait_ref.without_const();
|
||||
let non_const_obligation = Obligation {
|
||||
cause: obligation.cause.clone(),
|
||||
@ -3126,7 +3122,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} */
|
||||
unsatisfied_const
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
|
||||
def_id: DefId,
|
||||
) -> bool {
|
||||
let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
|
||||
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
|
||||
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref)
|
||||
}
|
||||
|
||||
/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
|
||||
|
@ -574,7 +574,6 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||
// implement auto traits if the underlying type does as well.
|
||||
if let ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref: pred_trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}) = pred.kind().skip_binder()
|
||||
&& pred_trait_ref.self_ty() == tcx.types.self_param
|
||||
|
@ -1306,7 +1306,7 @@ fn normalize_to_error<'a, 'tcx>(
|
||||
cause,
|
||||
recursion_depth: depth,
|
||||
param_env,
|
||||
predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
|
||||
predicate: trait_ref.to_predicate(selcx.tcx()),
|
||||
};
|
||||
let tcx = selcx.infcx.tcx;
|
||||
let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
|
||||
@ -1867,8 +1867,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
if selcx.infcx.predicate_must_hold_modulo_regions(
|
||||
&obligation.with(
|
||||
selcx.tcx(),
|
||||
ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty])
|
||||
.without_const(),
|
||||
ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
|
||||
),
|
||||
) =>
|
||||
{
|
||||
@ -2152,8 +2151,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
|
||||
LangItem::Sized,
|
||||
obligation.cause.span(),
|
||||
[self_ty],
|
||||
)
|
||||
.without_const();
|
||||
);
|
||||
obligations.push(obligation.with(tcx, sized_predicate));
|
||||
}
|
||||
(metadata_ty.into(), obligations)
|
||||
|
@ -291,9 +291,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
constraints.outlives.extend(
|
||||
args.as_generator().upvar_tys().map(|t| -> ty::GenericArg<'tcx> { t.into() }),
|
||||
);
|
||||
constraints
|
||||
.outlives
|
||||
.extend(args.as_generator().upvar_tys().iter().map(ty::GenericArg::from));
|
||||
constraints.outlives.push(args.as_generator().resume_ty().into());
|
||||
}
|
||||
|
||||
|
@ -154,9 +154,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.infcx
|
||||
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
|
||||
|
||||
candidates
|
||||
.vec
|
||||
.extend(result.into_iter().map(|(idx, constness)| ProjectionCandidate(idx, constness)));
|
||||
// FIXME(effects) proper constness needed?
|
||||
candidates.vec.extend(
|
||||
result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)),
|
||||
);
|
||||
}
|
||||
|
||||
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
|
||||
|
@ -59,7 +59,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
ParamCandidate(param) => {
|
||||
let obligations =
|
||||
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
|
||||
ImplSource::Param(param.skip_binder().constness, obligations)
|
||||
// FIXME(effects)
|
||||
ImplSource::Param(ty::BoundConstness::NotConst, obligations)
|
||||
}
|
||||
|
||||
ImplCandidate(impl_def_id) => {
|
||||
@ -128,14 +129,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
subobligation.set_depth_from_parent(obligation.recursion_depth);
|
||||
}
|
||||
|
||||
if !obligation.predicate.is_const_if_const() {
|
||||
// normalize nested predicates according to parent predicate's constness.
|
||||
impl_src = impl_src.map(|mut o| {
|
||||
o.predicate = o.predicate.without_const(self.tcx());
|
||||
o
|
||||
});
|
||||
}
|
||||
|
||||
Ok(impl_src)
|
||||
}
|
||||
|
||||
@ -1305,6 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// If we have a projection type, make sure to normalize it so we replace it
|
||||
// with a fresh infer variable
|
||||
ty::Alias(ty::Projection | ty::Inherent, ..) => {
|
||||
// FIXME(effects) this needs constness
|
||||
let predicate = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
@ -1317,7 +1311,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
cause.span,
|
||||
[nested_ty],
|
||||
),
|
||||
constness: ty::BoundConstness::ConstIfConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}),
|
||||
&mut nested,
|
||||
@ -1336,6 +1329,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// since it's either not `const Drop` (and we raise an error during selection),
|
||||
// or it's an ADT (and we need to check for a custom impl during selection)
|
||||
_ => {
|
||||
// FIXME(effects) this needs constness
|
||||
let predicate = self_ty.rebind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::from_lang_item(
|
||||
self.tcx(),
|
||||
@ -1343,7 +1337,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
cause.span,
|
||||
[nested_ty],
|
||||
),
|
||||
constness: ty::BoundConstness::ConstIfConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
});
|
||||
|
||||
|
@ -1583,7 +1583,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> {
|
||||
) -> smallvec::SmallVec<[usize; 2]> {
|
||||
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
|
||||
@ -1632,7 +1632,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
_ => false,
|
||||
}
|
||||
}) {
|
||||
return Some((idx, pred.constness));
|
||||
return Some(idx);
|
||||
}
|
||||
}
|
||||
None
|
||||
@ -1820,7 +1820,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
(ParamCandidate(other), ParamCandidate(victim)) => {
|
||||
let same_except_bound_vars = other.skip_binder().trait_ref
|
||||
== victim.skip_binder().trait_ref
|
||||
&& other.skip_binder().constness == victim.skip_binder().constness
|
||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
||||
&& !other.skip_binder().trait_ref.has_escaping_bound_vars();
|
||||
if same_except_bound_vars {
|
||||
@ -1830,12 +1829,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
// probably best characterized as a "hack", since we might prefer to just do our
|
||||
// best to *not* create essentially duplicate candidates in the first place.
|
||||
DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len())
|
||||
} else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
|
||||
&& victim.skip_binder().constness == ty::BoundConstness::NotConst
|
||||
&& other.skip_binder().polarity == victim.skip_binder().polarity
|
||||
{
|
||||
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||
DropVictim::Yes
|
||||
} else {
|
||||
DropVictim::No
|
||||
}
|
||||
@ -2169,7 +2162,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
let all = args
|
||||
.as_generator()
|
||||
.upvar_tys()
|
||||
.chain(iter::once(args.as_generator().witness()))
|
||||
.iter()
|
||||
.chain([args.as_generator().witness()])
|
||||
.collect::<Vec<_>>();
|
||||
Where(obligation.predicate.rebind(all))
|
||||
}
|
||||
@ -2210,7 +2204,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
// Not yet resolved.
|
||||
Ambiguous
|
||||
} else {
|
||||
Where(obligation.predicate.rebind(args.as_closure().upvar_tys().collect()))
|
||||
Where(obligation.predicate.rebind(args.as_closure().upvar_tys().to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,16 +500,12 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
|
||||
let mut pretty_predicates =
|
||||
Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
|
||||
|
||||
for (mut p, _) in predicates {
|
||||
for (p, _) in predicates {
|
||||
if let Some(poly_trait_ref) = p.as_trait_clause() {
|
||||
if Some(poly_trait_ref.def_id()) == sized_trait {
|
||||
types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
|
||||
p = p.without_const(tcx);
|
||||
}
|
||||
}
|
||||
pretty_predicates.push(p.to_string());
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
|
||||
fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let trait_ref = item.trait_ref();
|
||||
let pred = trait_ref.without_const().to_predicate(tcx);
|
||||
let pred = trait_ref.to_predicate(tcx);
|
||||
|
||||
debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
|
||||
|
||||
@ -113,9 +113,13 @@ impl<'tcx> TraitAliasExpander<'tcx> {
|
||||
|
||||
// Don't recurse if this trait alias is already on the stack for the DFS search.
|
||||
let anon_pred = anonymize_predicate(tcx, pred);
|
||||
if item.path.iter().rev().skip(1).any(|&(tr, _)| {
|
||||
anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred
|
||||
}) {
|
||||
if item
|
||||
.path
|
||||
.iter()
|
||||
.rev()
|
||||
.skip(1)
|
||||
.any(|&(tr, _)| anonymize_predicate(tcx, tr.to_predicate(tcx)) == anon_pred)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
|
||||
|
||||
let mut emit_vptr_on_new_entry = false;
|
||||
let mut visited = PredicateSet::new(tcx);
|
||||
let predicate = trait_ref.without_const().to_predicate(tcx);
|
||||
let predicate = trait_ref.to_predicate(tcx);
|
||||
let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
|
||||
smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
|
||||
visited.insert(predicate);
|
||||
|
@ -348,11 +348,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// if the trait predicate is not const, the wf obligations should not be const as well.
|
||||
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
|
||||
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.args)
|
||||
} else {
|
||||
self.nominal_obligations(trait_ref.def_id, trait_ref.args)
|
||||
};
|
||||
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.args);
|
||||
|
||||
debug!("compute_trait_pred obligations {:?}", obligations);
|
||||
let param_env = self.param_env;
|
||||
@ -445,8 +441,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
// `i32: Clone`
|
||||
// `i32: Copy`
|
||||
// ]
|
||||
// Projection types do not require const predicates.
|
||||
let obligations = self.nominal_obligations_without_const(data.def_id, data.args);
|
||||
let obligations = self.nominal_obligations(data.def_id, data.args);
|
||||
self.out.extend(obligations);
|
||||
|
||||
self.compute_projection_args(data.args);
|
||||
@ -472,8 +467,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
self.recursion_depth,
|
||||
&mut self.out,
|
||||
);
|
||||
// Inherent projection types do not require const predicates.
|
||||
let obligations = self.nominal_obligations_without_const(data.def_id, args);
|
||||
let obligations = self.nominal_obligations(data.def_id, args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
|
||||
@ -516,7 +510,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
cause,
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
ty::Binder::dummy(trait_ref).without_const(),
|
||||
ty::Binder::dummy(trait_ref),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -667,7 +661,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
}
|
||||
|
||||
ty::FnDef(did, args) => {
|
||||
let obligations = self.nominal_obligations_without_const(did, args);
|
||||
let obligations = self.nominal_obligations(did, args);
|
||||
self.out.extend(obligations);
|
||||
}
|
||||
|
||||
@ -822,11 +816,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn nominal_obligations_inner(
|
||||
fn nominal_obligations(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
remap_constness: bool,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
let predicates = self.tcx().predicates_of(def_id);
|
||||
let mut origins = vec![def_id; predicates.predicates.len()];
|
||||
@ -841,16 +834,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
debug_assert_eq!(predicates.predicates.len(), origins.len());
|
||||
|
||||
iter::zip(predicates, origins.into_iter().rev())
|
||||
.map(|((mut pred, span), origin_def_id)| {
|
||||
.map(|((pred, span), origin_def_id)| {
|
||||
let code = if span.is_dummy() {
|
||||
traits::ItemObligation(origin_def_id)
|
||||
} else {
|
||||
traits::BindingObligation(origin_def_id, span)
|
||||
};
|
||||
let cause = self.cause(code);
|
||||
if remap_constness {
|
||||
pred = pred.without_const(self.tcx());
|
||||
}
|
||||
traits::Obligation::with_depth(
|
||||
self.tcx(),
|
||||
cause,
|
||||
@ -863,22 +853,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn nominal_obligations(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
self.nominal_obligations_inner(def_id, args, false)
|
||||
}
|
||||
|
||||
fn nominal_obligations_without_const(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||
self.nominal_obligations_inner(def_id, args, true)
|
||||
}
|
||||
|
||||
fn from_object_ty(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
|
@ -317,7 +317,9 @@ fn layout_of_uncached<'tcx>(
|
||||
ty::Closure(_, ref args) => {
|
||||
let tys = args.as_closure().upvar_tys();
|
||||
univariant(
|
||||
&tys.map(|ty| Ok(cx.layout_of(ty)?.layout)).try_collect::<IndexVec<_, _>>()?,
|
||||
&tys.iter()
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.try_collect::<IndexVec<_, _>>()?,
|
||||
&ReprOptions::default(),
|
||||
StructKind::AlwaysSized,
|
||||
)?
|
||||
@ -729,7 +731,7 @@ fn generator_layout<'tcx>(
|
||||
// Build a prefix layout, including "promoting" all ineligible
|
||||
// locals as part of the prefix. We compute the layout of all of
|
||||
// these fields at once to get optimal packing.
|
||||
let tag_index = args.as_generator().prefix_tys().count();
|
||||
let tag_index = args.as_generator().prefix_tys().len();
|
||||
|
||||
// `info.variant_fields` already accounts for the reserved variants, so no need to add them.
|
||||
let max_discr = (info.variant_fields.len() - 1) as u128;
|
||||
@ -748,6 +750,7 @@ fn generator_layout<'tcx>(
|
||||
let prefix_layouts = args
|
||||
.as_generator()
|
||||
.prefix_tys()
|
||||
.iter()
|
||||
.map(|ty| Ok(cx.layout_of(ty)?.layout))
|
||||
.chain(iter::once(Ok(tag_layout)))
|
||||
.chain(promoted_layouts)
|
||||
@ -1062,6 +1065,7 @@ fn variant_info_for_generator<'tcx>(
|
||||
let upvar_fields: Vec<_> = args
|
||||
.as_generator()
|
||||
.upvar_tys()
|
||||
.iter()
|
||||
.zip(upvar_names)
|
||||
.enumerate()
|
||||
.map(|(field_idx, (_, name))| {
|
||||
|
@ -120,12 +120,16 @@ where
|
||||
_ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
|
||||
|
||||
ty::Closure(_, args) => {
|
||||
queue_type(self, args.as_closure().tupled_upvars_ty());
|
||||
for upvar in args.as_closure().upvar_tys() {
|
||||
queue_type(self, upvar);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Generator(def_id, args, _) => {
|
||||
let args = args.as_generator();
|
||||
queue_type(self, args.tupled_upvars_ty());
|
||||
for upvar in args.upvar_tys() {
|
||||
queue_type(self, upvar);
|
||||
}
|
||||
|
||||
let witness = args.witness();
|
||||
let interior_tys = match witness.kind() {
|
||||
|
@ -1893,7 +1893,8 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
||||
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
|
||||
/// same memory layout, the following is not allowed and undefined behavior:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[cfg_attr(bootstrap, doc = "```rust,no_run")]
|
||||
#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
|
||||
/// # use std::cell::UnsafeCell;
|
||||
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
|
||||
/// let t = ptr as *const UnsafeCell<T> as *mut T;
|
||||
|
@ -197,8 +197,8 @@ impl CStr {
|
||||
///
|
||||
/// This function will wrap the provided `ptr` with a `CStr` wrapper, which
|
||||
/// allows inspection and interoperation of non-owned C strings. The total
|
||||
/// size of the raw C string must be smaller than `isize::MAX` **bytes**
|
||||
/// in memory due to calling the `slice::from_raw_parts` function.
|
||||
/// size of the terminated buffer must be smaller than [`isize::MAX`] **bytes**
|
||||
/// in memory (a restriction from [`slice::from_raw_parts`]).
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
@ -295,11 +295,11 @@ impl CStr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a C string wrapper from a byte slice.
|
||||
/// Creates a C string wrapper from a byte slice with any number of nuls.
|
||||
///
|
||||
/// This method will create a `CStr` from any byte slice that contains at
|
||||
/// least one nul byte. The caller does not need to know or specify where
|
||||
/// the nul byte is located.
|
||||
/// least one nul byte. Unlike with [`CStr::from_bytes_with_nul`], the caller
|
||||
/// does not need to know where the nul byte is located.
|
||||
///
|
||||
/// If the first byte is a nul character, this method will return an
|
||||
/// empty `CStr`. If multiple nul characters are present, the `CStr` will
|
||||
@ -341,7 +341,8 @@ impl CStr {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a C string wrapper from a byte slice.
|
||||
/// Creates a C string wrapper from a byte slice with exactly one nul
|
||||
/// terminator.
|
||||
///
|
||||
/// This function will cast the provided `bytes` to a `CStr`
|
||||
/// wrapper after ensuring that the byte slice is nul-terminated
|
||||
|
@ -113,9 +113,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
}
|
||||
let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
|
||||
let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
|
||||
let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
|
||||
let mut fmt_override = ignore::overrides::OverrideBuilder::new(&build.src);
|
||||
for ignore in rustfmt_config.ignore {
|
||||
ignore_fmt.add(&format!("!{ignore}")).expect(&ignore);
|
||||
fmt_override.add(&format!("!{ignore}")).expect(&ignore);
|
||||
}
|
||||
let git_available = match Command::new("git")
|
||||
.arg("--version")
|
||||
@ -152,6 +152,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
.map(|entry| {
|
||||
entry.split(' ').nth(1).expect("every git status entry should list a path")
|
||||
});
|
||||
let mut untracked_count = 0;
|
||||
for untracked_path in untracked_paths {
|
||||
println!("skip untracked path {untracked_path} during rustfmt invocations");
|
||||
// The leading `/` makes it an exact match against the
|
||||
@ -159,7 +160,8 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
// have `foo.rs` in the repository root it will also match
|
||||
// against anything like `compiler/rustc_foo/src/foo.rs`,
|
||||
// preventing the latter from being formatted.
|
||||
ignore_fmt.add(&format!("!/{untracked_path}")).expect(&untracked_path);
|
||||
untracked_count += 1;
|
||||
fmt_override.add(&format!("!/{untracked_path}")).expect(&untracked_path);
|
||||
}
|
||||
// Only check modified files locally to speed up runtime.
|
||||
// We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through;
|
||||
@ -172,10 +174,25 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
println!("formatting modified file {file}");
|
||||
}
|
||||
} else {
|
||||
println!("formatting {} modified files", files.len());
|
||||
let pluralized = |count| if count > 1 { "files" } else { "file" };
|
||||
let untracked_msg = if untracked_count == 0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(
|
||||
", skipped {} untracked {}",
|
||||
untracked_count,
|
||||
pluralized(untracked_count),
|
||||
)
|
||||
};
|
||||
println!(
|
||||
"formatting {} modified {}{}",
|
||||
files.len(),
|
||||
pluralized(files.len()),
|
||||
untracked_msg
|
||||
);
|
||||
}
|
||||
for file in files {
|
||||
ignore_fmt.add(&format!("/{file}")).expect(&file);
|
||||
fmt_override.add(&format!("/{file}")).expect(&file);
|
||||
}
|
||||
}
|
||||
Ok(None) => {}
|
||||
@ -196,7 +213,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
println!("Could not find usable git. Skipping git-aware format checks");
|
||||
}
|
||||
|
||||
let ignore_fmt = ignore_fmt.build().unwrap();
|
||||
let fmt_override = fmt_override.build().unwrap();
|
||||
|
||||
let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
|
||||
eprintln!("./x.py fmt is not supported on this channel");
|
||||
@ -252,7 +269,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
||||
None => WalkBuilder::new(src.clone()),
|
||||
}
|
||||
.types(matcher)
|
||||
.overrides(ignore_fmt)
|
||||
.overrides(fmt_override)
|
||||
.build_parallel();
|
||||
|
||||
// there is a lot of blocking involved in spawning a child process and reading files to format.
|
||||
|
@ -24,7 +24,6 @@ use crate::util::{self, exe, output, t, up_to_date};
|
||||
use crate::{CLang, GitRepo, Kind};
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use build_helper::git::get_git_merge_base;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LlvmResult {
|
||||
@ -129,19 +128,13 @@ pub fn prebuilt_llvm_config(
|
||||
/// This retrieves the LLVM sha we *want* to use, according to git history.
|
||||
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
|
||||
let llvm_sha = if is_git {
|
||||
// We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
|
||||
// walk back further to the last bors merge commit that actually changed LLVM. The first
|
||||
// step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
|
||||
// in that case.
|
||||
let closest_upstream =
|
||||
get_git_merge_base(Some(&config.src)).unwrap_or_else(|_| "HEAD".into());
|
||||
let mut rev_list = config.git();
|
||||
rev_list.args(&[
|
||||
PathBuf::from("rev-list"),
|
||||
format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
|
||||
"-n1".into(),
|
||||
"--first-parent".into(),
|
||||
closest_upstream.into(),
|
||||
"HEAD".into(),
|
||||
"--".into(),
|
||||
config.src.join("src/llvm-project"),
|
||||
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
|
||||
|
@ -370,9 +370,8 @@ fn clean_poly_trait_predicate<'tcx>(
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> Option<WherePredicate> {
|
||||
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
|
||||
if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
||||
&& Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
|
||||
{
|
||||
// FIXME(effects) check constness
|
||||
if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -480,12 +480,6 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
|
||||
cx: &mut DocContext<'_>,
|
||||
item_def_id: DefId,
|
||||
) -> impl Iterator<Item = Item> {
|
||||
// FIXME: To be removed once `parallel_compiler` bugs are fixed!
|
||||
// More information in <https://github.com/rust-lang/rust/pull/106930>.
|
||||
if cfg!(parallel_compiler) {
|
||||
return vec![].into_iter().chain(vec![].into_iter());
|
||||
}
|
||||
|
||||
let auto_impls = cx
|
||||
.sess()
|
||||
.prof
|
||||
|
@ -78,22 +78,13 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
|
||||
/// We will then fall back to origin/master in the hope that at least this exists.
|
||||
pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
|
||||
let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
|
||||
for upstream_master in [format!("{upstream_remote}/master"), format!("origin/master")] {
|
||||
if rev_exists(&upstream_master, git_dir)? {
|
||||
return Ok(upstream_master);
|
||||
}
|
||||
let upstream_master = format!("{upstream_remote}/master");
|
||||
if rev_exists(&upstream_master, git_dir)? {
|
||||
return Ok(upstream_master);
|
||||
}
|
||||
|
||||
Err(format!("Cannot find any suitable upstream master branch"))
|
||||
}
|
||||
|
||||
pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> {
|
||||
let updated_master = updated_master_branch(git_dir)?;
|
||||
let mut git = Command::new("git");
|
||||
if let Some(git_dir) = git_dir {
|
||||
git.current_dir(git_dir);
|
||||
}
|
||||
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
|
||||
// We could implement smarter logic here in the future.
|
||||
Ok("origin/master".into())
|
||||
}
|
||||
|
||||
/// Returns the files that have been modified in the current branch compared to the master branch.
|
||||
@ -103,13 +94,20 @@ pub fn get_git_modified_files(
|
||||
git_dir: Option<&Path>,
|
||||
extensions: &Vec<&str>,
|
||||
) -> Result<Option<Vec<String>>, String> {
|
||||
let merge_base = get_git_merge_base(git_dir)?;
|
||||
let Ok(updated_master) = updated_master_branch(git_dir) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let mut git = Command::new("git");
|
||||
if let Some(git_dir) = git_dir {
|
||||
git.current_dir(git_dir);
|
||||
}
|
||||
let files = output_result(git.args(["diff-index", "--name-only", merge_base.trim()]))?
|
||||
let git = || {
|
||||
let mut git = Command::new("git");
|
||||
if let Some(git_dir) = git_dir {
|
||||
git.current_dir(git_dir);
|
||||
}
|
||||
git
|
||||
};
|
||||
|
||||
let merge_base = output_result(git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
|
||||
let files = output_result(git().arg("diff-index").arg("--name-only").arg(merge_base.trim()))?
|
||||
.lines()
|
||||
.map(|s| s.trim().to_owned())
|
||||
.filter(|f| {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c91a693e7977e33a1064b63a5daf5fb689f01651
|
||||
Subproject commit 020651c52257052d28f6fd83fbecf5cfa1ed516c
|
@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty::{
|
||||
self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
|
||||
self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
|
||||
ToPredicate, TraitPredicate, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -523,7 +523,6 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
|
||||
if let ClauseKind::Trait(p) = p.kind().skip_binder()
|
||||
&& p.trait_ref.def_id == eq_trait_id
|
||||
&& let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
|
||||
&& p.constness == BoundConstness::NotConst
|
||||
{
|
||||
// Flag types which already have an `Eq` bound.
|
||||
params[self_ty.index as usize].1 = false;
|
||||
@ -535,7 +534,6 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
|
||||
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
|
||||
ClauseKind::Trait(TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
|
||||
constness: BoundConstness::NotConst,
|
||||
polarity: ImplPolarity::Positive,
|
||||
})
|
||||
.to_predicate(tcx)
|
||||
|
@ -10,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, BoundConstness, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
|
||||
self, Binder, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
|
||||
GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
|
||||
};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -171,7 +171,6 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
||||
= cx.tcx.infer_ctxt().build().type_implements_fn_trait(
|
||||
cx.param_env,
|
||||
Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
|
||||
BoundConstness::NotConst,
|
||||
ImplPolarity::Positive,
|
||||
) && path_to_local(callee)
|
||||
.map_or(
|
||||
|
@ -16,7 +16,7 @@ use rustc_middle::mir::{
|
||||
};
|
||||
use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
@ -399,11 +399,12 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME(effects) constness
|
||||
let obligation = Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::dummy_with_span(body.span),
|
||||
ConstCx::new(tcx, body).param_env,
|
||||
TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]).with_constness(BoundConstness::ConstIfConst),
|
||||
TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]),
|
||||
);
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
|
@ -267,7 +267,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
|
||||
cause: ObligationCause::dummy(),
|
||||
param_env,
|
||||
recursion_depth: 0,
|
||||
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
|
||||
predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
|
||||
};
|
||||
infcx
|
||||
.evaluate_obligation(&obligation)
|
||||
|
@ -18,7 +18,7 @@ use rustc_middle::ty::{
|
||||
layout::{HasParamEnv, LayoutOf},
|
||||
Ty,
|
||||
};
|
||||
use rustc_target::abi::{Abi, Size};
|
||||
use rustc_target::abi::{Abi, Align, Size};
|
||||
|
||||
use crate::borrow_tracker::{
|
||||
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
|
||||
@ -619,6 +619,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
retag_info: RetagInfo, // diagnostics info about this retag
|
||||
) -> InterpResult<'tcx, Option<AllocId>> {
|
||||
let this = self.eval_context_mut();
|
||||
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
|
||||
this.check_ptr_access_align(place.ptr, size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
|
||||
|
||||
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
|
||||
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
|
||||
@ -707,18 +709,6 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
|
||||
log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
|
||||
|
||||
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
|
||||
let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
|
||||
if base_offset + size > alloc_size {
|
||||
throw_ub!(PointerOutOfBounds {
|
||||
alloc_id,
|
||||
alloc_size,
|
||||
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
|
||||
ptr_size: size,
|
||||
msg: CheckInAllocMsg::InboundsTest
|
||||
});
|
||||
}
|
||||
|
||||
trace!(
|
||||
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
|
||||
new_tag,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use log::trace;
|
||||
|
||||
use rustc_target::abi::{Abi, Size};
|
||||
use rustc_target::abi::{Abi, Align, Size};
|
||||
|
||||
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
|
||||
use rustc_middle::{
|
||||
@ -182,6 +182,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
new_tag: BorTag,
|
||||
) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> {
|
||||
let this = self.eval_context_mut();
|
||||
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
|
||||
this.check_ptr_access_align(place.ptr, ptr_size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
|
||||
|
||||
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
|
||||
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
|
||||
@ -202,51 +204,33 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
|
||||
};
|
||||
|
||||
trace!("Reborrow of size {:?}", ptr_size);
|
||||
let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO {
|
||||
this.ptr_get_alloc_id(place.ptr)?
|
||||
} else {
|
||||
match this.ptr_try_get_alloc_id(place.ptr) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
// This pointer doesn't come with an AllocId, so there's no
|
||||
// memory to do retagging in.
|
||||
trace!(
|
||||
"reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
|
||||
new_tag,
|
||||
place.ptr,
|
||||
place.layout.ty,
|
||||
);
|
||||
log_creation(this, None)?;
|
||||
return Ok(None);
|
||||
}
|
||||
let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr) {
|
||||
Ok(data) => {
|
||||
// Unlike SB, we *do* a proper retag for size 0 if can identify the allocation.
|
||||
// After all, the pointer may be lazily initialized outside this initial range.
|
||||
data
|
||||
},
|
||||
Err(_) => {
|
||||
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
|
||||
// This pointer doesn't come with an AllocId, so there's no
|
||||
// memory to do retagging in.
|
||||
trace!(
|
||||
"reborrow of size 0: reference {:?} derived from {:?} (pointee {})",
|
||||
new_tag,
|
||||
place.ptr,
|
||||
place.layout.ty,
|
||||
);
|
||||
log_creation(this, None)?;
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
|
||||
|
||||
let orig_tag = match parent_prov {
|
||||
ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers
|
||||
ProvenanceExtra::Concrete(tag) => tag,
|
||||
};
|
||||
|
||||
// Protection against trying to get a reference to a vtable:
|
||||
// vtables do not have an alloc_extra so the call to
|
||||
// `get_alloc_extra` that follows fails.
|
||||
let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
|
||||
if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) {
|
||||
return Ok(Some((alloc_id, orig_tag)));
|
||||
}
|
||||
|
||||
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
|
||||
|
||||
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
|
||||
if base_offset + ptr_size > alloc_size {
|
||||
throw_ub!(PointerOutOfBounds {
|
||||
alloc_id,
|
||||
alloc_size,
|
||||
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
|
||||
ptr_size,
|
||||
msg: CheckInAllocMsg::InboundsTest
|
||||
});
|
||||
}
|
||||
|
||||
trace!(
|
||||
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
|
||||
new_tag,
|
||||
|
@ -206,7 +206,7 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
|
||||
) -> InterpResult<'tcx, Option<Id>> {
|
||||
let this = self.eval_context_mut();
|
||||
let value_place =
|
||||
this.deref_operand_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
|
||||
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
|
||||
|
||||
// Since we are lazy, this update has to be atomic.
|
||||
let (old, success) = this
|
||||
|
@ -715,9 +715,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
|
||||
/// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
|
||||
fn deref_operand_as(
|
||||
fn deref_pointer_as(
|
||||
&self,
|
||||
op: &OpTy<'tcx, Provenance>,
|
||||
op: &impl Readable<'tcx, Provenance>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
@ -746,15 +746,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
}
|
||||
|
||||
/// Calculates the MPlaceTy given the offset and layout of an access on an operand
|
||||
fn deref_operand_and_offset(
|
||||
fn deref_pointer_and_offset(
|
||||
&self,
|
||||
op: &OpTy<'tcx, Provenance>,
|
||||
op: &impl Readable<'tcx, Provenance>,
|
||||
offset: u64,
|
||||
base_layout: TyAndLayout<'tcx>,
|
||||
value_layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
let op_place = this.deref_operand_as(op, base_layout)?;
|
||||
let op_place = this.deref_pointer_as(op, base_layout)?;
|
||||
let offset = Size::from_bytes(offset);
|
||||
|
||||
// Ensure that the access is within bounds.
|
||||
@ -763,28 +763,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
Ok(value_place)
|
||||
}
|
||||
|
||||
fn read_scalar_at_offset(
|
||||
fn deref_pointer_and_read(
|
||||
&self,
|
||||
op: &OpTy<'tcx, Provenance>,
|
||||
op: &impl Readable<'tcx, Provenance>,
|
||||
offset: u64,
|
||||
base_layout: TyAndLayout<'tcx>,
|
||||
value_layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
|
||||
let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
|
||||
this.read_scalar(&value_place)
|
||||
}
|
||||
|
||||
fn write_scalar_at_offset(
|
||||
fn deref_pointer_and_write(
|
||||
&mut self,
|
||||
op: &OpTy<'tcx, Provenance>,
|
||||
op: &impl Readable<'tcx, Provenance>,
|
||||
offset: u64,
|
||||
value: impl Into<Scalar<Provenance>>,
|
||||
base_layout: TyAndLayout<'tcx>,
|
||||
value_layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
let this = self.eval_context_mut();
|
||||
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
|
||||
let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
|
||||
this.write_scalar(value, &value_place)
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
1 => {
|
||||
let [_flags, buf] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||
|
||||
let buf_place = this.deref_operand(buf)?;
|
||||
let buf_place = this.deref_pointer(buf)?;
|
||||
|
||||
let ptr_layout = this.layout_of(ptr_ty)?;
|
||||
|
||||
|
@ -418,9 +418,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
// // First thing: load all the arguments. Details depend on the shim.
|
||||
// let arg1 = this.read_scalar(arg1)?.to_u32()?;
|
||||
// let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly
|
||||
// let arg3 = this.deref_operand_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
|
||||
// let arg3 = this.deref_pointer_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
|
||||
// // through the pointer and supply the type information yourself
|
||||
// let arg4 = this.deref_operand(arg4)?; // when you want to load/store through the pointer and trust
|
||||
// let arg4 = this.deref_pointer(arg4)?; // when you want to load/store through the pointer and trust
|
||||
// // the user-given type (which you shouldn't usually do)
|
||||
//
|
||||
// // ...
|
||||
|
@ -130,7 +130,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let [place] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
|
||||
// Perform atomic load.
|
||||
let val = this.read_scalar_atomic(&place, atomic)?;
|
||||
@ -147,7 +147,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let [place, val] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
|
||||
// Perform regular load.
|
||||
let val = this.read_scalar(val)?;
|
||||
@ -188,7 +188,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let [place, rhs] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
let rhs = this.read_immediate(rhs)?;
|
||||
|
||||
if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() {
|
||||
@ -229,7 +229,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let [place, new] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
let new = this.read_scalar(new)?;
|
||||
|
||||
let old = this.atomic_exchange_scalar(&place, new, atomic)?;
|
||||
@ -248,7 +248,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let [place, expect_old, new] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()`
|
||||
let new = this.read_scalar(new)?;
|
||||
|
||||
|
@ -96,12 +96,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
// Raw memory accesses
|
||||
"volatile_load" => {
|
||||
let [place] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
this.copy_op(&place, dest, /*allow_transmute*/ false)?;
|
||||
}
|
||||
"volatile_store" => {
|
||||
let [place, dest] = check_arg_count(args)?;
|
||||
let place = this.deref_operand(place)?;
|
||||
let place = this.deref_pointer(place)?;
|
||||
this.copy_op(dest, &place, /*allow_transmute*/ false)?;
|
||||
}
|
||||
|
||||
|
@ -534,7 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr)?;
|
||||
let place = this.deref_pointer(&ptr)?;
|
||||
this.read_immediate(&place)?
|
||||
} else {
|
||||
passthru
|
||||
@ -557,7 +557,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
|
||||
|
||||
if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr)?;
|
||||
let place = this.deref_pointer(&ptr)?;
|
||||
this.write_immediate(*value, &place)?;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user