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