about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-31 06:22:57 +0000
committerbors <bors@rust-lang.org>2024-10-31 06:22:57 +0000
commit4d296eabe4c5cfbce9bb68e6221bca2165aae97b (patch)
tree9feba64683f870341913af6122d2fa218e588f97
parentc8b83785dccdd22345d193fed7431ce44074007b (diff)
parent49a76c14c447acc032d4a5358a668a13160067f6 (diff)
downloadrust-4d296eabe4c5cfbce9bb68e6221bca2165aae97b.tar.gz
rust-4d296eabe4c5cfbce9bb68e6221bca2165aae97b.zip
Auto merge of #132384 - matthiaskrgr:rollup-0ze5wc4, r=matthiaskrgr
Rollup of 4 pull requests

Successful merges:

 - #132347 (Remove `ValueAnalysis` and `ValueAnalysisWrapper`.)
 - #132365 (pass `RUSTC_HOST_FLAGS` at once without the for loop)
 - #132366 (Do not enforce `~const` constness effects in typeck if `rustc_do_not_const_check`)
 - #132376 (Annotate `input` reference tests)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs416
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs339
-rw-r--r--src/bootstrap/src/bin/rustc.rs4
-rw-r--r--tests/ui/json/json-bom-plus-crlf-multifile.rs2
-rw-r--r--tests/ui/json/json-bom-plus-crlf.rs2
-rw-r--r--tests/ui/json/json-bom-plus-crlf.stderr8
-rw-r--r--tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs1
-rw-r--r--tests/ui/macros/not-utf8.rs2
-rw-r--r--tests/ui/macros/not-utf8.stderr2
-rw-r--r--tests/ui/parser/shebang/issue-71471-ignore-tidy.rs2
-rw-r--r--tests/ui/parser/shebang/multiline-attrib.rs1
-rw-r--r--tests/ui/parser/shebang/regular-attrib.rs1
-rw-r--r--tests/ui/parser/shebang/shebang-and-attrib.rs1
-rw-r--r--tests/ui/parser/shebang/shebang-comment.rs1
-rw-r--r--tests/ui/parser/shebang/shebang-doc-comment.rs2
-rw-r--r--tests/ui/parser/shebang/shebang-empty.rs1
-rw-r--r--tests/ui/parser/shebang/shebang-must-start-file.rs2
-rw-r--r--tests/ui/parser/shebang/shebang-space.rs1
-rw-r--r--tests/ui/parser/shebang/sneaky-attrib.rs1
-rw-r--r--tests/ui/parser/shebang/valid-shebang.rs1
-rw-r--r--tests/ui/parser/utf16-be-without-bom.rsbin127 -> 162 bytes
-rw-r--r--tests/ui/parser/utf16-be-without-bom.stderr28
-rw-r--r--tests/ui/parser/utf16-le-without-bom.rsbin128 -> 163 bytes
-rw-r--r--tests/ui/parser/utf16-le-without-bom.stderr28
-rw-r--r--tests/ui/traits/const-traits/do-not-const-check.rs3
-rw-r--r--tests/ui/traits/const-traits/do-not-const-check.stderr11
-rw-r--r--tests/ui/utf8-bom.rs1
28 files changed, 355 insertions, 511 deletions
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 93d50bf3d7b..6eb6792a119 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -851,6 +851,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
+        // If we have `rustc_do_not_const_check`, do not check `~const` bounds.
+        if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) {
+            return;
+        }
+
         let host = match self.tcx.hir().body_const_context(self.body_id) {
             Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {
                 ty::BoundConstness::Const
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 80151b8ba2d..af2d514fc76 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -1,38 +1,3 @@
-//! This module provides a framework on top of the normal MIR dataflow framework to simplify the
-//! implementation of analyses that track information about the values stored in certain places.
-//! We are using the term "place" here to refer to a `mir::Place` (a place expression) instead of
-//! an `interpret::Place` (a memory location).
-//!
-//! The default methods of [`ValueAnalysis`] (prefixed with `super_` instead of `handle_`)
-//! provide some behavior that should be valid for all abstract domains that are based only on the
-//! value stored in a certain place. On top of these default rules, an implementation should
-//! override some of the `handle_` methods. For an example, see `ConstAnalysis`.
-//!
-//! An implementation must also provide a [`Map`]. Before the analysis begins, all places that
-//! should be tracked during the analysis must be registered. During the analysis, no new places
-//! can be registered. The [`State`] can be queried to retrieve the abstract value stored for a
-//! certain place by passing the map.
-//!
-//! This framework is currently experimental. Originally, it supported shared references and enum
-//! variants. However, it was discovered that both of these were unsound, and especially references
-//! had subtle but serious issues. In the future, they could be added back in, but we should clarify
-//! the rules for optimizations that rely on the aliasing model first.
-//!
-//!
-//! # Notes
-//!
-//! - The bottom state denotes uninitialized memory. Because we are only doing a sound approximation
-//! of the actual execution, we can also use this state for places where access would be UB.
-//!
-//! - The assignment logic in `State::insert_place_idx` assumes that the places are non-overlapping,
-//! or identical. Note that this refers to place expressions, not memory locations.
-//!
-//! - Currently, places that have their reference taken cannot be tracked. Although this would be
-//! possible, it has to rely on some aliasing model, which we are not ready to commit to yet.
-//! Because of that, we can assume that the only way to change the value behind a tracked place is
-//! by direct assignment.
-
-use std::assert_matches::assert_matches;
 use std::fmt::{Debug, Formatter};
 use std::ops::Range;
 
@@ -42,359 +7,14 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::bug;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use tracing::debug;
 
-use crate::fmt::DebugWithContext;
+use crate::JoinSemiLattice;
 use crate::lattice::{HasBottom, HasTop};
-use crate::{Analysis, JoinSemiLattice, SwitchIntEdgeEffects};
-
-pub trait ValueAnalysis<'tcx> {
-    /// For each place of interest, the analysis tracks a value of the given type.
-    type Value: Clone + JoinSemiLattice + HasBottom + HasTop + Debug;
-
-    const NAME: &'static str;
-
-    fn map(&self) -> &Map<'tcx>;
-
-    fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) {
-        self.super_statement(statement, state)
-    }
-
-    fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) {
-        match &statement.kind {
-            StatementKind::Assign(box (place, rvalue)) => {
-                self.handle_assign(*place, rvalue, state);
-            }
-            StatementKind::SetDiscriminant { box place, variant_index } => {
-                self.handle_set_discriminant(*place, *variant_index, state);
-            }
-            StatementKind::Intrinsic(box intrinsic) => {
-                self.handle_intrinsic(intrinsic, state);
-            }
-            StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
-                // StorageLive leaves the local in an uninitialized state.
-                // StorageDead makes it UB to access the local afterwards.
-                state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM);
-            }
-            StatementKind::Deinit(box place) => {
-                // Deinit makes the place uninitialized.
-                state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
-            }
-            StatementKind::Retag(..) => {
-                // We don't track references.
-            }
-            StatementKind::ConstEvalCounter
-            | StatementKind::Nop
-            | StatementKind::FakeRead(..)
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..) => (),
-        }
-    }
-
-    fn handle_set_discriminant(
-        &self,
-        place: Place<'tcx>,
-        variant_index: VariantIdx,
-        state: &mut State<Self::Value>,
-    ) {
-        self.super_set_discriminant(place, variant_index, state)
-    }
-
-    fn super_set_discriminant(
-        &self,
-        place: Place<'tcx>,
-        _variant_index: VariantIdx,
-        state: &mut State<Self::Value>,
-    ) {
-        state.flood_discr(place.as_ref(), self.map());
-    }
-
-    fn handle_intrinsic(
-        &self,
-        intrinsic: &NonDivergingIntrinsic<'tcx>,
-        state: &mut State<Self::Value>,
-    ) {
-        self.super_intrinsic(intrinsic, state);
-    }
-
-    fn super_intrinsic(
-        &self,
-        intrinsic: &NonDivergingIntrinsic<'tcx>,
-        _state: &mut State<Self::Value>,
-    ) {
-        match intrinsic {
-            NonDivergingIntrinsic::Assume(..) => {
-                // Could use this, but ignoring it is sound.
-            }
-            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
-                dst: _,
-                src: _,
-                count: _,
-            }) => {
-                // This statement represents `*dst = *src`, `count` times.
-            }
-        }
-    }
-
-    fn handle_assign(
-        &self,
-        target: Place<'tcx>,
-        rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
-    ) {
-        self.super_assign(target, rvalue, state)
-    }
-
-    fn super_assign(
-        &self,
-        target: Place<'tcx>,
-        rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
-    ) {
-        let result = self.handle_rvalue(rvalue, state);
-        state.assign(target.as_ref(), result, self.map());
-    }
-
-    fn handle_rvalue(
-        &self,
-        rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> ValueOrPlace<Self::Value> {
-        self.super_rvalue(rvalue, state)
-    }
-
-    fn super_rvalue(
-        &self,
-        rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> ValueOrPlace<Self::Value> {
-        match rvalue {
-            Rvalue::Use(operand) => self.handle_operand(operand, state),
-            Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state),
-            Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
-                // We don't track such places.
-                ValueOrPlace::TOP
-            }
-            Rvalue::Repeat(..)
-            | Rvalue::ThreadLocalRef(..)
-            | Rvalue::Len(..)
-            | Rvalue::Cast(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::Aggregate(..)
-            | Rvalue::ShallowInitBox(..) => {
-                // No modification is possible through these r-values.
-                ValueOrPlace::TOP
-            }
-        }
-    }
-
-    fn handle_operand(
-        &self,
-        operand: &Operand<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> ValueOrPlace<Self::Value> {
-        self.super_operand(operand, state)
-    }
-
-    fn super_operand(
-        &self,
-        operand: &Operand<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> ValueOrPlace<Self::Value> {
-        match operand {
-            Operand::Constant(box constant) => {
-                ValueOrPlace::Value(self.handle_constant(constant, state))
-            }
-            Operand::Copy(place) | Operand::Move(place) => {
-                // On move, we would ideally flood the place with bottom. But with the current
-                // framework this is not possible (similar to `InterpCx::eval_operand`).
-                self.map()
-                    .find(place.as_ref())
-                    .map(ValueOrPlace::Place)
-                    .unwrap_or(ValueOrPlace::TOP)
-            }
-        }
-    }
-
-    fn handle_constant(
-        &self,
-        constant: &ConstOperand<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> Self::Value {
-        self.super_constant(constant, state)
-    }
-
-    fn super_constant(
-        &self,
-        _constant: &ConstOperand<'tcx>,
-        _state: &mut State<Self::Value>,
-    ) -> Self::Value {
-        Self::Value::TOP
-    }
-
-    /// The effect of a successful function call return should not be
-    /// applied here, see [`Analysis::apply_terminator_effect`].
-    fn handle_terminator<'mir>(
-        &self,
-        terminator: &'mir Terminator<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        self.super_terminator(terminator, state)
-    }
-
-    fn super_terminator<'mir>(
-        &self,
-        terminator: &'mir Terminator<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        match &terminator.kind {
-            TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
-                // Effect is applied by `handle_call_return`.
-            }
-            TerminatorKind::Drop { place, .. } => {
-                state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
-            }
-            TerminatorKind::Yield { .. } => {
-                // They would have an effect, but are not allowed in this phase.
-                bug!("encountered disallowed terminator");
-            }
-            TerminatorKind::SwitchInt { discr, targets } => {
-                return self.handle_switch_int(discr, targets, state);
-            }
-            TerminatorKind::TailCall { .. } => {
-                // FIXME(explicit_tail_calls): determine if we need to do something here (probably not)
-            }
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::UnwindResume
-            | TerminatorKind::UnwindTerminate(_)
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::CoroutineDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                // These terminators have no effect on the analysis.
-            }
-        }
-        terminator.edges()
-    }
-
-    fn handle_call_return(
-        &self,
-        return_places: CallReturnPlaces<'_, 'tcx>,
-        state: &mut State<Self::Value>,
-    ) {
-        self.super_call_return(return_places, state)
-    }
-
-    fn super_call_return(
-        &self,
-        return_places: CallReturnPlaces<'_, 'tcx>,
-        state: &mut State<Self::Value>,
-    ) {
-        return_places.for_each(|place| {
-            state.flood(place.as_ref(), self.map());
-        })
-    }
-
-    fn handle_switch_int<'mir>(
-        &self,
-        discr: &'mir Operand<'tcx>,
-        targets: &'mir SwitchTargets,
-        state: &mut State<Self::Value>,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        self.super_switch_int(discr, targets, state)
-    }
-
-    fn super_switch_int<'mir>(
-        &self,
-        discr: &'mir Operand<'tcx>,
-        targets: &'mir SwitchTargets,
-        _state: &mut State<Self::Value>,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        TerminatorEdges::SwitchInt { discr, targets }
-    }
-
-    fn wrap(self) -> ValueAnalysisWrapper<Self>
-    where
-        Self: Sized,
-    {
-        ValueAnalysisWrapper(self)
-    }
-}
-
-pub struct ValueAnalysisWrapper<T>(pub T);
-
-impl<'tcx, T: ValueAnalysis<'tcx>> Analysis<'tcx> for ValueAnalysisWrapper<T> {
-    type Domain = State<T::Value>;
-
-    const NAME: &'static str = T::NAME;
-
-    fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
-        State::Unreachable
-    }
-
-    fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
-        // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
-        assert_matches!(state, State::Unreachable);
-        *state = State::new_reachable();
-        for arg in body.args_iter() {
-            state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
-        }
-    }
-
-    fn apply_statement_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        statement: &Statement<'tcx>,
-        _location: Location,
-    ) {
-        if state.is_reachable() {
-            self.0.handle_statement(statement, state);
-        }
-    }
-
-    fn apply_terminator_effect<'mir>(
-        &mut self,
-        state: &mut Self::Domain,
-        terminator: &'mir Terminator<'tcx>,
-        _location: Location,
-    ) -> TerminatorEdges<'mir, 'tcx> {
-        if state.is_reachable() {
-            self.0.handle_terminator(terminator, state)
-        } else {
-            TerminatorEdges::None
-        }
-    }
-
-    fn apply_call_return_effect(
-        &mut self,
-        state: &mut Self::Domain,
-        _block: BasicBlock,
-        return_places: CallReturnPlaces<'_, 'tcx>,
-    ) {
-        if state.is_reachable() {
-            self.0.handle_call_return(return_places, state)
-        }
-    }
-
-    fn apply_switch_int_edge_effects(
-        &mut self,
-        _block: BasicBlock,
-        _discr: &Operand<'tcx>,
-        _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
-    ) {
-    }
-}
 
 rustc_index::newtype_index!(
     /// This index uniquely identifies a place.
@@ -464,7 +84,7 @@ impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> {
     }
 }
 
