Skip to content

Rollup of 5 pull requests #101767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/session.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,13 @@ session_target_invalid_bits_size = {$err}
session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored

session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform

session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions

session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`

session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen

session_crate_name_empty = crate name must not be empty

session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
2 changes: 1 addition & 1 deletion compiler/rustc_errors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_target = { path = "../rustc_target" }
rustc_hir = { path = "../rustc_hir" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_target = { path = "../rustc_target" }
unicode-width = "0.1.4"
atty = "0.2"
termcolor = "1.0"
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,16 @@ rustc_queries! {
desc { "looking up late bound vars" }
}

/// Computes the visibility of the provided `def_id`.
///
/// If the item from the `def_id` doesn't have a visibility, it will panic. For example
/// a generic type parameter will panic if you call this method on it:
///
/// ```
/// pub trait Foo<T: Debug> {}
/// ```
///
/// In here, if you call `visibility` on `T`, it'll panic.
query visibility(def_id: DefId) -> ty::Visibility<DefId> {
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
Expand Down
188 changes: 166 additions & 22 deletions compiler/rustc_mir_build/src/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,170 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
)
);
}
StmtKind::Let {
remainder_scope,
init_scope,
pattern,
initializer: Some(initializer),
lint_level,
else_block: Some(else_block),
} => {
// When lowering the statement `let <pat> = <expr> else { <else> };`,
// the `<else>` block is nested in the parent scope enclosing this statment.
// That scope is usually either the enclosing block scope,
// or the remainder scope of the last statement.
// This is to make sure that temporaries instantiated in `<expr>` are dropped
// as well.
// In addition, even though bindings in `<pat>` only come into scope if
// the pattern matching passes, in the MIR building the storages for them
// are declared as live any way.
// This is similar to `let x;` statements without an initializer expression,
// where the value of `x` in this example may or may be assigned,
// because the storage for their values may not be live after all due to
// failure in pattern matching.
// For this reason, we declare those storages as live but we do not schedule
// any drop yet- they are scheduled later after the pattern matching.
// The generated MIR will have `StorageDead` whenever the control flow breaks out
// of the parent scope, regardless of the result of the pattern matching.
// However, the drops are inserted in MIR only when the control flow breaks out of
// the scope of the remainder scope associated with this `let .. else` statement.
// Pictorial explanation of the scope structure:
// ┌─────────────────────────────────┐
// │ Scope of the enclosing block, │
// │ or the last remainder scope │
// │ ┌───────────────────────────┐ │
// │ │ Scope for <else> block │ │
// │ └───────────────────────────┘ │
// │ ┌───────────────────────────┐ │
// │ │ Remainder scope of │ │
// │ │ this let-else statement │ │
// │ │ ┌─────────────────────┐ │ │
// │ │ │ <expr> scope │ │ │
// │ │ └─────────────────────┘ │ │
// │ │ extended temporaries in │ │
// │ │ <expr> lives in this │ │
// │ │ scope │ │
// │ │ ┌─────────────────────┐ │ │
// │ │ │ Scopes for the rest │ │ │
// │ │ └─────────────────────┘ │ │
// │ └───────────────────────────┘ │
// └─────────────────────────────────┘
// Generated control flow:
// │ let Some(x) = y() else { return; }
// │
// ┌────────▼───────┐
// │ evaluate y() │
// └────────┬───────┘
// │ ┌────────────────┐
// ┌────────▼───────┐ │Drop temporaries│
// │Test the pattern├──────►in y() │
// └────────┬───────┘ │because breaking│
// │ │out of <expr> │
// ┌────────▼───────┐ │scope │
// │Move value into │ └───────┬────────┘
// │binding x │ │
// └────────┬───────┘ ┌───────▼────────┐
// │ │Drop extended │
// ┌────────▼───────┐ │temporaries in │
// │Drop temporaries│ │<expr> because │
// │in y() │ │breaking out of │
// │because breaking│ │remainder scope │
// │out of <expr> │ └───────┬────────┘
// │scope │ │
// └────────┬───────┘ ┌───────▼────────┐
// │ │Enter <else> ├────────►
// ┌────────▼───────┐ │block │ return;
// │Continue... │ └────────────────┘
// └────────────────┘

let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });

// Lower the `else` block first because its parent scope is actually
// enclosing the rest of the `let .. else ..` parts.
let else_block_span = this.thir[*else_block].span;
// This place is not really used because this destination place
// should never be used to take values at the end of the failure
// block.
let dummy_place = this.temp(this.tcx.types.never, else_block_span);
let failure_entry = this.cfg.start_new_block();
let failure_block;
unpack!(
failure_block = this.ast_block(
dummy_place,
failure_entry,
*else_block,
this.source_info(else_block_span),
)
);
this.cfg.terminate(
failure_block,
this.source_info(else_block_span),
TerminatorKind::Unreachable,
);

// Declare the bindings, which may create a source scope.
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
this.push_scope((*remainder_scope, source_info));
let_scope_stack.push(remainder_scope);

let visibility_scope =
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));

