Skip to content

Commit 3c0f722

Browse files
committed
Auto merge of #139154 - jhpratt:rollup-rv8f915, r=jhpratt
Rollup of 5 pull requests Successful merges: - #139044 (bootstrap: Avoid cloning `change-id` list) - #139111 (Properly document FakeReads) - #139122 (Remove attribute `#[rustc_error]`) - #139132 (Improve hir_pretty for struct expressions.) - #139141 (Switch some rustc_on_unimplemented uses to diagnostic::on_unimplemented) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2ea33b5 + a99b533 commit 3c0f722

File tree

57 files changed

+228
-302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+228
-302
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1087,9 +1087,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
10871087
WarnFollowing, EncodeCrossCrate::No
10881088
),
10891089
rustc_attr!(
1090-
TEST, rustc_error, Normal,
1091-
template!(Word, List: "delayed_bug_from_inside_query"),
1092-
WarnFollowingWordOnly, EncodeCrossCrate::Yes
1090+
TEST, rustc_delayed_bug_from_inside_query, Normal,
1091+
template!(Word),
1092+
WarnFollowing, EncodeCrossCrate::No
10931093
),
10941094
rustc_attr!(
10951095
TEST, rustc_dump_user_args, Normal, template!(Word),

compiler/rustc_hir_pretty/src/lib.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,8 @@ impl<'a> State<'a> {
11931193
wth: hir::StructTailExpr<'_>,
11941194
) {
11951195
self.print_qpath(qpath, true);
1196-
self.word("{");
1196+
self.nbsp();
1197+
self.word_space("{");
11971198
self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span);
11981199
match wth {
11991200
hir::StructTailExpr::Base(expr) => {
@@ -1215,20 +1216,13 @@ impl<'a> State<'a> {
12151216
self.word("..");
12161217
self.end();
12171218
}
1218-
hir::StructTailExpr::None => {
1219-
if !fields.is_empty() {
1220-
self.word(",");
1221-
}
1222-
}
1219+
hir::StructTailExpr::None => {}
12231220
}
1224-
1221+
self.space();
12251222
self.word("}");
12261223
}
12271224

12281225
fn print_expr_field(&mut self, field: &hir::ExprField<'_>) {
1229-
if self.attrs(field.hir_id).is_empty() {
1230-
self.space();
1231-
}
12321226
self.cbox(INDENT_UNIT);
12331227
self.print_attrs_as_outer(self.attrs(field.hir_id));
12341228
if !field.is_shorthand {

compiler/rustc_interface/messages.ftl

-6
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,5 @@ interface_out_dir_error =
5050
interface_proc_macro_crate_panic_abort =
5151
building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
5252
53-
interface_rustc_error_fatal =
54-
fatal error triggered by #[rustc_error]
55-
56-
interface_rustc_error_unexpected_annotation =
57-
unexpected annotation used with `#[rustc_error(...)]`!
58-
5953
interface_temps_dir_error =
6054
failed to find or create the directory specified by `--temps-dir`

compiler/rustc_interface/src/errors.rs

-14
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,6 @@ pub struct TempsDirError;
7373
#[diag(interface_out_dir_error)]
7474
pub struct OutDirError;
7575

76-
#[derive(Diagnostic)]
77-
#[diag(interface_rustc_error_fatal)]
78-
pub struct RustcErrorFatal {
79-
#[primary_span]
80-
pub span: Span,
81-
}
82-
83-
#[derive(Diagnostic)]
84-
#[diag(interface_rustc_error_unexpected_annotation)]
85-
pub struct RustcErrorUnexpectedAnnotation {
86-
#[primary_span]
87-
pub span: Span,
88-
}
89-
9076
#[derive(Diagnostic)]
9177
#[diag(interface_failed_writing_file)]
9278
pub struct FailedWritingFile<'a> {

compiler/rustc_interface/src/passes.rs

+6-36
Original file line numberDiff line numberDiff line change
@@ -1067,48 +1067,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
10671067
});
10681068
}
10691069