-/// The dataflow state for an instance of [`ValueAnalysis`].
+/// Dataflow state.
 ///
 /// Every instance specifies a lattice that represents the possible values of a single tracked
 /// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an
@@ -514,7 +134,7 @@ impl<V: Clone + HasBottom> State<V> {
         }
     }
 
-    fn is_reachable(&self) -> bool {
+    pub fn is_reachable(&self) -> bool {
         matches!(self, State::Reachable(_))
     }
 
@@ -1317,34 +937,6 @@ pub fn excluded_locals(body: &Body<'_>) -> BitSet<Local> {
     collector.result
 }
 
-/// This is used to visualize the dataflow analysis.
-impl<'tcx, T> DebugWithContext<ValueAnalysisWrapper<T>> for State<T::Value>
-where
-    T: ValueAnalysis<'tcx>,
-    T::Value: Debug,
-{
-    fn fmt_with(&self, ctxt: &ValueAnalysisWrapper<T>, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match self {
-            State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f),
-            State::Unreachable => write!(f, "unreachable"),
-        }
-    }
-
-    fn fmt_diff_with(
-        &self,
-        old: &Self,
-        ctxt: &ValueAnalysisWrapper<T>,
-        f: &mut Formatter<'_>,
-    ) -> std::fmt::Result {
-        match (self, old) {
-            (State::Reachable(this), State::Reachable(old)) => {
-                debug_with_context(this, Some(old), ctxt.0.map(), f)
-            }
-            _ => Ok(()), // Consider printing something here.
-        }
-    }
-}
-
 fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
     place: PlaceIndex,
     place_str: &str,
