From b0cfeec2931cfb3bc9f8b11510684fb2fedee731 Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Fri, 26 Aug 2022 16:06:27 +0200 Subject: [PATCH 01/11] translations(rustc_session): migrates session.rs and config.rs --- compiler/rustc_session/src/config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 8bb3878fbbb47..0018346c72c49 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,6 +1,7 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. +use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -898,7 +899,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.emit_fatal(err); + sess.emit_fatal(TargetDataLayoutParseError { err }); }); let mut ret = CrateConfig::default(); From 329d5014b6a773d819e6cd56d5930a204bed7983 Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Thu, 1 Sep 2022 08:03:47 +0200 Subject: [PATCH 02/11] translations(rustc_session): migrate output.rs --- .../locales/en-US/session.ftl | 10 ++++ compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_session/src/config.rs | 3 +- compiler/rustc_session/src/errors.rs | 51 ++++++++++++++++++- compiler/rustc_session/src/lib.rs | 2 + compiler/rustc_session/src/output.rs | 35 ++++--------- compiler/rustc_session/src/session.rs | 44 ++++++++++++++++ 7 files changed, 119 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index d2a2958f62436..76cae3c81e451 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -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}` diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 4d207fd17fb2d..c36ca11fad6f2 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -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" diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0018346c72c49..8bb3878fbbb47 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,7 +1,6 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. -use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -899,7 +898,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.emit_fatal(TargetDataLayoutParseError { err }); + sess.emit_fatal(err); }); let mut ret = CrateConfig::default(); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 3c93cfab183d2..c6596ff249899 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -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; @@ -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, +} + +pub struct InvalidCharacterInCrateName<'a> { + pub span: Option, + 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 + } +} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 02d5d33c8d5ba..b9b243f6f0840 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -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; diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index e5e6579d75b10..2511bee46afeb 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,5 +1,9 @@ //! Related to out filenames of compilation (e.g. save analysis, binaries). use crate::config::{CrateType, Input, OutputFilenames, OutputType}; +use crate::errors::{ + CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + InvalidCharacterInCrateName, +}; use crate::Session; use rustc_ast as ast; use rustc_span::symbol::sym; @@ -30,11 +34,7 @@ pub fn out_filename( /// read-only file. We should be consistent. pub fn check_file_is_writeable(file: &Path, sess: &Session) { if !is_writeable(file) { - sess.fatal(&format!( - "output file {} is not writeable -- check its \ - permissions", - file.display() - )); + sess.emit_fatal(FileIsNotWriteable { file }); } } @@ -61,11 +61,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { if name.as_str() != s { - let msg = format!( - "`--crate-name` and `#[crate_name]` are \ - required to match, but `{s}` != `{name}`" - ); - sess.span_err(attr.span, &msg); + sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name }); } } return validate(s.clone(), None); @@ -77,11 +73,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Input::File(ref path) = *input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { if s.starts_with('-') { - let msg = format!( - "crate names cannot start with a `-`, but \ - `{s}` has a leading hyphen" - ); - sess.err(&msg); + sess.emit_err(CrateNameInvalid { s }); } else { return validate(s.replace('-', "_"), None); } @@ -94,15 +86,9 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { let mut err_count = 0; { - let mut say = |s: &str| { - match sp { - Some(sp) => sess.span_err(sp, s), - None => sess.err(s), - }; - err_count += 1; - }; if s.is_empty() { - say("crate name must not be empty"); + err_count += 1; + sess.emit_err(CrateNameEmpty { span: sp }); } for c in s.chars() { if c.is_alphanumeric() { @@ -111,7 +97,8 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { if c == '_' { continue; } - say(&format!("invalid character `{c}` in crate name: `{s}`")); + err_count += 1; + sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s }); } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index caf9d582ab099..b1b4101af9e64 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -297,6 +297,8 @@ impl Session { } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn>( &self, sp: S, @@ -305,6 +307,8 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_expectation>( &self, sp: S, @@ -314,6 +318,8 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -323,10 +329,14 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_expectation( &self, msg: impl Into, @@ -335,6 +345,8 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_allow>( &self, sp: S, @@ -343,10 +355,14 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_expect( &self, msg: impl Into, @@ -355,6 +371,8 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err>( &self, sp: S, @@ -363,6 +381,8 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err_with_code>( &self, sp: S, @@ -373,6 +393,8 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err( &self, msg: impl Into, @@ -380,6 +402,8 @@ impl Session { self.parse_sess.struct_err(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err_with_code( &self, msg: impl Into, @@ -388,6 +412,8 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_code( &self, msg: impl Into, @@ -396,6 +422,8 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal>( &self, sp: S, @@ -404,6 +432,8 @@ impl Session { self.diagnostic().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal_with_code>( &self, sp: S, @@ -413,15 +443,21 @@ impl Session { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { self.diagnostic().span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal_with_code>( &self, sp: S, @@ -431,10 +467,14 @@ impl Session { self.diagnostic().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn fatal(&self, msg: impl Into) -> ! { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_or_warn>( &self, is_warning: bool, @@ -448,6 +488,8 @@ impl Session { } } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err>( &self, sp: S, @@ -456,6 +498,8 @@ impl Session { self.diagnostic().span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_with_code>( &self, sp: S, From bae0b21ec488570b0b25d3d70346407b7572e1f7 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Sun, 4 Sep 2022 23:17:43 +0800 Subject: [PATCH 03/11] reorder nesting scopes and declare bindings without drop schedule --- compiler/rustc_mir_build/src/build/block.rs | 117 ++++++++++++++---- .../rustc_mir_build/src/build/matches/mod.rs | 40 +----- compiler/rustc_typeck/src/check/region.rs | 26 ++-- .../async-await/async-await-let-else.stderr | 3 +- .../let-else/let-else-temporary-lifetime.rs | 1 + 5 files changed, 122 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index c8d4a1bf2c9e7..e2cd27d03394f 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -109,13 +109,99 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) ); } + StmtKind::Let { + remainder_scope, + init_scope, + pattern, + initializer: Some(initializer), + lint_level, + else_block: Some(else_block), + } => { + let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); + this.block_context.push(BlockFrame::Statement { ignores_expr_result }); + // 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 else_block_span = this.thir[*else_block].span; + 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 }); @@ -141,27 +227,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 }) }, ) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 505273033a4ca..00c9ee6f6056c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -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) @@ -2274,23 +2274,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { init: &Expr<'tcx>, initializer_span: Span, else_block: BlockId, - visibility_scope: Option, - remainder_scope: region::Scope, - remainder_span: Span, + let_else_scope: ®ion::Scope, pattern: &Pat<'tcx>, - ) -> BlockAnd<()> { + ) -> BlockAnd { 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, @@ -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) } } diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index b779713482e14..594a7e450b8e5 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -126,6 +126,20 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h for (i, statement) in blk.stmts.iter().enumerate() { match statement.kind { + hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => { + // Let-else has a special lexical structure for variables. + let mut prev_cx = visitor.cx; + visitor.enter_scope(Scope { + id: blk.hir_id.local_id, + data: ScopeData::Remainder(FirstStatementIndex::new(i)), + }); + visitor.cx.var_parent = visitor.cx.parent; + visitor.visit_stmt(statement); + mem::swap(&mut prev_cx, &mut visitor.cx); + // We need to back out temporarily and + visitor.visit_block(els); + visitor.cx = prev_cx; + } hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => { // Each declaration introduces a subscope for bindings // introduced by the declaration; this subscope covers a @@ -138,10 +152,10 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; + visitor.visit_stmt(statement) } - hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } - visitor.visit_stmt(statement) } walk_list!(visitor, visit_expr, &blk.expr); } @@ -460,7 +474,6 @@ fn resolve_local<'tcx>( visitor: &mut RegionResolutionVisitor<'tcx>, pat: Option<&'tcx hir::Pat<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>, - els: Option<&'tcx hir::Block<'tcx>>, ) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); @@ -547,9 +560,6 @@ fn resolve_local<'tcx>( if let Some(pat) = pat { visitor.visit_pat(pat); } - if let Some(els) = els { - visitor.visit_block(els); - } /// Returns `true` if `pat` match the `P&` non-terminal. /// @@ -766,7 +776,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // (i.e., `'static`), which means that after `g` returns, it drops, // and all the associated destruction scope rules apply. self.cx.var_parent = None; - resolve_local(self, None, Some(&body.value), None); + resolve_local(self, None, Some(&body.value)); } if body.generator_kind.is_some() { @@ -793,7 +803,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_expr(self, ex); } fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init, l.els) + resolve_local(self, Some(&l.pat), l.init) } } diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr index 4d23e27c426b2..aef3c03a961f9 100644 --- a/src/test/ui/async-await/async-await-let-else.stderr +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -35,7 +35,8 @@ LL | bar2(Rc::new(())).await | | | has type `Rc<()>` which is not `Send` LL | }; - | - `Rc::new(())` is later dropped here +LL | } + | - `Rc::new(())` is later dropped here note: required by a bound in `is_send` --> $DIR/async-await-let-else.rs:16:15 | diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs index 07fcc16e7bbda..8542c3496b045 100644 --- a/src/test/ui/let-else/let-else-temporary-lifetime.rs +++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs @@ -1,4 +1,5 @@ // run-pass +// compile-flags: -Zvalidate-mir #![feature(let_else)] use std::fmt::Display; From 33f596cf93bcfa8e881d612522782ec728cac365 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 5 Sep 2022 14:17:41 +0800 Subject: [PATCH 04/11] add test for #99975 --- src/test/ui/let-else/issue-99975.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/ui/let-else/issue-99975.rs diff --git a/src/test/ui/let-else/issue-99975.rs b/src/test/ui/let-else/issue-99975.rs new file mode 100644 index 0000000000000..80f6355619412 --- /dev/null +++ b/src/test/ui/let-else/issue-99975.rs @@ -0,0 +1,20 @@ +// run-pass +// compile-flags: -C opt-level=3 -Zvalidate-mir + +#![feature(let_else)] + +fn return_result() -> Option { + Some("ok".to_string()) +} + +fn start() -> String { + let Some(content) = return_result() else { + return "none".to_string() + }; + + content +} + +fn main() { + start(); +} From fa93d9dbaf806fdebe42baa66902e57ee5601f15 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 5 Sep 2022 14:24:13 +0800 Subject: [PATCH 05/11] supplement for the missing or incomplete comments --- compiler/rustc_mir_build/src/build/block.rs | 5 ++++- compiler/rustc_typeck/src/check/region.rs | 10 +++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index e2cd27d03394f..d611f02333ff1 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -119,10 +119,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { 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 else_block_span = this.thir[*else_block].span; let dummy_place = this.temp(this.tcx.types.never, else_block_span); let failure_entry = this.cfg.start_new_block(); let failure_block; diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 594a7e450b8e5..46ffafc5a619a 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -128,16 +128,24 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h match statement.kind { hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => { // Let-else has a special lexical structure for variables. + // First we take a checkpoint of the current scope context here. let mut prev_cx = visitor.cx; + visitor.enter_scope(Scope { id: blk.hir_id.local_id, data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; visitor.visit_stmt(statement); + // We need to back out temporarily to the last enclosing scope + // for the `else` block, so that even the temporaries receiving + // extended lifetime will be dropped inside this block. + // We are visiting the `else` block in this order so that + // the sequence of visits agree with the order in the default + // `hir::intravisit` visitor. mem::swap(&mut prev_cx, &mut visitor.cx); - // We need to back out temporarily and visitor.visit_block(els); + // From now on, we continue normally. visitor.cx = prev_cx; } hir::StmtKind::Local(..) | hir::StmtKind::Item(..) => { From f47325992b8ebb9d55f1cd850c3a7630fce3b5ae Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 12 Sep 2022 22:50:52 +0800 Subject: [PATCH 06/11] enclose else block in terminating scope --- compiler/rustc_typeck/src/check/region.rs | 1 + src/test/ui/async-await/async-await-let-else.stderr | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 46ffafc5a619a..b89db79bef8d9 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -144,6 +144,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h // the sequence of visits agree with the order in the default // `hir::intravisit` visitor. mem::swap(&mut prev_cx, &mut visitor.cx); + visitor.terminating_scopes.insert(els.hir_id.local_id); visitor.visit_block(els); // From now on, we continue normally. visitor.cx = prev_cx; diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr index aef3c03a961f9..791091abe353b 100644 --- a/src/test/ui/async-await/async-await-let-else.stderr +++ b/src/test/ui/async-await/async-await-let-else.stderr @@ -35,8 +35,7 @@ LL | bar2(Rc::new(())).await | | | has type `Rc<()>` which is not `Send` LL | }; -LL | } - | - `Rc::new(())` is later dropped here + | - `Rc::new(())` is later dropped here note: required by a bound in `is_send` --> $DIR/async-await-let-else.rs:16:15 | From b96322801e7ea1fa92a07bb06ba42b72d689bd90 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 12 Sep 2022 14:04:11 -0700 Subject: [PATCH 07/11] rustdoc: remove no-op CSS `.search-results .result-name > span` The rule `display: inline-block` was added in 5afa52bc7dee683f25f437dddf338dbc6ad32eb8. The `margin: 0` and `font-weight: normal` were added in c01bd560e2f87a9a960ed071213edd70f73171a8. Both seem to have been added to override class-based rules that were targetted at method sections. See for an example. The selectors that these were meant to override were changed in a8318e420d19c364b1eec33956a86164941f6df4 and 76a3b609d0b93c5d8da5e4e3db37bd03e5cb1c30 to be more specific, so they no longer need to be overridden. --- src/librustdoc/html/static/css/rustdoc.css | 6 ------ src/test/rustdoc-gui/search-result-display.goml | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 72e04decbe3e0..d159b48e37fce 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -987,12 +987,6 @@ so that we can apply CSS-filters to change the arrow color in themes */ padding-right: 1em; } -.search-results .result-name > span { - display: inline-block; - margin: 0; - font-weight: normal; -} - .popover { font-size: 1rem; position: absolute; diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index 54482005fa601..efbbfb925bd3b 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -13,6 +13,9 @@ size: (600, 100) // when computed it's larger. assert-css: (".search-results div.desc", {"width": "566px"}) +// The result set is all on one line. +assert-css: (".search-results .result-name > span", {"display": "inline"}) + // Check that the crate filter `