1070-
/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
1071-
/// to write UI tests that actually test that compilation succeeds without reporting
1072-
/// an error.
1073-
fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
1074-
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
1075-
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
1076-
match attr.meta_item_list() {
1077-
// Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
1078-
Some(list)
1079-
if list.iter().any(|list_item| {
1080-
matches!(
1081-
list_item.ident().map(|i| i.name),
1082-
Some(sym::delayed_bug_from_inside_query)
1083-
)
1084-
}) =>
1085-
{
1086-
tcx.ensure_ok().trigger_delayed_bug(def_id);
1087-
}
1088-
1089-
// Bare `#[rustc_error]`.
1090-
None => {
1091-
tcx.dcx().emit_fatal(errors::RustcErrorFatal { span: tcx.def_span(def_id) });
1092-
}
1093-
1094-
// Some other attribute.
1095-
Some(_) => {
1096-
tcx.dcx().emit_warn(errors::RustcErrorUnexpectedAnnotation {
1097-
span: tcx.def_span(def_id),
1098-
});
1099-
}
1100-
}
1101-
}
1102-
}
1103-
11041070
/// Runs the codegen backend, after which the AST and analysis can
11051071
/// be discarded.
11061072
pub(crate) fn start_codegen<'tcx>(
11071073
codegen_backend: &dyn CodegenBackend,
11081074
tcx: TyCtxt<'tcx>,
11091075
) -> Box<dyn Any> {
1110-
// Hook for UI tests.
1111-
check_for_rustc_errors_attr(tcx);
1076+
// Hook for tests.
1077+
if let Some((def_id, _)) = tcx.entry_fn(())
1078+
&& tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query)
1079+
{
1080+
tcx.ensure_ok().trigger_delayed_bug(def_id);
1081+
}
11121082

11131083
// Don't run this test assertions when not doing codegen. Compiletest tries to build
11141084
// build-fail tests in check mode first and expects it to not give an error in that case.

compiler/rustc_middle/src/mir/syntax.rs

+84-28
Original file line numberDiff line numberDiff line change
@@ -334,14 +334,19 @@ pub enum StatementKind<'tcx> {
334334
/// See [`Rvalue`] documentation for details on each of those.
335335
Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
336336