@@ -1391,7 +983,7 @@ fn debug_with_context_rec<V: Debug + Eq + HasBottom>(
     Ok(())
 }
 
-fn debug_with_context<V: Debug + Eq + HasBottom>(
+pub fn debug_with_context<V: Debug + Eq + HasBottom>(
     new: &StateData<V>,
     old: Option<&StateData<V>>,
     map: &Map<'_>,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index c084b20772f..dd85d06540d 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,6 +2,9 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
+use std::assert_matches::assert_matches;
+use std::fmt::Formatter;
+
 use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx};
 use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str};
 use rustc_const_eval::interpret::{
@@ -15,9 +18,10 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_mir_dataflow::lattice::FlatSet;
+use rustc_mir_dataflow::fmt::DebugWithContext;
+use rustc_mir_dataflow::lattice::{FlatSet, HasBottom};
 use rustc_mir_dataflow::value_analysis::{
-    Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
+    Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context,
 };
 use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
 use rustc_span::DUMMY_SP;
@@ -58,8 +62,8 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
 
         // Perform the actual dataflow analysis.
         let analysis = ConstAnalysis::new(tcx, body, map);
-        let mut results = debug_span!("analyze")
-            .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None));
+        let mut results =
+            debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None));
 
         // Collect results and patch the body afterwards.
         let mut visitor = Collector::new(tcx, &body.local_decls);
@@ -69,6 +73,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
     }
 }
 