let init = &this.thir[*initializer];
let initializer_span = init.span;
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.visit_primary_bindings(
pattern,
UserTypeProjections::none(),
&mut |this, _, _, _, node, span, _, _| {
this.storage_live_binding(block, node, span, OutsideGuard, false);
},
);
let failure = unpack!(
block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)),
|this| {
let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| {
this.ast_let_else(
block,
init,
initializer_span,
*else_block,
&last_remainder_scope,
pattern,
)
})
}
)
);
this.cfg.goto(failure, source_info, failure_entry);

if let Some(source_scope) = visibility_scope {
this.source_scope = source_scope;
}
last_remainder_scope = *remainder_scope;
}
StmtKind::Let { init_scope, initializer: None, else_block: Some(_), .. } => {
span_bug!(
init_scope.span(this.tcx, this.region_scope_tree),
"initializer is missing, but else block is present in this let binding",
)
}
StmtKind::Let {
remainder_scope,
init_scope,
ref pattern,
initializer,
lint_level,
else_block,
else_block: None,
} => {
let ignores_expr_result = matches!(pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
Expand All @@ -141,27 +298,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|this| {
let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| {
if let Some(else_block) = else_block {
this.ast_let_else(
block,
init,
initializer_span,
*else_block,
visibility_scope,
last_remainder_scope,
remainder_span,
pattern,
)
} else {
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.expr_into_pattern(block, pattern, init) // irrefutable pattern
}
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.expr_into_pattern(block, &pattern, init) // irrefutable pattern
})
},
)
Expand Down
40 changes: 6 additions & 34 deletions compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
// Although there is almost always scope for given variable in corner cases
// like #92893 we might get variable with no scope.
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop {
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
}
Place::from(local_id)
Expand Down Expand Up @@ -2274,23 +2274,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
init: &Expr<'tcx>,
initializer_span: Span,
else_block: BlockId,
visibility_scope: Option<SourceScope>,
remainder_scope: region::Scope,
remainder_span: Span,
let_else_scope: &region::Scope,
pattern: &Pat<'tcx>,
) -> BlockAnd<()> {
) -> BlockAnd<BasicBlock> {
let else_block_span = self.thir[else_block].span;
let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
let (matching, failure) = self.in_if_then_scope(*let_else_scope, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
let fake_borrow_temps = this.lower_match_tree(
block,
Expand Down Expand Up @@ -2321,28 +2312,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
None,
None,
);
this.break_for_else(failure, remainder_scope, this.source_info(initializer_span));
this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span));
matching.unit()
});

// This place is not really used because this destination place
// should never be used to take values at the end of the failure
// block.
let dummy_place = self.temp(self.tcx.types.never, else_block_span);
let failure_block;
unpack!(
failure_block = self.ast_block(
dummy_place,
failure,
else_block,
self.source_info(else_block_span),
)
);
self.cfg.terminate(
failure_block,
self.source_info(else_block_span),
TerminatorKind::Unreachable,
);
matching.unit()
matching.and(failure)
}
}
51 changes: 50 additions & 1 deletion compiler/rustc_session/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::num::NonZeroU32;

use crate::cgu_reuse_tracker::CguReuse;
use crate::{self as rustc_session, SessionDiagnostic};
use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan};
use rustc_errors::{fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, MultiSpan};
use rustc_macros::SessionDiagnostic;
use rustc_span::{Span, Symbol};
use rustc_target::abi::TargetDataLayoutErrors;
Expand Down Expand Up @@ -170,3 +170,52 @@ pub struct StackProtectorNotSupportedForTarget<'a> {
pub struct SplitDebugInfoUnstablePlatform {
pub debuginfo: SplitDebuginfo,
}

#[derive(SessionDiagnostic)]
#[diag(session::file_is_not_writeable)]
pub struct FileIsNotWriteable<'a> {
pub file: &'a std::path::Path,
}

#[derive(SessionDiagnostic)]
#[diag(session::crate_name_does_not_match)]
pub struct CrateNameDoesNotMatch<'a> {
#[primary_span]
pub span: Span,
pub s: &'a str,
pub name: Symbol,
}

#[derive(SessionDiagnostic)]
#[diag(session::crate_name_invalid)]
pub struct CrateNameInvalid<'a> {
pub s: &'a str,
}

#[derive(SessionDiagnostic)]
#[diag(session::crate_name_empty)]
pub struct CrateNameEmpty {
#[primary_span]
pub span: Option<Span>,
}

pub struct InvalidCharacterInCrateName<'a> {
pub span: Option<Span>,
pub character: char,
pub crate_name: &'a str,
}

impl crate::SessionDiagnostic<'_> for InvalidCharacterInCrateName<'_> {
fn into_diagnostic(
self,
sess: &Handler,
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name);
if let Some(sp) = self.span {
diag.set_span(sp);
}
diag.set_arg("character", self.character);
diag.set_arg("crate_name", self.crate_name);
diag
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#![feature(map_many_mut)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]

#[macro_use]
extern crate rustc_macros;
Expand Down
Loading