337-
/// This represents all the reading that a pattern match may do (e.g., inspecting constants and
338-
/// discriminant values), and the kind of pattern it comes from. This is in order to adapt
339-
/// potential error messages to these specific patterns.
337+
/// When executed at runtime, this is a nop.
340338
///
341-
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
342-
/// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
339+
/// During static analysis, a fake read:
340+
/// - requires that the value being read is initialized (or, in the case
341+
/// of closures, that it was fully initialized at some point in the past)
342+
/// - constitutes a use of a value for the purposes of NLL (i.e. if the
343+
/// value being fake-read is a reference, the lifetime of that reference
344+
/// will be extended to cover the `FakeRead`)
345+
/// - but, unlike an actual read, does *not* invalidate any exclusive
346+
/// borrows.
343347
///
344-
/// When executed at runtime this is a nop.
348+
/// See [`FakeReadCause`] for more details on the situations in which a
349+
/// `FakeRead` is emitted.
345350
///
346351
/// Disallowed after drop elaboration.
347352
FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
@@ -518,28 +523,59 @@ pub enum RetagKind {
518523
/// The `FakeReadCause` describes the type of pattern why a FakeRead statement exists.
519524
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, Hash, HashStable, PartialEq)]
520525
pub enum FakeReadCause {
521-
/// Inject a fake read of the borrowed input at the end of each guards
522-
/// code.
526+
/// A fake read injected into a match guard to ensure that the discriminants
527+
/// that are being matched on aren't modified while the match guard is being
528+
/// evaluated.
529+
///
530+
/// At the beginning of each match guard, a [fake borrow][FakeBorrowKind] is
531+
/// inserted for each discriminant accessed in the entire `match` statement.
532+
///
533+
/// Then, at the end of the match guard, a `FakeRead(ForMatchGuard)` is
534+
/// inserted to keep the fake borrows alive until that point.
523535
///
524536
/// This should ensure that you cannot change the variant for an enum while
525537
/// you are in the midst of matching on it.
526538
ForMatchGuard,
527539

528-
/// `let x: !; match x {}` doesn't generate any read of x so we need to
529-
/// generate a read of x to check that it is initialized and safe.
540+
/// Fake read of the scrutinee of a `match` or destructuring `let`
541+
/// (i.e. `let` with non-trivial pattern).
542+
///
543+
/// In `match x { ... }`, we generate a `FakeRead(ForMatchedPlace, x)`
544+
/// and insert it into the `otherwise_block` (which is supposed to be
545+
/// unreachable for irrefutable pattern-matches like `match` or `let`).
546+
///
547+
/// This is necessary because `let x: !; match x {}` doesn't generate any
548+
/// actual read of x, so we need to generate a `FakeRead` to check that it
549+
/// is initialized.
530550
///
531-
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
532-
/// FakeRead for that Place outside the closure, in such a case this option would be
533-
/// Some(closure_def_id).
534-
/// Otherwise, the value of the optional LocalDefId will be None.
551+
/// If the `FakeRead(ForMatchedPlace)` is being performed with a closure
552+
/// that doesn't capture the required upvars, the `FakeRead` within the
553+
/// closure is omitted entirely.
554+
///
555+
/// To make sure that this is still sound, if a closure matches against
556+
/// a Place starting with an Upvar, we hoist the `FakeRead` to the
557+
/// definition point of the closure.
558+
///
559+
/// If the `FakeRead` comes from being hoisted out of a closure like this,
560+
/// we record the `LocalDefId` of the closure. Otherwise, the `Option` will be `None`.
535561
//
536562
// We can use LocalDefId here since fake read statements are removed
537563
// before codegen in the `CleanupNonCodegenStatements` pass.
538564
ForMatchedPlace(Option<LocalDefId>),
539565

540-
/// A fake read of the RefWithinGuard version of a bind-by-value variable
541-
/// in a match guard to ensure that its value hasn't change by the time
542-
/// we create the OutsideGuard version.
566+
/// A fake read injected into a match guard to ensure that the places
567+
/// bound by the pattern are immutable for the duration of the match guard.
568+
///
569+
/// Within a match guard, references are created for each place that the
570+
/// pattern creates a binding for — this is known as the `RefWithinGuard`
571+
/// version of the variables. To make sure that the references stay
572+
/// alive until the end of the match guard, and properly prevent the
573+
/// places in question from being modified, a `FakeRead(ForGuardBinding)`
574+
/// is inserted at the end of the match guard.
575+
///
576+
/// For details on how these references are created, see the extensive
577+
/// documentation on `bind_matched_candidate_for_guard` in
578+
/// `rustc_mir_build`.
543579
ForGuardBinding,
544580

545581
/// Officially, the semantics of
@@ -552,22 +588,42 @@ pub enum FakeReadCause {
552588
/// However, if we see the simple pattern `let var = <expr>`, we optimize this to
553589
/// evaluate `<expr>` directly into the variable `var`. This is mostly unobservable,
554590
/// but in some cases it can affect the borrow checker, as in #53695.
555-
/// Therefore, we insert a "fake read" here to ensure that we get
556-
/// appropriate errors.
557591
///
558-
/// If a closure pattern matches a Place starting with an Upvar, then we introduce a
559-
/// FakeRead for that Place outside the closure, in such a case this option would be
560-
/// Some(closure_def_id).
561-
/// Otherwise, the value of the optional DefId will be None.
592+
/// Therefore, we insert a `FakeRead(ForLet)` immediately after each `let`
593+
/// with a trivial pattern.
594+
///
595+
/// FIXME: `ExprUseVisitor` has an entirely different opinion on what `FakeRead(ForLet)`
596+
/// is supposed to mean. If it was accurate to what MIR lowering does,
597+
/// would it even make sense to hoist these out of closures like
598+
/// `ForMatchedPlace`?
562599
ForLet(Option<LocalDefId>),
563600

564-
/// If we have an index expression like
601+
/// Currently, index expressions overloaded through the `Index` trait
602+
/// get lowered differently than index expressions with builtin semantics
603+
/// for arrays and slices — the latter will emit code to perform
604+
/// bound checks, and then return a MIR place that will only perform the
605+
/// indexing "for real" when it gets incorporated into an instruction.
606+
///
607+
/// This is observable in the fact that the following compiles:
608+
///
609+
/// ```
610+
/// fn f(x: &mut [&mut [u32]], i: usize) {
611+
/// x[i][x[i].len() - 1] += 1;
612+
/// }
613+
/// ```
614+
///
615+
/// However, we need to be careful to not let the user invalidate the
616+
/// bound check with an expression like
617+
///
618+
/// `(*x)[1][{ x = y; 4}]`
565619
///
566-
/// (*x)[1][{ x = y; 4}]
620+
/// Here, the first bounds check would be invalidated when we evaluate the
621+
/// second index expression. To make sure that this doesn't happen, we
622+
/// create a fake borrow of `x` and hold it while we evaluate the second
623+
/// index.
567624
///
568-
/// then the first bounds check is invalidated when we evaluate the second
569-
/// index expression. Thus we create a fake borrow of `x` across the second
570-
/// indexer, which will cause a borrow check error.
625+
/// This borrow is kept alive by a `FakeRead(ForIndex)` at the end of its
626+
/// scope.
571627
ForIndex,
572628
}
573629

compiler/rustc_middle/src/util/bug.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
4949
pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
5050
tcx.dcx().span_delayed_bug(
5151
tcx.def_span(key),
52-
"delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
52+
"delayed bug triggered by #[rustc_delayed_bug_from_inside_query]",
5353
);
5454
}
5555