+// Note: Currently, places that have their reference taken cannot be tracked. Although this would
+// be possible, it has to rely on some aliasing model, which we are not ready to commit to yet.
+// Because of that, we can assume that the only way to change the value behind a tracked place is
+// by direct assignment.
 struct ConstAnalysis<'a, 'tcx> {
     map: Map<'tcx>,
     tcx: TyCtxt<'tcx>,
@@ -77,20 +85,198 @@ struct ConstAnalysis<'a, 'tcx> {
     param_env: ty::ParamEnv<'tcx>,
 }
 
-impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
-    type Value = FlatSet<Scalar>;
+impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
+    type Domain = State<FlatSet<Scalar>>;
 
     const NAME: &'static str = "ConstAnalysis";
 
-    fn map(&self) -> &Map<'tcx> {
-        &self.map
+    // The bottom state denotes uninitialized memory. Because we are only doing a sound
+    // approximation of the actual execution, we can also use this state for places where access
+    // would be UB.
+    fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain {
+        State::Unreachable
+    }
+
+    fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
+        // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
+        assert_matches!(state, State::Unreachable);
+        *state = State::new_reachable();
+        for arg in body.args_iter() {
+            state.flood(PlaceRef { local: arg, projection: &[] }, &self.map);
+        }
+    }
+
+    fn apply_statement_effect(
+        &mut self,
+        state: &mut Self::Domain,
+        statement: &Statement<'tcx>,
+        _location: Location,
+    ) {
+        if state.is_reachable() {
+            self.handle_statement(statement, state);
+        }
+    }
+
+    fn apply_terminator_effect<'mir>(
+        &mut self,
+        state: &mut Self::Domain,
+        terminator: &'mir Terminator<'tcx>,
+        _location: Location,
+    ) -> TerminatorEdges<'mir, 'tcx> {
+        if state.is_reachable() {
+            self.handle_terminator(terminator, state)
+        } else {
+            TerminatorEdges::None
+        }
+    }
+
+    fn apply_call_return_effect(
+        &mut self,
+        state: &mut Self::Domain,
+        _block: BasicBlock,
+        return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+        if state.is_reachable() {
+            self.handle_call_return(return_places, state)
+        }
+    }
+}
+
+impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self {
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+        Self {
+            map,
+            tcx,
+            local_decls: &body.local_decls,
+            ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
+            param_env,
+        }
+    }
+
+    fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<FlatSet<Scalar>>) {
+        match &statement.kind {
+            StatementKind::Assign(box (place, rvalue)) => {
+                self.handle_assign(*place, rvalue, state);
+            }
+            StatementKind::SetDiscriminant { box place, variant_index } => {
+                self.handle_set_discriminant(*place, *variant_index, state);
+            }
+            StatementKind::Intrinsic(box intrinsic) => {
+                self.handle_intrinsic(intrinsic);
+            }
+            StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
+                // StorageLive leaves the local in an uninitialized state.
+                // StorageDead makes it UB to access the local afterwards.
+                state.flood_with(
+                    Place::from(*local).as_ref(),
+                    &self.map,
+                    FlatSet::<Scalar>::BOTTOM,
+                );
+            }
+            StatementKind::Deinit(box place) => {
+                // Deinit makes the place uninitialized.
+                state.flood_with(place.as_ref(), &self.map, FlatSet::<Scalar>::BOTTOM);
+            }
+            StatementKind::Retag(..) => {
+                // We don't track references.
+            }
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
+            | StatementKind::FakeRead(..)
+            | StatementKind::PlaceMention(..)
+            | StatementKind::Coverage(..)
+            | StatementKind::AscribeUserType(..) => (),
+        }
+    }
+
+    fn handle_intrinsic(&self, intrinsic: &NonDivergingIntrinsic<'tcx>) {
+        match intrinsic {
+            NonDivergingIntrinsic::Assume(..) => {
+                // Could use this, but ignoring it is sound.
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+                dst: _,
+                src: _,
+                count: _,
+            }) => {
+                // This statement represents `*dst = *src`, `count` times.
+            }
+        }
+    }
+
+    fn handle_operand(
+        &self,
+        operand: &Operand<'tcx>,
+        state: &mut State<FlatSet<Scalar>>,
+    ) -> ValueOrPlace<FlatSet<Scalar>> {
+        match operand {
+            Operand::Constant(box constant) => {
+                ValueOrPlace::Value(self.handle_constant(constant, state))
+            }
+            Operand::Copy(place) | Operand::Move(place) => {
+                // On move, we would ideally flood the place with bottom. But with the current
+                // framework this is not possible (similar to `InterpCx::eval_operand`).
+                self.map.find(place.as_ref()).map(ValueOrPlace::Place).unwrap_or(ValueOrPlace::TOP)
+            }
+        }
+    }
+
+    /// The effect of a successful function call return should not be
+    /// applied here, see [`Analysis::apply_terminator_effect`].
+    fn handle_terminator<'mir>(
+        &self,
+        terminator: &'mir Terminator<'tcx>,
+        state: &mut State<FlatSet<Scalar>>,
+    ) -> TerminatorEdges<'mir, 'tcx> {
+        match &terminator.kind {
+            TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
+                // Effect is applied by `handle_call_return`.
+            }
+            TerminatorKind::Drop { place, .. } => {
+                state.flood_with(place.as_ref(), &self.map, FlatSet::<Scalar>::BOTTOM);
+            }
+            TerminatorKind::Yield { .. } => {
+                // They would have an effect, but are not allowed in this phase.
+                bug!("encountered disallowed terminator");
+            }
+            TerminatorKind::SwitchInt { discr, targets } => {
+                return self.handle_switch_int(discr, targets, state);
+            }
+            TerminatorKind::TailCall { .. } => {
+                // FIXME(explicit_tail_calls): determine if we need to do something here (probably
+                // not)
+            }
+            TerminatorKind::Goto { .. }
+            | TerminatorKind::UnwindResume
+            | TerminatorKind::UnwindTerminate(_)
+            | TerminatorKind::Return
+            | TerminatorKind::Unreachable
+            | TerminatorKind::Assert { .. }
+            | TerminatorKind::CoroutineDrop
+            | TerminatorKind::FalseEdge { .. }
+            | TerminatorKind::FalseUnwind { .. } => {
+                // These terminators have no effect on the analysis.
+            }
+        }
+        terminator.edges()
+    }
+
+    fn handle_call_return(
+        &self,
+        return_places: CallReturnPlaces<'_, 'tcx>,
+        state: &mut State<FlatSet<Scalar>>,
+    ) {
+        return_places.for_each(|place| {
+            state.flood(place.as_ref(), &self.map);
+        })
     }
 
     fn handle_set_discriminant(
         &self,
         place: Place<'tcx>,
         variant_index: VariantIdx,
-        state: &mut State<Self::Value>,
+        state: &mut State<FlatSet<Scalar>>,
     ) {
         state.flood_discr(place.as_ref(), &self.map);
         if self.map.find_discr(place.as_ref()).is_some() {
@@ -109,17 +295,17 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         &self,
         target: Place<'tcx>,
         rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
+        state: &mut State<FlatSet<Scalar>>,
     ) {
         match rvalue {
             Rvalue::Use(operand) => {
-                state.flood(target.as_ref(), self.map());
+                state.flood(target.as_ref(), &self.map);
                 if let Some(target) = self.map.find(target.as_ref()) {
                     self.assign_operand(state, target, operand);
                 }
             }
             Rvalue::CopyForDeref(rhs) => {
-                state.flood(target.as_ref(), self.map());
+                state.flood(target.as_ref(), &self.map);
                 if let Some(target) = self.map.find(target.as_ref()) {
                     self.assign_operand(state, target, &Operand::Copy(*rhs));
                 }
@@ -127,9 +313,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             Rvalue::Aggregate(kind, operands) => {
                 // If we assign `target = Enum::Variant#0(operand)`,
                 // we must make sure that all `target as Variant#i` are `Top`.
-                state.flood(target.as_ref(), self.map());
+                state.flood(target.as_ref(), &self.map);
 
-                let Some(target_idx) = self.map().find(target.as_ref()) else { return };
+                let Some(target_idx) = self.map.find(target.as_ref()) else { return };
 
                 let (variant_target, variant_index) = match **kind {
                     AggregateKind::Tuple | AggregateKind::Closure(..) => (Some(target_idx), None),
@@ -148,14 +334,14 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 if let Some(variant_target_idx) = variant_target {
                     for (field_index, operand) in operands.iter_enumerated() {
                         if let Some(field) =
-                            self.map().apply(variant_target_idx, TrackElem::Field(field_index))
+                            self.map.apply(variant_target_idx, TrackElem::Field(field_index))
                         {
                             self.assign_operand(state, field, operand);
                         }
                     }
                 }
                 if let Some(variant_index) = variant_index
-                    && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant)
+                    && let Some(discr_idx) = self.map.apply(target_idx, TrackElem::Discriminant)
                 {
                     // We are assigning the discriminant as part of an aggregate.
                     // This discriminant can only alias a variant field's value if the operand
@@ -170,23 +356,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             }
             Rvalue::BinaryOp(op, box (left, right)) if op.is_overflowing() => {
                 // Flood everything now, so we can use `insert_value_idx` directly later.
-                state.flood(target.as_ref(), self.map());
+                state.flood(target.as_ref(), &self.map);
 
-                let Some(target) = self.map().find(target.as_ref()) else { return };
+                let Some(target) = self.map.find(target.as_ref()) else { return };
 
-                let value_target = self.map().apply(target, TrackElem::Field(0_u32.into()));
-                let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into()));
+                let value_target = self.map.apply(target, TrackElem::Field(0_u32.into()));
+                let overflow_target = self.map.apply(target, TrackElem::Field(1_u32.into()));
 
                 if value_target.is_some() || overflow_target.is_some() {
                     let (val, overflow) = self.binary_op(state, *op, left, right);
 
                     if let Some(value_target) = value_target {
                         // We have flooded `target` earlier.
-                        state.insert_value_idx(value_target, val, self.map());
+                        state.insert_value_idx(value_target, val, &self.map);
                     }
                     if let Some(overflow_target) = overflow_target {
                         // We have flooded `target` earlier.
-                        state.insert_value_idx(overflow_target, overflow, self.map());
+                        state.insert_value_idx(overflow_target, overflow, &self.map);
                     }
                 }
             }
@@ -196,27 +382,30 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 _,
             ) => {
                 let pointer = self.handle_operand(operand, state);
-                state.assign(target.as_ref(), pointer, self.map());
+                state.assign(target.as_ref(), pointer, &self.map);
 
-                if let Some(target_len) = self.map().find_len(target.as_ref())
+                if let Some(target_len) = self.map.find_len(target.as_ref())
                     && let operand_ty = operand.ty(self.local_decls, self.tcx)
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
                     && let ty::Array(_, len) = operand_ty.kind()
                     && let Some(len) = Const::Ty(self.tcx.types.usize, *len)
                         .try_eval_scalar_int(self.tcx, self.param_env)
                 {
-                    state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
+                    state.insert_value_idx(target_len, FlatSet::Elem(len.into()), &self.map);
                 }
             }
-            _ => self.super_assign(target, rvalue, state),
+            _ => {
+                let result = self.handle_rvalue(rvalue, state);
+                state.assign(target.as_ref(), result, &self.map);
+            }
         }
     }
 
     fn handle_rvalue(
         &self,
         rvalue: &Rvalue<'tcx>,
-        state: &mut State<Self::Value>,
-    ) -> ValueOrPlace<Self::Value> {
+        state: &mut State<FlatSet<Scalar>>,
+    ) -> ValueOrPlace<FlatSet<Scalar>> {
         let val = match rvalue {
             Rvalue::Len(place) => {
                 let place_ty = place.ty(self.local_decls, self.tcx);
@@ -225,7 +414,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                         .try_eval_scalar(self.tcx, self.param_env)
                         .map_or(FlatSet::Top, FlatSet::Elem)
                 } else if let [ProjectionElem::Deref] = place.projection[..] {
-                    state.get_len(place.local.into(), self.map())
+                    state.get_len(place.local.into(), &self.map)
                 } else {
                     FlatSet::Top
                 }
@@ -296,8 +485,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
                 };
                 FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx))
             }
