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_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index f72e7389fc606..e7e039d80de1e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -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 {} + /// ``` + /// + /// In here, if you call `visibility` on `T`, it'll panic. query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index c8d4a1bf2c9e7..7ab7870c4642f 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -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 = else { };`, + // the `` 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 `` are dropped + // as well. + // In addition, even though bindings in `` 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 block │ │ + // │ └───────────────────────────┘ │ + // │ ┌───────────────────────────┐ │ + // │ │ Remainder scope of │ │ + // │ │ this let-else statement │ │ + // │ │ ┌─────────────────────┐ │ │ + // │ │ │ scope │ │ │ + // │ │ └─────────────────────┘ │ │ + // │ │ extended temporaries in │ │ + // │ │ 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 │ + // ┌────────▼───────┐ │scope │ + // │Move value into │ └───────┬────────┘ + // │binding x │ │ + // └────────┬───────┘ ┌───────▼────────┐ + // │ │Drop extended │ + // ┌────────▼───────┐ │temporaries in │ + // │Drop temporaries│ │ because │ + // │in y() │ │breaking out of │ + // │because breaking│ │remainder scope │ + // │out of │ └───────┬────────┘ + // │scope │ │ + // └────────┬───────┘ ┌───────▼────────┐ + // │ │Enter ├────────► + // ┌────────▼───────┐ │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 }); @@ -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 }) }, ) 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_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 9ed4faccdb852..a001f87db00c6 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, diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index b779713482e14..b89db79bef8d9 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -126,6 +126,29 @@ 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. + // 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); + visitor.terminating_scopes.insert(els.hir_id.local_id); + visitor.visit_block(els); + // From now on, we continue normally. + 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 +161,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 +483,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 +569,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 +785,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 +812,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/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index aa3e8b9974ecb..46fd7f2d0e493 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -688,7 +688,7 @@ macro_rules! uint_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 011c559b34bdf..600e7cf3a0bed 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -986,12 +986,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 `