compiler/rustc_span/src/symbol.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1774,6 +1774,7 @@ symbols! {
17741774
rustc_deallocator,
17751775
rustc_def_path,
17761776
rustc_default_body_unstable,
1777+
rustc_delayed_bug_from_inside_query,
17771778
rustc_deny_explicit_impl,
17781779
rustc_deprecated_safe_2024,
17791780
rustc_diagnostic_item,
@@ -1790,7 +1791,6 @@ symbols! {
17901791
rustc_dump_user_args,
17911792
rustc_dump_vtable,
17921793
rustc_effective_visibility,
1793-
rustc_error,
17941794
rustc_evaluate_where_clauses,
17951795
rustc_expected_cgu_reuse,
17961796
rustc_force_inline,

library/alloc/src/vec/mod.rs

-8
Original file line numberDiff line numberDiff line change
@@ -3360,10 +3360,6 @@ impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
33603360
}
33613361

33623362
#[stable(feature = "rust1", since = "1.0.0")]
3363-
#[rustc_on_unimplemented(
3364-
message = "vector indices are of type `usize` or ranges of `usize`",
3365-
label = "vector indices are of type `usize` or ranges of `usize`"
3366-
)]
33673363
impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
33683364
type Output = I::Output;
33693365

@@ -3374,10 +3370,6 @@ impl<T, I: SliceIndex<[T]>, A: Allocator> Index<I> for Vec<T, A> {
33743370
}
33753371

33763372
#[stable(feature = "rust1", since = "1.0.0")]
3377-
#[rustc_on_unimplemented(
3378-
message = "vector indices are of type `usize` or ranges of `usize`",
3379-
label = "vector indices are of type `usize` or ranges of `usize`"
3380-
)]
33813373
impl<T, I: SliceIndex<[T]>, A: Allocator> IndexMut<I> for Vec<T, A> {
33823374
#[inline]
33833375
fn index_mut(&mut self, index: I) -> &mut Self::Output {

library/core/src/iter/traits/accum.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::num::Wrapping;
1010
/// [`sum()`]: Iterator::sum
1111
/// [`FromIterator`]: iter::FromIterator
1212
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
13-
#[rustc_on_unimplemented(
13+
#[diagnostic::on_unimplemented(
1414
message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
1515
label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
1616
)]
@@ -31,7 +31,7 @@ pub trait Sum<A = Self>: Sized {
3131
/// [`product()`]: Iterator::product
3232
/// [`FromIterator`]: iter::FromIterator
3333
#[stable(feature = "iter_arith_traits", since = "1.12.0")]
34-
#[rustc_on_unimplemented(
34+
#[diagnostic::on_unimplemented(
3535
message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
3636
label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
3737
)]

src/bootstrap/src/bin/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ fn check_version(config: &Config) -> Option<String> {
191191
}
192192

193193
msg.push_str("There have been changes to x.py since you last updated:\n");
194-
msg.push_str(&human_readable_changes(&changes));
194+
msg.push_str(&human_readable_changes(changes));
195195

196196
msg.push_str("NOTE: to silence this warning, ");
197197
msg.push_str(&format!(

src/bootstrap/src/core/config/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ impl Config {
13811381
if !changes.is_empty() {
13821382
println!(
13831383
"WARNING: There have been changes to x.py since you last updated:\n{}",
1384-
crate::human_readable_changes(&changes)
1384+
crate::human_readable_changes(changes)
13851385
);
13861386
}
13871387
}

0 commit comments

Comments
 (0)