-            Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()),
-            _ => return self.super_rvalue(rvalue, state),
+            Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
+            Rvalue::Use(operand) => return self.handle_operand(operand, state),
+            Rvalue::CopyForDeref(place) => {
+                return self.handle_operand(&Operand::Copy(*place), state);
+            }
+            Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
+                // We don't track such places.
+                return ValueOrPlace::TOP;
+            }
+            Rvalue::Repeat(..)
+            | Rvalue::ThreadLocalRef(..)
+            | Rvalue::Cast(..)
+            | Rvalue::BinaryOp(..)
+            | Rvalue::Aggregate(..)
+            | Rvalue::ShallowInitBox(..) => {
+                // No modification is possible through these r-values.
+                return ValueOrPlace::TOP;
+            }
         };
         ValueOrPlace::Value(val)
     }
@@ -305,8 +510,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
     fn handle_constant(
         &self,
         constant: &ConstOperand<'tcx>,
-        _state: &mut State<Self::Value>,
-    ) -> Self::Value {
+        _state: &mut State<FlatSet<Scalar>>,
+    ) -> FlatSet<Scalar> {
         constant
             .const_
             .try_eval_scalar(self.tcx, self.param_env)
@@ -317,11 +522,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
         &self,
         discr: &'mir Operand<'tcx>,
         targets: &'mir SwitchTargets,
-        state: &mut State<Self::Value>,
+        state: &mut State<FlatSet<Scalar>>,
     ) -> TerminatorEdges<'mir, 'tcx> {
         let value = match self.handle_operand(discr, state) {
             ValueOrPlace::Value(value) => value,
-            ValueOrPlace::Place(place) => state.get_idx(place, self.map()),
+            ValueOrPlace::Place(place) => state.get_idx(place, &self.map),
         };
         match value {
             // We are branching on uninitialized data, this is UB, treat it as unreachable.
@@ -334,19 +539,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
             FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets },
         }
     }
-}
-
-impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self {
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        Self {
-            map,
-            tcx,
-            local_decls: &body.local_decls,
-            ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine),
-            param_env,
-        }
-    }
 
     /// The caller must have flooded `place`.
     fn assign_operand(
@@ -537,16 +729,40 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     }
 }
 
-pub(crate) struct Patch<'tcx> {
+/// This is used to visualize the dataflow analysis.
+impl<'tcx> DebugWithContext<ConstAnalysis<'_, 'tcx>> for State<FlatSet<Scalar>> {
+    fn fmt_with(&self, ctxt: &ConstAnalysis<'_, 'tcx>, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            State::Reachable(values) => debug_with_context(values, None, &ctxt.map, f),
+            State::Unreachable => write!(f, "unreachable"),
+        }
+    }
+
+    fn fmt_diff_with(
+        &self,
+        old: &Self,
+        ctxt: &ConstAnalysis<'_, 'tcx>,
+        f: &mut Formatter<'_>,
+    ) -> std::fmt::Result {
+        match (self, old) {
+            (State::Reachable(this), State::Reachable(old)) => {
+                debug_with_context(this, Some(old), &ctxt.map, f)
+            }
+            _ => Ok(()), // Consider printing something here.
+        }
+    }
+}
+
+struct Patch<'tcx> {
     tcx: TyCtxt<'tcx>,
 
     /// For a given MIR location, this stores the values of the operands used by that location. In
     /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
     /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
