1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
//! Values computed by queries that use MIR.
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::BitMatrix;
use rustc_index::{Idx, IndexVec};
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::abi::{FieldIdx, VariantIdx};
use smallvec::SmallVec;
use std::cell::Cell;
use std::fmt::{self, Debug};
use super::{ConstValue, SourceInfo};
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
/// Unsafe operation outside `unsafe`.
General,
/// Unsafe operation in an `unsafe fn` but outside an `unsafe` block.
/// Has to be handled as a lint for backwards compatibility.
UnsafeFn,
}
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationDetails {
CallToUnsafeFunction,
UseOfInlineAssembly,
InitializingTypeWith,
CastOfPointerToInt,
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
CallToFunctionWith,
}
impl UnsafetyViolationDetails {
pub fn description_and_note(&self) -> (&'static str, &'static str) {
use UnsafetyViolationDetails::*;
match self {
CallToUnsafeFunction => (
"call to unsafe function",
"consult the function's documentation for information on how to avoid undefined \
behavior",
),
UseOfInlineAssembly => (
"use of inline assembly",
"inline assembly is entirely unchecked and can cause undefined behavior",
),
InitializingTypeWith => (
"initializing type with `rustc_layout_scalar_valid_range` attr",
"initializing a layout restricted type's field with a value outside the valid \
range is undefined behavior",
),
CastOfPointerToInt => {
("cast of pointer to int", "casting pointers to integers in constants")
}
UseOfMutableStatic => (
"use of mutable static",
"mutable statics can be mutated by multiple threads: aliasing violations or data \
races will cause undefined behavior",
),
UseOfExternStatic => (
"use of extern static",
"extern statics are not controlled by the Rust type system: invalid data, \
aliasing violations or data races will cause undefined behavior",
),
DerefOfRawPointer => (
"dereference of raw pointer",
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
and cause data races: all of these are undefined behavior",
),
AccessToUnionField => (
"access to union field",
"the field may not be properly initialized: using uninitialized data will cause \
undefined behavior",
),
MutationOfLayoutConstrainedField => (
"mutation of layout constrained field",
"mutating layout constrained fields cannot statically be checked for valid values",
),
BorrowOfLayoutConstrainedField => (
"borrow of layout constrained field with interior mutability",
"references to fields of layout constrained fields lose the constraints. Coupled \
with interior mutability, the field can be changed to invalid values",
),
CallToFunctionWith => (
"call to function with `#[target_feature]`",
"can only be called if the required target features are available",
),
}
}
}
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyViolation {
pub source_info: SourceInfo,
pub lint_root: hir::HirId,
pub kind: UnsafetyViolationKind,
pub details: UnsafetyViolationDetails,
}
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnusedUnsafe {
/// `unsafe` block contains no unsafe operations
/// > ``unnecessary `unsafe` block``
Unused,
/// `unsafe` block nested under another (used) `unsafe` block
/// > ``… because it's nested under this `unsafe` block``
InUnsafeBlock(hir::HirId),
}
#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyCheckResult {
/// Violations that are propagated *upwards* from this function.
pub violations: Vec<UnsafetyViolation>,
/// Used `unsafe` blocks in this function. This is used for the "unused_unsafe" lint.
pub used_unsafe_blocks: UnordSet<hir::HirId>,
/// This is `Some` iff the item is not a closure.
pub unused_unsafes: Option<Vec<(hir::HirId, UnusedUnsafe)>>,
}
rustc_index::newtype_index! {
#[derive(HashStable)]
#[debug_format = "_{}"]
pub struct GeneratorSavedLocal {}
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct GeneratorSavedTy<'tcx> {
pub ty: Ty<'tcx>,
/// Source info corresponding to the local in the original MIR body.
pub source_info: SourceInfo,
/// Whether the local should be ignored for trait bound computations.
pub ignore_for_traits: bool,
}
/// The layout of generator state.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct GeneratorLayout<'tcx> {
/// The type of every local stored inside the generator.
pub field_tys: IndexVec<GeneratorSavedLocal, GeneratorSavedTy<'tcx>>,
/// The name for debuginfo.
pub field_names: IndexVec<GeneratorSavedLocal, Option<Symbol>>,
/// Which of the above fields are in each variant. Note that one field may
/// be stored in multiple variants.
pub variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, GeneratorSavedLocal>>,
/// The source that led to each variant being created (usually, a yield or
/// await).
pub variant_source_info: IndexVec<VariantIdx, SourceInfo>,
/// Which saved locals are storage-live at the same time. Locals that do not
/// have conflicts with each other are allowed to overlap in the computed
/// layout.
#[type_foldable(identity)]
#[type_visitable(ignore)]
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
}
impl Debug for GeneratorLayout<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Prints an iterator of (key, value) tuples as a map.
struct MapPrinter<'a, K, V>(Cell<Option<Box<dyn Iterator<Item = (K, V)> + 'a>>>);
impl<'a, K, V> MapPrinter<'a, K, V> {
fn new(iter: impl Iterator<Item = (K, V)> + 'a) -> Self {
Self(Cell::new(Some(Box::new(iter))))
}
}
impl<'a, K: Debug, V: Debug> Debug for MapPrinter<'a, K, V> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_map().entries(self.0.take().unwrap()).finish()
}
}
/// Prints the generator variant name.
struct GenVariantPrinter(VariantIdx);
impl From<VariantIdx> for GenVariantPrinter {
fn from(idx: VariantIdx) -> Self {
GenVariantPrinter(idx)
}
}
impl Debug for GenVariantPrinter {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let variant_name = ty::GeneratorArgs::variant_name(self.0);
if fmt.alternate() {
write!(fmt, "{:9}({:?})", variant_name, self.0)
} else {
write!(fmt, "{variant_name}")
}
}
}
/// Forces its contents to print in regular mode instead of alternate mode.
struct OneLinePrinter<T>(T);
impl<T: Debug> Debug for OneLinePrinter<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{:?}", self.0)
}
}
fmt.debug_struct("GeneratorLayout")
.field("field_tys", &MapPrinter::new(self.field_tys.iter_enumerated()))
.field(
"variant_fields",
&MapPrinter::new(
self.variant_fields
.iter_enumerated()
.map(|(k, v)| (GenVariantPrinter(k), OneLinePrinter(v))),
),
)
.field("storage_conflicts", &self.storage_conflicts)
.finish()
}
}
#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckResults`, this has
/// unerased regions.
pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[FieldIdx; 8]>,
pub tainted_by_errors: Option<ErrorGuaranteed>,
}
/// The result of the `mir_const_qualif` query.
///
/// Each field (except `error_occurred`) corresponds to an implementer of the `Qualif` trait in
/// `rustc_const_eval/src/transform/check_consts/qualifs.rs`. See that file for more information on each
/// `Qualif`.
#[derive(Clone, Copy, Debug, Default, TyEncodable, TyDecodable, HashStable)]
pub struct ConstQualifs {
pub has_mut_interior: bool,
pub needs_drop: bool,
pub needs_non_const_drop: bool,
pub custom_eq: bool,
pub tainted_by_errors: Option<ErrorGuaranteed>,
}
/// After we borrow check a closure, we are left with various
/// requirements that we have inferred between the free regions that
/// appear in the closure's signature or on its field types. These
/// requirements are then verified and proved by the closure's
/// creating function. This struct encodes those requirements.
///
/// The requirements are listed as being between various `RegionVid`. The 0th
/// region refers to `'static`; subsequent region vids refer to the free
/// regions that appear in the closure (or generator's) type, in order of
/// appearance. (This numbering is actually defined by the `UniversalRegions`
/// struct in the NLL region checker. See for example
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
/// closure's signature and captures are erased.
///
/// Example: If type check produces a closure with the closure args:
///
/// ```text
/// ClosureArgs = [
/// 'a, // From the parent.
/// 'b,
/// i8, // the "closure kind"
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
/// &'<erased> String, // some upvar
/// ]
/// ```
///
/// We would "renumber" each free region to a unique vid, as follows:
///
/// ```text
/// ClosureArgs = [
/// '1, // From the parent.
/// '2,
/// i8, // the "closure kind"
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
/// &'4 String, // some upvar
/// ]
/// ```
///
/// Now the code might impose a requirement like `'1: '2`. When an
/// instance of the closure is created, the corresponding free regions
/// can be extracted from its type and constrained to have the given
/// outlives relationship.
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct ClosureRegionRequirements<'tcx> {
/// The number of external regions defined on the closure. In our
/// example above, it would be 3 -- one for `'static`, then `'1`
/// and `'2`. This is just used for a sanity check later on, to
/// make sure that the number of regions we see at the callsite
/// matches.
pub num_external_vids: usize,
/// Requirements between the various free regions defined in
/// indices.
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
}
/// Indicates an outlives-constraint between a type or between two
/// free regions declared on the closure.
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct ClosureOutlivesRequirement<'tcx> {
// This region or type ...
pub subject: ClosureOutlivesSubject<'tcx>,
// ... must outlive this one.
pub outlived_free_region: ty::RegionVid,
// If not, report an error here ...
pub blame_span: Span,
// ... due to this reason.
pub category: ConstraintCategory<'tcx>,
}
// Make sure this enum doesn't unintentionally grow
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
/// Outlives-constraints can be categorized to determine whether and why they
/// are interesting (for error reporting). Order of variants indicates sort
/// order of the category, thereby influencing diagnostic output.
///
/// See also `rustc_const_eval::borrow_check::constraints`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ConstraintCategory<'tcx> {
Return(ReturnConstraint),
Yield,
UseAsConst,
UseAsStatic,
TypeAnnotation,
Cast,
/// A constraint that came from checking the body of a closure.
///
/// We try to get the category that the closure used when reporting this.
ClosureBounds,
/// Contains the function type if available.
CallArgument(Option<Ty<'tcx>>),
CopyBound,
SizedBound,
Assignment,
/// A constraint that came from a usage of a variable (e.g. in an ADT expression
/// like `Foo { field: my_val }`)
Usage,
OpaqueType,
ClosureUpvar(FieldIdx),
/// A constraint from a user-written predicate
/// with the provided span, written on the item
/// with the given `DefId`
Predicate(Span),
/// A "boring" constraint (caused by the given location) is one that
/// the user probably doesn't want to see described in diagnostics,
/// because it is kind of an artifact of the type system setup.
Boring,
// Boring and applicable everywhere.
BoringNoLocation,
/// A constraint that doesn't correspond to anything the user sees.
Internal,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ReturnConstraint {
Normal,
ClosureUpvar(FieldIdx),
}
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum ClosureOutlivesSubject<'tcx> {
/// Subject is a type, typically a type parameter, but could also
/// be a projection. Indicates a requirement like `T: 'a` being
/// passed to the caller, where the type here is `T`.
Ty(ClosureOutlivesSubjectTy<'tcx>),
/// Subject is a free region from the closure. Indicates a requirement
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
Region(ty::RegionVid),
}
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
///
/// This abstraction is necessary because the type may include `ReVar` regions,
/// which is what we use internally within NLL code, and they can't be used in
/// a query response.
///
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
/// type is not recognized as a binder for late-bound region.
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub struct ClosureOutlivesSubjectTy<'tcx> {
inner: Ty<'tcx>,
}
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
/// All regions of `ty` must be of kind `ReVar` and must represent
/// universal regions *external* to the closure.
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
ty::ReVar(vid) => {
let br = ty::BoundRegion { var: ty::BoundVar::new(vid.index()), kind: ty::BrAnon };
ty::Region::new_late_bound(tcx, depth, br)
}
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
});
Self { inner }
}
pub fn instantiate(
self,
tcx: TyCtxt<'tcx>,
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
) -> Ty<'tcx> {
tcx.fold_regions(self.inner, |r, depth| match r.kind() {
ty::ReLateBound(debruijn, br) => {
debug_assert_eq!(debruijn, depth);
map(ty::RegionVid::new(br.var.index()))
}
_ => bug!("unexpected region {r:?}"),
})
}
}
/// The constituent parts of a mir constant of kind ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
}
/// Coverage information summarized from a MIR if instrumented for source code coverage (see
/// compiler option `-Cinstrument-coverage`). This information is generated by the
/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
pub struct CoverageInfo {
/// The total number of coverage region counters added to the MIR `Body`.
pub num_counters: u32,
/// The total number of coverage region counter expressions added to the MIR `Body`.
pub num_expressions: u32,
}