-    pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>,
+    before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>,
 
     /// Stores the assigned values for assignments where the Rvalue is constant.
-    pub(crate) assignments: FxHashMap<Location, Const<'tcx>>,
+    assignments: FxHashMap<Location, Const<'tcx>>,
 }
 
 impl<'tcx> Patch<'tcx> {
@@ -725,8 +941,7 @@ fn try_write_constant<'tcx>(
     interp_ok(())
 }
 
-impl<'mir, 'tcx>
-    ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
+impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
     for Collector<'_, 'tcx>
 {
     type Domain = State<FlatSet<Scalar>>;
@@ -734,7 +949,7 @@ impl<'mir, 'tcx>
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
-        results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
+        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &Self::Domain,
         statement: &'mir Statement<'tcx>,
         location: Location,
@@ -744,8 +959,8 @@ impl<'mir, 'tcx>
                 OperandCollector {
                     state,
                     visitor: self,
-                    ecx: &mut results.analysis.0.ecx,
-                    map: &results.analysis.0.map,
+                    ecx: &mut results.analysis.ecx,
+                    map: &results.analysis.map,
                 }
                 .visit_rvalue(rvalue, location);
             }
@@ -756,7 +971,7 @@ impl<'mir, 'tcx>
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_after_primary_effect(
         &mut self,
-        results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
+        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &Self::Domain,
         statement: &'mir Statement<'tcx>,
         location: Location,
@@ -767,10 +982,10 @@ impl<'mir, 'tcx>
             }
             StatementKind::Assign(box (place, _)) => {
                 if let Some(value) = self.try_make_constant(
-                    &mut results.analysis.0.ecx,
+                    &mut results.analysis.ecx,
                     place,
                     state,
-                    &results.analysis.0.map,
+                    &results.analysis.map,
                 ) {
                     self.patch.assignments.insert(location, value);
                 }
@@ -781,7 +996,7 @@ impl<'mir, 'tcx>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
+        results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
         state: &Self::Domain,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
@@ -789,8 +1004,8 @@ impl<'mir, 'tcx>
         OperandCollector {
             state,
             visitor: self,
-            ecx: &mut results.analysis.0.ecx,
-            map: &results.analysis.0.map,
+            ecx: &mut results.analysis.ecx,
+            map: &results.analysis.map,
         }
         .visit_terminator(terminator, location);
     }
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 18f5a1a58db..88595ff7e51 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -175,9 +175,7 @@ fn main() {
         // Find any host flags that were passed by bootstrap.
         // The flags are stored in a RUSTC_HOST_FLAGS variable, separated by spaces.
         if let Ok(flags) = std::env::var("RUSTC_HOST_FLAGS") {
-            for flag in flags.split(' ') {
-                cmd.arg(flag);
-            }
+            cmd.args(flags.split(' '));
         }
     }
 
diff --git a/tests/ui/json/json-bom-plus-crlf-multifile.rs b/tests/ui/json/json-bom-plus-crlf-multifile.rs
index ae608770aae..79c4b2430e1 100644
--- a/tests/ui/json/json-bom-plus-crlf-multifile.rs
+++ b/tests/ui/json/json-bom-plus-crlf-multifile.rs
@@ -1,6 +1,8 @@
 // (This line has BOM so it's ignored by compiletest for directives)

 //

 //@ compile-flags: --json=diagnostic-short --error-format=json

+//@ reference: input.byte-order-mark

+//@ reference: input.crlf

 // ignore-tidy-cr

 

 #[path = "json-bom-plus-crlf-multifile-aux.rs"]

diff --git a/tests/ui/json/json-bom-plus-crlf.rs b/tests/ui/json/json-bom-plus-crlf.rs
index 4a309128199..9e250c256eb 100644
--- a/tests/ui/json/json-bom-plus-crlf.rs
+++ b/tests/ui/json/json-bom-plus-crlf.rs
@@ -1,6 +1,8 @@
 // (This line has BOM so it's ignored by compiletest for directives)

 //

 //@ compile-flags: --json=diagnostic-short --error-format=json

+//@ reference: input.byte-order-mark

+//@ reference: input.crlf

 // ignore-tidy-cr

 

 // For easier verifying, the byte offsets in this file should match those

diff --git a/tests/ui/json/json-bom-plus-crlf.stderr b/tests/ui/json/json-bom-plus-crlf.stderr
index cd1e3665b3e..fee70431bdf 100644
--- a/tests/ui/json/json-bom-plus-crlf.stderr
+++ b/tests/ui/json/json-bom-plus-crlf.stderr
@@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":608,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":598,"byte_end":604,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":608,"byte_end":608,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types: expected `String`, found integer
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":672,"byte_end":673,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":663,"byte_end":669,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":673,"byte_end":673,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1;  // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -52,7 +52,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":668,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":658,"byte_end":664,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":668,"byte_end":668,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types: expected `String`, found integer
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":733,"line_start":20,"line_end":20,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":723,"byte_end":729,"line_start":20,"line_end":20,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":733,"byte_end":733,"line_start":20,"line_end":20,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":"    let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:20:22: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -80,7 +80,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":732,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":721,"byte_end":727,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":732,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types: expected `String`, found integer
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":796,"byte_end":797,"line_start":24,"line_end":24,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":792,"line_start":23,"line_end":23,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":797,"byte_end":797,"line_start":24,"line_end":24,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1;  // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:24:1: error[E0308]: mismatched types: expected `String`, found integer
 "}
 {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
 
@@ -108,7 +108,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":787,"byte_end":795,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":778,"byte_end":784,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types: expected `String`, found `()`
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":852,"byte_end":860,"line_start":26,"line_end":27,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":"    let s : String = (","highlight_start":22,"highlight_end":23},{"text":"    );  // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":843,"byte_end":849,"line_start":26,"line_end":26,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":"    let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:26:22: error[E0308]: mismatched types: expected `String`, found `()`
 "}
 {"$message_type":"diagnostic","message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
 "}
diff --git a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
index b355997a4b3..ee193a58ce1 100644
--- a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
+++ b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs
@@ -1,4 +1,5 @@
 //@ run-pass

+//@ reference: input.crlf

 // ignore-tidy-cr

 // ignore-tidy-cr (repeated again because of tidy bug)

 // license is ignored because tidy can't handle the CRLF here properly.

diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs
index 3c433a4e27c..8100d65a9f8 100644
--- a/tests/ui/macros/not-utf8.rs
+++ b/tests/ui/macros/not-utf8.rs
@@ -1,4 +1,6 @@
 //@ error-pattern: did not contain valid UTF-8
+//@ reference: input.encoding.utf8
+//@ reference: input.encoding.invalid
 
 fn foo() {
     include!("not-utf8.bin")
diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr
index bf4704285c0..0d587cab5f3 100644
--- a/tests/ui/macros/not-utf8.stderr
+++ b/tests/ui/macros/not-utf8.stderr
@@ -1,5 +1,5 @@
 error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8
-  --> $DIR/not-utf8.rs:4:5
+  --> $DIR/not-utf8.rs:6:5
    |
 LL |     include!("not-utf8.bin")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs
index a2505180884..e9bff91f1e8 100644
--- a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs
+++ b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs
@@ -1,2 +1,4 @@
 
 #!B //~ expected `[`, found `B`
+
+//@ reference: input.shebang
diff --git a/tests/ui/parser/shebang/multiline-attrib.rs b/tests/ui/parser/shebang/multiline-attrib.rs
index bb083610e55..2d2e0298638 100644
--- a/tests/ui/parser/shebang/multiline-attrib.rs
+++ b/tests/ui/parser/shebang/multiline-attrib.rs
@@ -1,6 +1,7 @@
 #!
 [allow(unused_variables)]
 //@ check-pass
+//@ reference: input.shebang.inner-attribute
 
 fn main() {
     let x = 5;
diff --git a/tests/ui/parser/shebang/regular-attrib.rs b/tests/ui/parser/shebang/regular-attrib.rs
index aed633d3ef1..c2ac25661ef 100644
--- a/tests/ui/parser/shebang/regular-attrib.rs
+++ b/tests/ui/parser/shebang/regular-attrib.rs
@@ -1,5 +1,6 @@
 #![allow(unused_variables)]
 //@ check-pass
+//@ reference: input.shebang.inner-attribute
 fn main() {
     let x = 5;
 }
diff --git a/tests/ui/parser/shebang/shebang-and-attrib.rs b/tests/ui/parser/shebang/shebang-and-attrib.rs
index a66c10db532..d73db6b22f0 100644
--- a/tests/ui/parser/shebang/shebang-and-attrib.rs
+++ b/tests/ui/parser/shebang/shebang-and-attrib.rs
@@ -1,6 +1,7 @@
 #!/usr/bin/env run-cargo-script
 
 //@ check-pass
+//@ reference: input.shebang.inner-attribute
 #![allow(unused_variables)]
 
 
diff --git a/tests/ui/parser/shebang/shebang-comment.rs b/tests/ui/parser/shebang/shebang-comment.rs
index 37bcac8b29e..6f89e8954c3 100644
--- a/tests/ui/parser/shebang/shebang-comment.rs
+++ b/tests/ui/parser/shebang/shebang-comment.rs
@@ -1,6 +1,7 @@
 #!//bin/bash
 
 //@ check-pass
+//@ reference: input.shebang
 fn main() {
     println!("a valid shebang (that is also a rust comment)")
 }
diff --git a/tests/ui/parser/shebang/shebang-doc-comment.rs b/tests/ui/parser/shebang/shebang-doc-comment.rs
index 72866753e0e..4992c758325 100644
--- a/tests/ui/parser/shebang/shebang-doc-comment.rs
+++ b/tests/ui/parser/shebang/shebang-doc-comment.rs
@@ -1,3 +1,5 @@
 #!///bin/bash
 [allow(unused_variables)]
 //~^ ERROR expected item, found `[`
+
+//@ reference: input.shebang.inner-attribute
diff --git a/tests/ui/parser/shebang/shebang-empty.rs b/tests/ui/parser/shebang/shebang-empty.rs
index bb0df599783..51bf8a07c90 100644
--- a/tests/ui/parser/shebang/shebang-empty.rs
+++ b/tests/ui/parser/shebang/shebang-empty.rs
@@ -1,4 +1,5 @@
 #!
 
 //@ check-pass
+//@ reference: input.shebang
 fn main() {}
diff --git a/tests/ui/parser/shebang/shebang-must-start-file.rs b/tests/ui/parser/shebang/shebang-must-start-file.rs
index e0392572dc8..f91e32f744e 100644
--- a/tests/ui/parser/shebang/shebang-must-start-file.rs
+++ b/tests/ui/parser/shebang/shebang-must-start-file.rs
@@ -1,6 +1,8 @@
 // something on the first line for tidy
 #!/bin/bash  //~ expected `[`, found `/`
 
+//@ reference: input.shebang
+
 fn main() {
     println!("ok!");
 }
diff --git a/tests/ui/parser/shebang/shebang-space.rs b/tests/ui/parser/shebang/shebang-space.rs
index cc58eed8b8a..803d4e04057 100644
--- a/tests/ui/parser/shebang/shebang-space.rs
+++ b/tests/ui/parser/shebang/shebang-space.rs
@@ -1,5 +1,6 @@
 #!    
 
 //@ check-pass
+//@ reference: input.shebang
 // ignore-tidy-end-whitespace
 fn main() {}
diff --git a/tests/ui/parser/shebang/sneaky-attrib.rs b/tests/ui/parser/shebang/sneaky-attrib.rs
index eb814c6af24..e22c45cc39f 100644
--- a/tests/ui/parser/shebang/sneaky-attrib.rs
+++ b/tests/ui/parser/shebang/sneaky-attrib.rs
@@ -11,6 +11,7 @@
 [allow(unused_variables)]
 
 //@ check-pass
+//@ reference: input.shebang.inner-attribute
 fn main() {
     let x = 5;
 }
diff --git a/tests/ui/parser/shebang/valid-shebang.rs b/tests/ui/parser/shebang/valid-shebang.rs
index e59d4074ddf..f93b0e15d77 100644
--- a/tests/ui/parser/shebang/valid-shebang.rs
+++ b/tests/ui/parser/shebang/valid-shebang.rs
@@ -1,6 +1,7 @@
 #!/usr/bin/env run-cargo-script
 
 //@ check-pass
+//@ reference: input.shebang
 fn main() {
     println!("Hello World!");
 }
diff --git a/tests/ui/parser/utf16-be-without-bom.rs b/tests/ui/parser/utf16-be-without-bom.rs
index 68e89bc7c22..f5fe8dc5a8c 100644
--- a/tests/ui/parser/utf16-be-without-bom.rs
+++ b/tests/ui/parser/utf16-be-without-bom.rs
Binary files differdiff --git a/tests/ui/parser/utf16-be-without-bom.stderr b/tests/ui/parser/utf16-be-without-bom.stderr
index 55ebf7aacd2..b915c7941b3 100644
--- a/tests/ui/parser/utf16-be-without-bom.stderr
+++ b/tests/ui/parser/utf16-be-without-bom.stderr
@@ -1,5 +1,5 @@
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:1
+  --> $DIR/utf16-be-without-bom.rs:5:1
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    | ^
@@ -7,7 +7,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:3
+  --> $DIR/utf16-be-without-bom.rs:5:3
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |   ^
@@ -15,7 +15,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:5
+  --> $DIR/utf16-be-without-bom.rs:5:5
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |     ^
@@ -23,7 +23,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:7
+  --> $DIR/utf16-be-without-bom.rs:5:7
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |       ^
@@ -31,7 +31,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:9
+  --> $DIR/utf16-be-without-bom.rs:5:9
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |         ^
@@ -39,7 +39,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:11
+  --> $DIR/utf16-be-without-bom.rs:5:11
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |           ^
@@ -47,7 +47,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:13
+  --> $DIR/utf16-be-without-bom.rs:5:13
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |             ^
@@ -55,7 +55,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:15
+  --> $DIR/utf16-be-without-bom.rs:5:15
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |               ^
@@ -63,7 +63,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:17
+  --> $DIR/utf16-be-without-bom.rs:5:17
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                 ^
@@ -71,7 +71,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:19
+  --> $DIR/utf16-be-without-bom.rs:5:19
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                   ^
@@ -79,7 +79,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:21
+  --> $DIR/utf16-be-without-bom.rs:5:21
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                     ^
@@ -87,7 +87,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:23
+  --> $DIR/utf16-be-without-bom.rs:5:23
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                       ^
@@ -95,7 +95,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-be-without-bom.rs:4:25
+  --> $DIR/utf16-be-without-bom.rs:5:25
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                         ^
@@ -103,7 +103,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: expected one of `!` or `::`, found `n`
-  --> $DIR/utf16-be-without-bom.rs:4:4
+  --> $DIR/utf16-be-without-bom.rs:5:4
    |
 LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |    ^ expected one of `!` or `::`
diff --git a/tests/ui/parser/utf16-le-without-bom.rs b/tests/ui/parser/utf16-le-without-bom.rs
index bdf4860d016..8c781b27dc0 100644
--- a/tests/ui/parser/utf16-le-without-bom.rs
+++ b/tests/ui/parser/utf16-le-without-bom.rs
Binary files differdiff --git a/tests/ui/parser/utf16-le-without-bom.stderr b/tests/ui/parser/utf16-le-without-bom.stderr
index ad272a70f06..d937a07bc66 100644
--- a/tests/ui/parser/utf16-le-without-bom.stderr
+++ b/tests/ui/parser/utf16-le-without-bom.stderr
@@ -1,5 +1,5 @@
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:2
+  --> $DIR/utf16-le-without-bom.rs:5:2
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |  ^
@@ -7,7 +7,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:4
+  --> $DIR/utf16-le-without-bom.rs:5:4
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |    ^
@@ -15,7 +15,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:6
+  --> $DIR/utf16-le-without-bom.rs:5:6
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |      ^
@@ -23,7 +23,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:8
+  --> $DIR/utf16-le-without-bom.rs:5:8
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |        ^
@@ -31,7 +31,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:10
+  --> $DIR/utf16-le-without-bom.rs:5:10
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |          ^
@@ -39,7 +39,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:12
+  --> $DIR/utf16-le-without-bom.rs:5:12
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |            ^
@@ -47,7 +47,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:14
+  --> $DIR/utf16-le-without-bom.rs:5:14
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |              ^
@@ -55,7 +55,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:16
+  --> $DIR/utf16-le-without-bom.rs:5:16
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                ^
@@ -63,7 +63,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:18
+  --> $DIR/utf16-le-without-bom.rs:5:18
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                  ^
@@ -71,7 +71,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:20
+  --> $DIR/utf16-le-without-bom.rs:5:20
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                    ^
@@ -79,7 +79,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:22
+  --> $DIR/utf16-le-without-bom.rs:5:22
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                      ^
@@ -87,7 +87,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:4:24
+  --> $DIR/utf16-le-without-bom.rs:5:24
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |                        ^
@@ -95,7 +95,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: unknown start of token: \u{0}
-  --> $DIR/utf16-le-without-bom.rs:5:1
+  --> $DIR/utf16-le-without-bom.rs:6:1
    |
 LL | ␀
    | ^
@@ -103,7 +103,7 @@ LL | ␀
    = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used
 
 error: expected one of `!` or `::`, found `n`
-  --> $DIR/utf16-le-without-bom.rs:4:3
+  --> $DIR/utf16-le-without-bom.rs:5:3
    |
 LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀
    |   ^ expected one of `!` or `::`
diff --git a/tests/ui/traits/const-traits/do-not-const-check.rs b/tests/ui/traits/const-traits/do-not-const-check.rs
index 443b6385735..d227a9a9c09 100644
--- a/tests/ui/traits/const-traits/do-not-const-check.rs
+++ b/tests/ui/traits/const-traits/do-not-const-check.rs
@@ -1,5 +1,6 @@
 //@ check-pass
-#![feature(const_trait_impl, rustc_attrs)]
+#![feature(const_trait_impl, rustc_attrs, effects)]
+//~^ WARN the feature `effects` is incomplete
 
 #[const_trait]
 trait IntoIter {
diff --git a/tests/ui/traits/const-traits/do-not-const-check.stderr b/tests/ui/traits/const-traits/do-not-const-check.stderr
new file mode 100644
index 00000000000..0d81ef74e8d
--- /dev/null
+++ b/tests/ui/traits/const-traits/do-not-const-check.stderr
@@ -0,0 +1,11 @@
+warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/do-not-const-check.rs:2:43
+   |
+LL | #![feature(const_trait_impl, rustc_attrs, effects)]
+   |                                           ^^^^^^^
+   |
+   = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/utf8-bom.rs b/tests/ui/utf8-bom.rs
index 5b9e27fb7b9..eb82f6652cb 100644
--- a/tests/ui/utf8-bom.rs
+++ b/tests/ui/utf8-bom.rs
@@ -1,4 +1,5 @@
 // This file has utf-8 BOM, it should be compiled normally without error.
 //@ run-pass
+//@ reference: input.byte-order-mark
 
 pub fn main() {}