diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index d05d09a11eacd..ab8874d796df2 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -336,7 +336,7 @@ fn report_inline_asm( } let level = match level { llvm::DiagnosticLevel::Error => Level::Error { lint: false }, - llvm::DiagnosticLevel::Warning => Level::Warning, + llvm::DiagnosticLevel::Warning => Level::Warning(None), llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 02c7c1a435fae..632f07c5c2d80 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1761,7 +1761,7 @@ impl SharedEmitterMain { let mut err = match level { Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(), - Level::Warning => sess.struct_warn(msg), + Level::Warning(_) => sess.struct_warn(msg), Level::Note => sess.struct_note_without_error(msg), _ => bug!("Invalid inline asm diagnostic level"), }; diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 1f270fcf56baa..0fcd61d1e58c3 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -87,7 +87,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType { Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => { AnnotationType::Error } - Level::Warning => AnnotationType::Warning, + Level::Warning(_) => AnnotationType::Warning, Level::Note | Level::OnceNote => AnnotationType::Note, Level::Help => AnnotationType::Help, // FIXME(#59346): Not sure how to map this level diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 00c0ff8bcaf9c..b8545139cecc1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -209,7 +209,7 @@ impl Diagnostic { | Level::Error { .. } | Level::FailureNote => true, - Level::Warning + Level::Warning(_) | Level::Note | Level::OnceNote | Level::Help @@ -222,7 +222,9 @@ impl Diagnostic { &mut self, unstable_to_stable: &FxHashMap, ) { - if let Level::Expect(expectation_id) = &mut self.level { + if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) = + &mut self.level + { if expectation_id.is_stable() { return; } @@ -450,7 +452,7 @@ impl Diagnostic { /// Add a warning attached to this diagnostic. #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] pub fn warn(&mut self, msg: impl Into) -> &mut Self { - self.sub(Level::Warning, msg, MultiSpan::new(), None); + self.sub(Level::Warning(None), msg, MultiSpan::new(), None); self } @@ -462,7 +464,7 @@ impl Diagnostic { sp: S, msg: impl Into, ) -> &mut Self { - self.sub(Level::Warning, msg, sp.into(), None); + self.sub(Level::Warning(None), msg, sp.into(), None); self } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index fff35ac6ac894..d4d1491c16945 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -154,7 +154,7 @@ impl Emitter for JsonEmitter { .into_iter() .map(|mut diag| { if diag.level == crate::Level::Allow { - diag.level = crate::Level::Warning; + diag.level = crate::Level::Warning(None); } FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) } }) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 8b6eba122f8f0..aa4ea82dffb61 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -660,6 +660,23 @@ impl Handler { result } + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. + /// The `id` is used for lint emissions which should also fulfill a lint expectation. + /// + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_span_warn_with_expectation( + &self, + span: impl Into, + msg: impl Into, + id: LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + let mut result = self.struct_warn_with_expectation(msg, id); + result.set_span(span); + result + } + /// Construct a builder at the `Allow` level at the given `span` and with the `msg`. #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] pub fn struct_span_allow( @@ -693,7 +710,21 @@ impl Handler { /// * `is_force_warn` was set in `DiagnosticId::Lint` #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Level::Warning, msg) + DiagnosticBuilder::new(self, Level::Warning(None), msg) + } + + /// Construct a builder at the `Warning` level with the `msg`. The `id` is used for + /// lint emissions which should also fulfill a lint expectation. + /// + /// Attempting to `.emit()` the builder will only emit if either: + /// * `can_emit_warnings` is `true` + /// * `is_force_warn` was set in `DiagnosticId::Lint` + pub fn struct_warn_with_expectation( + &self, + msg: impl Into, + id: LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg) } /// Construct a builder at the `Allow` level with the `msg`. @@ -864,7 +895,7 @@ impl Handler { #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] pub fn span_warn(&self, span: impl Into, msg: impl Into) { - self.emit_diag_at_span(Diagnostic::new(Warning, msg), span); + self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span); } #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)] @@ -874,7 +905,7 @@ impl Handler { msg: impl Into, code: DiagnosticId, ) { - self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span); + self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span); } pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { @@ -928,7 +959,7 @@ impl Handler { } pub fn warn(&self, msg: impl Into) { - let mut db = DiagnosticBuilder::new(self, Warning, msg); + let mut db = DiagnosticBuilder::new(self, Warning(None), msg); db.emit(); } @@ -1033,13 +1064,10 @@ impl Handler { for mut diag in diags.into_iter() { diag.update_unstable_expectation_id(unstable_to_stable); - let stable_id = diag - .level - .get_expectation_id() - .expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`"); - inner.fulfilled_expectations.insert(stable_id); - - (*TRACK_DIAGNOSTICS)(&diag); + // Here the diagnostic is given back to `emit_diagnostic` where it was first + // intercepted. Now it should be processed as usual, since the unstable expectation + // id is now stable. + inner.emit_diagnostic(&mut diag); } } @@ -1089,6 +1117,15 @@ impl HandlerInner { // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option { + // The `LintExpectationId` can be stable or unstable depending on when it was created. + // Diagnostics created before the definition of `HirId`s are unstable and can not yet + // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by + // a stable one by the `LintLevelsBuilder`. + if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() { + self.unstable_expect_diagnostics.push(diagnostic.clone()); + return None; + } + if diagnostic.level == Level::DelayedBug { // FIXME(eddyb) this should check for `has_errors` and stop pushing // once *any* errors were emitted (and truncate `delayed_span_bugs` @@ -1105,7 +1142,12 @@ impl HandlerInner { self.future_breakage_diagnostics.push(diagnostic.clone()); } - if diagnostic.level == Warning + if let Some(expectation_id) = diagnostic.level.get_expectation_id() { + self.suppressed_expected_diag = true; + self.fulfilled_expectations.insert(expectation_id); + } + + if matches!(diagnostic.level, Warning(_)) && !self.flags.can_emit_warnings && !diagnostic.is_force_warn() { @@ -1115,22 +1157,9 @@ impl HandlerInner { return None; } - // The `LintExpectationId` can be stable or unstable depending on when it was created. - // Diagnostics created before the definition of `HirId`s are unstable and can not yet - // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by - // a stable one by the `LintLevelsBuilder`. - if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level { - self.unstable_expect_diagnostics.push(diagnostic.clone()); - return None; - } - (*TRACK_DIAGNOSTICS)(diagnostic); - if let Level::Expect(expectation_id) = diagnostic.level { - self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id); - return None; - } else if diagnostic.level == Allow { + if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) { return None; } @@ -1167,7 +1196,7 @@ impl HandlerInner { self.emitter.emit_diagnostic(&diagnostic); if diagnostic.is_error() { self.deduplicated_err_count += 1; - } else if diagnostic.level == Warning { + } else if let Warning(_) = diagnostic.level { self.deduplicated_warn_count += 1; } } @@ -1220,7 +1249,7 @@ impl HandlerInner { match (errors.len(), warnings.len()) { (0, 0) => return, (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new( - Level::Warning, + Level::Warning(None), DiagnosticMessage::Str(warnings), )), (_, 0) => { @@ -1453,7 +1482,10 @@ pub enum Level { /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called. lint: bool, }, - Warning, + /// This [`LintExpectationId`] is used for expected lint diagnostics, which should + /// also emit a warning due to the `force-warn` flag. In all other cases this should + /// be `None`. + Warning(Option), Note, /// A note that is only emitted once. OnceNote, @@ -1476,7 +1508,7 @@ impl Level { Bug | DelayedBug | Fatal | Error { .. } => { spec.set_fg(Some(Color::Red)).set_intense(true); } - Warning => { + Warning(_) => { spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows)); } Note | OnceNote => { @@ -1495,7 +1527,7 @@ impl Level { match self { Bug | DelayedBug => "error: internal compiler error", Fatal | Error { .. } => "error", - Warning => "warning", + Warning(_) => "warning", Note | OnceNote => "note", Help => "help", FailureNote => "failure-note", @@ -1510,7 +1542,7 @@ impl Level { pub fn get_expectation_id(&self) -> Option { match self { - Level::Expect(id) => Some(*id), + Level::Expect(id) | Level::Warning(Some(id)) => Some(*id), _ => None, } } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index d4407c03d03f5..e7ce9e7f1b705 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -267,7 +267,7 @@ impl ToInternal for Level { fn to_internal(self) -> rustc_errors::Level { match self { Level::Error => rustc_errors::Level::Error { lint: false }, - Level::Warning => rustc_errors::Level::Warning, + Level::Warning => rustc_errors::Level::Warning(None), Level::Note => rustc_errors::Level::Note, Level::Help => rustc_errors::Level::Help, _ => unreachable!("unknown proc_macro::Level variant: {:?}", self), diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 2084494f7719e..eeb66f2d73871 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -324,7 +324,7 @@ impl LintStore { registered_tools: &RegisteredTools, ) { let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name); - if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn { + if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) { struct_span_err!( sess, DUMMY_SP, @@ -375,7 +375,7 @@ impl LintStore { match level { Level::Allow => "-A", Level::Warn => "-W", - Level::ForceWarn => "--force-warn", + Level::ForceWarn(_) => "--force-warn", Level::Deny => "-D", Level::Forbid => "-F", Level::Expect(_) => { diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index dc48ac0a618e7..95e3125045db4 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -19,16 +19,16 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { let lint_expectations = &tcx.lint_levels(()).lint_expectations; for (id, expectation) in lint_expectations { - if !fulfilled_expectations.contains(id) - && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) - { - // This check will always be true, since `lint_expectations` only - // holds stable ids - if let LintExpectationId::Stable { hir_id, .. } = id { + // This check will always be true, since `lint_expectations` only + // holds stable ids + if let LintExpectationId::Stable { hir_id, .. } = id { + if !fulfilled_expectations.contains(&id) + && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) + { emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation); - } else { - unreachable!("at this stage all `LintExpectationId`s are stable"); } + } else { + unreachable!("at this stage all `LintExpectationId`s are stable"); } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 7faac5b5296d4..4773feded12fa 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -117,7 +117,9 @@ impl<'s> LintLevelsBuilder<'s> { }; for id in ids { // ForceWarn and Forbid cannot be overridden - if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) { + if let Some((Level::ForceWarn(_) | Level::Forbid, _)) = + self.current_specs().get(&id) + { continue; } @@ -226,11 +228,18 @@ impl<'s> LintLevelsBuilder<'s> { return; } - if let Level::ForceWarn = old_level { - self.current_specs_mut().insert(id, (old_level, old_src)); - } else { - self.current_specs_mut().insert(id, (level, src)); - } + match (old_level, level) { + // If the new level is an expectation store it in `ForceWarn` + (Level::ForceWarn(_), Level::Expect(expectation_id)) => self + .current_specs_mut() + .insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)), + // Keep `ForceWarn` level but drop the expectation + (Level::ForceWarn(_), _) => { + self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src)) + } + // Set the lint level as normal + _ => self.current_specs_mut().insert(id, (level, src)), + }; } /// Pushes a list of AST lint attributes onto this context. @@ -269,6 +278,7 @@ impl<'s> LintLevelsBuilder<'s> { let level = match Level::from_attr(attr) { None => continue, + // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index); diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 913dc58a10259..cb1c6f4098767 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -162,13 +162,19 @@ pub enum Level { /// /// See RFC 2383. /// - /// The `LintExpectationId` is used to later link a lint emission to the actual + /// The [`LintExpectationId`] is used to later link a lint emission to the actual /// expectation. It can be ignored in most cases. Expect(LintExpectationId), /// The `warn` level will produce a warning if the lint was violated, however the /// compiler will continue with its execution. Warn, - ForceWarn, + /// This lint level is a special case of [`Warn`], that can't be overridden. This is used + /// to ensure that a lint can't be suppressed. This lint level can currently only be set + /// via the console and is therefore session specific. + /// + /// The [`LintExpectationId`] is intended to fulfill expectations marked via the + /// `#[expect]` attribute, that will still be suppressed due to the level. + ForceWarn(Option), /// The `deny` level will produce an error and stop further execution after the lint /// pass is complete. Deny, @@ -184,7 +190,7 @@ impl Level { Level::Allow => "allow", Level::Expect(_) => "expect", Level::Warn => "warn", - Level::ForceWarn => "force-warn", + Level::ForceWarn(_) => "force-warn", Level::Deny => "deny", Level::Forbid => "forbid", } @@ -219,7 +225,7 @@ impl Level { pub fn is_error(self) -> bool { match self { - Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false, + Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn(_) => false, Level::Deny | Level::Forbid => true, } } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index c7c5f56867a5d..215d8decf2a88 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -115,7 +115,7 @@ impl LintLevelSets { // Ensure that we never exceed the `--cap-lints` argument // unless the source is a --force-warn - level = if let LintLevelSource::CommandLine(_, Level::ForceWarn) = src { + level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src { level } else { cmp::min(level, self.lint_cap) @@ -266,7 +266,7 @@ pub fn explain_lint_level_source( Level::Deny => "-D", Level::Forbid => "-F", Level::Allow => "-A", - Level::ForceWarn => "--force-warn", + Level::ForceWarn(_) => "--force-warn", Level::Expect(_) => { unreachable!("the expect level does not have a commandline flag") } @@ -352,8 +352,14 @@ pub fn struct_lint_level<'s, 'd>( // create a `DiagnosticBuilder` and continue as we would for warnings. sess.struct_expect("", expect_id) } - (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""), - (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""), + (Level::ForceWarn(Some(expect_id)), Some(span)) => { + sess.struct_span_warn_with_expectation(span, "", expect_id) + } + (Level::ForceWarn(Some(expect_id)), None) => { + sess.struct_warn_with_expectation("", expect_id) + } + (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""), + (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""), (Level::Deny | Level::Forbid, Some(span)) => { let mut builder = sess.diagnostic().struct_err_lint(""); builder.set_span(span); @@ -398,7 +404,7 @@ pub fn struct_lint_level<'s, 'd>( explain_lint_level_source(lint, level, src, &mut err); let name = lint.name_lower(); - let is_force_warn = matches!(level, Level::ForceWarn); + let is_force_warn = matches!(level, Level::ForceWarn(_)); err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); if let Some(future_incompatible) = future_incompatible { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c4a67006504fd..89d724626ccc0 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1432,7 +1432,7 @@ pub fn get_cmd_lint_options( let mut lint_opts_with_position = vec![]; let mut describe_lints = false; - for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] { + for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] { for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { if lint_name == "help" { describe_lints = true; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 2186456576a34..f1814eebfa6fd 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -287,6 +287,14 @@ impl Session { ) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_span_warn(sp, msg) } + pub fn struct_span_warn_with_expectation>( + &self, + sp: S, + msg: impl Into, + id: lint::LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) + } pub fn struct_span_warn_with_code>( &self, sp: S, @@ -298,6 +306,13 @@ impl Session { pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } + pub fn struct_warn_with_expectation( + &self, + msg: impl Into, + id: lint::LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + self.diagnostic().struct_warn_with_expectation(msg, id) + } pub fn struct_span_allow>( &self, sp: S, diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 95d9c3142dd46..f23980faa0417 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -161,6 +161,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// // update a key, guarding against the key possibly not being set /// let stat = player_stats.entry("attack").or_insert(100); /// *stat += random_stat_buff(); +/// +/// // modify an entry before an insert with in-place mutation +/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] @@ -1211,10 +1214,12 @@ impl BTreeMap { /// /// // count the number of occurrences of letters in the vec /// for x in ["a", "b", "a", "c", "a", "b"] { - /// *count.entry(x).or_insert(0) += 1; + /// count.entry(x).and_modify(|curr| *curr += 1).or_insert(1); /// } /// /// assert_eq!(count["a"], 3); + /// assert_eq!(count["b"], 2); + /// assert_eq!(count["c"], 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V, A> diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index d38fecc45b2fc..192a21f2ffc2d 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -164,6 +164,9 @@ use crate::sys; /// // update a key, guarding against the key possibly not being set /// let stat = player_stats.entry("attack").or_insert(100); /// *stat += random_stat_buff(); +/// +/// // modify an entry before an insert with in-place mutation +/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` /// /// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. @@ -829,8 +832,7 @@ where /// let mut letters = HashMap::new(); /// /// for ch in "a short treatise on fungi".chars() { - /// let counter = letters.entry(ch).or_insert(0); - /// *counter += 1; + /// letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1); /// } /// /// assert_eq!(letters[&'s'], 2); diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index d9467e8fd6bc1..40a3cc6d12cac 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -127,12 +127,18 @@ fn main() { } } + // Cargo doesn't pass RUSTFLAGS to proc_macros: + // https://github.com/rust-lang/cargo/issues/4423 + // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. + // We also declare that the flag is expected, which is mainly needed for + // later stages so that they don't warn about #[cfg(bootstrap)], + // but enabling it for stage 0 too lets any warnings, if they occur, + // occur more early on, e.g. about #[cfg(bootstrap = "foo")]. if stage == "0" { - // Cargo doesn't pass RUSTFLAGS to proc_macros: - // https://github.com/rust-lang/cargo/issues/4423 - // Set `--cfg=bootstrap` explicitly instead. cmd.arg("--cfg=bootstrap"); } + cmd.arg("-Zunstable-options"); + cmd.arg("--check-cfg=values(bootstrap)"); } if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index 83ca8ed932e46..912418fa7d1eb 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -59,39 +59,133 @@ + + - {ptr.pointer->value} + {ptr.pointer->value} - ptr.pointer->value - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->value + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + + - {ptr.pointer->value} + {ptr.pointer->value} + + + ptr.pointer->value + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} - ptr.pointer->value - ptr.pointer->strong - ptr.pointer->weak + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + - {ptr.pointer->data} + {ptr.pointer->data} - ptr.pointer->data - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->data + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + + - {ptr.pointer->data} + {ptr.pointer->data} - ptr.pointer->data - ptr.pointer->strong - ptr.pointer->weak + + ptr.pointer->data + ptr.pointer->strong + ptr.pointer->weak + + + ptr.pointer.pointer->strong + ptr.pointer.pointer->weak + + + + + + {{ len={ptr.pointer.length} }} + + ptr.pointer.length + ptr.pointer.data_ptr->strong + ptr.pointer.data_ptr->weak + + ptr.pointer.length + ($T1*)(((size_t*)ptr.pointer.data_ptr) + 2) + + Borrowed({__0}) Owned({__0}) diff --git a/src/test/debuginfo/rc_arc.rs b/src/test/debuginfo/rc_arc.rs index 8470ace24b845..c05c565d95634 100644 --- a/src/test/debuginfo/rc_arc.rs +++ b/src/test/debuginfo/rc_arc.rs @@ -8,74 +8,138 @@ // gdb-command:run -// gdb-command:print r -// gdb-check:[...]$1 = Rc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} -// gdb-command:print a -// gdb-check:[...]$2 = Arc(strong=2, weak=1) = {value = 42, strong = 2, weak = 1} - +// gdb-command:print rc +// gdb-check:[...]$1 = Rc(strong=11, weak=1) = {value = 111, strong = 11, weak = 1} +// gdb-command:print arc +// gdb-check:[...]$2 = Arc(strong=21, weak=1) = {value = 222, strong = 21, weak = 1} // === LLDB TESTS ================================================================================== // lldb-command:run -// lldb-command:print r -// lldb-check:[...]$0 = strong=2, weak=1 { value = 42 } -// lldb-command:print a -// lldb-check:[...]$1 = strong=2, weak=1 { data = 42 } +// lldb-command:print rc +// lldb-check:[...]$0 = strong=11, weak=1 { value = 111 } +// lldb-command:print arc +// lldb-check:[...]$1 = strong=21, weak=1 { data = 222 } // === CDB TESTS ================================================================================== // cdb-command:g -// cdb-command:dx r,d -// cdb-check:r,d : 42 [Type: alloc::rc::Rc] -// cdb-check: [] [Type: alloc::rc::Rc] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx rc,d +// cdb-check:rc,d : 111 [Type: alloc::rc::Rc] +// cdb-check: [Reference count] : 11 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] + +// cdb-command:dx weak_rc,d +// cdb-check:weak_rc,d : 111 [Type: alloc::rc::Weak] +// cdb-check: [Reference count] : 11 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] + +// cdb-command:dx arc,d +// cdb-check:arc,d : 222 [Type: alloc::sync::Arc] +// cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] + +// cdb-command:dx weak_arc,d +// cdb-check:weak_arc,d : 222 [Type: alloc::sync::Weak] +// cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] + +// cdb-command:dx dyn_rc,d +// cdb-check:dyn_rc,d [Type: alloc::rc::Rc >] +// cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] -// cdb-command:dx r1,d -// cdb-check:r1,d : 42 [Type: alloc::rc::Rc] -// cdb-check: [] [Type: alloc::rc::Rc] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx dyn_rc_weak,d +// cdb-check:dyn_rc_weak,d [Type: alloc::rc::Weak >] +// cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] -// cdb-command:dx w1,d -// cdb-check:w1,d : 42 [Type: alloc::rc::Weak] -// cdb-check: [] [Type: alloc::rc::Weak] -// cdb-check: [Reference count] : 2 [Type: core::cell::Cell] +// cdb-command:dx slice_rc,d +// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc >] +// cdb-check: [Length] : 3 [Type: [...]] +// cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] +// cdb-check: [0] : 1 [Type: u32] +// cdb-check: [1] : 2 [Type: u32] +// cdb-check: [2] : 3 [Type: u32] + +// cdb-command:dx slice_rc_weak,d +// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak >] +// cdb-check: [Length] : 3 [Type: [...]] +// cdb-check: [Reference count] : 41 [Type: core::cell::Cell] +// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] +// cdb-check: [0] : 1 [Type: u32] +// cdb-check: [1] : 2 [Type: u32] +// cdb-check: [2] : 3 [Type: u32] -// cdb-command:dx a,d -// cdb-check:a,d : 42 [Type: alloc::sync::Arc] -// cdb-check: [] [Type: alloc::sync::Arc] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx dyn_arc,d +// cdb-check:dyn_arc,d [Type: alloc::sync::Arc >] +// cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] -// cdb-command:dx a1,d -// cdb-check:a1,d : 42 [Type: alloc::sync::Arc] -// cdb-check: [] [Type: alloc::sync::Arc] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx dyn_arc_weak,d +// cdb-check:dyn_arc_weak,d [Type: alloc::sync::Weak >] +// cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] -// cdb-command:dx w2,d -// cdb-check:w2,d : 42 [Type: alloc::sync::Weak] -// cdb-check: [] [Type: alloc::sync::Weak] -// cdb-check: [Reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-command:dx slice_arc,d +// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc >] +// cdb-check: [Length] : 3 [Type: [...]] +// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [0] : 4 [Type: u32] +// cdb-check: [1] : 5 [Type: u32] +// cdb-check: [2] : 6 [Type: u32] + +// cdb-command:dx slice_arc_weak,d +// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak >] +// cdb-check: [Length] : 3 [Type: [...]] +// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] +// cdb-check: [0] : 4 [Type: u32] +// cdb-check: [1] : 5 [Type: u32] +// cdb-check: [2] : 6 [Type: u32] +use std::fmt::Debug; use std::rc::Rc; use std::sync::Arc; fn main() { - let r = Rc::new(42); - let r1 = Rc::clone(&r); - let w1 = Rc::downgrade(&r); + let rc = Rc::new(111); + inc_ref_count(&rc, 10); + let weak_rc = Rc::downgrade(&rc); + + let arc = Arc::new(222); + inc_ref_count(&arc, 20); + let weak_arc = Arc::downgrade(&arc); + + let dyn_rc: Rc = Rc::new(333); + inc_ref_count(&dyn_rc, 30); + let dyn_rc_weak = Rc::downgrade(&dyn_rc); + + let slice_rc: Rc<[u32]> = Rc::from(vec![1, 2, 3]); + inc_ref_count(&slice_rc, 40); + let slice_rc_weak = Rc::downgrade(&slice_rc); - let a = Arc::new(42); - let a1 = Arc::clone(&a); - let w2 = Arc::downgrade(&a); + let dyn_arc: Arc = Arc::new(444); + inc_ref_count(&dyn_arc, 50); + let dyn_arc_weak = Arc::downgrade(&dyn_arc); + + let slice_arc: Arc<[u32]> = Arc::from(vec![4, 5, 6]); + inc_ref_count(&slice_arc, 60); + let slice_arc_weak = Arc::downgrade(&slice_arc); zzz(); // #break } -fn zzz() { () } +fn inc_ref_count(rc: &T, count: usize) { + for _ in 0..count { + std::mem::forget(rc.clone()); + } +} + +fn zzz() { + () +} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs new file mode 100644 index 0000000000000..a3c3933d70038 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.rs @@ -0,0 +1,48 @@ +// compile-flags: --force-warn while_true +// compile-flags: --force-warn unused_variables +// compile-flags: --force-warn unused_mut +// check-pass + +#![feature(lint_reasons)] + +fn expect_early_pass_lint() { + #[expect(while_true)] + while true { + //~^ WARNING denote infinite loops with `loop { ... }` [while_true] + //~| NOTE requested on the command line with `--force-warn while-true` + //~| HELP use `loop` + println!("I never stop") + } +} + +#[expect(unused_variables, reason="")] +fn check_specific_lint() { + let x = 2; + //~^ WARNING unused variable: `x` [unused_variables] + //~| NOTE requested on the command line with `--force-warn unused-variables` + //~| HELP if this is intentional, prefix it with an underscore +} + +#[expect(unused)] +fn check_multiple_lints_with_lint_group() { + let fox_name = "Sir Nibbles"; + //~^ WARNING unused variable: `fox_name` [unused_variables] + //~| HELP if this is intentional, prefix it with an underscore + + let mut what_does_the_fox_say = "*ding* *deng* *dung*"; + //~^ WARNING variable does not need to be mutable [unused_mut] + //~| NOTE requested on the command line with `--force-warn unused-mut` + //~| HELP remove this `mut` + + println!("The fox says: {what_does_the_fox_say}"); +} + +#[allow(unused_variables)] +fn check_expect_overrides_allow_lint_level() { + #[expect(unused_variables)] + let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; + //~^ WARNING unused variable: `this_should_fulfill_the_expectation` [unused_variables] + //~| HELP if this is intentional, prefix it with an underscore +} + +fn main() {} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr new file mode 100644 index 0000000000000..06befcbb5117e --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_fulfilled.stderr @@ -0,0 +1,40 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/force_warn_expected_lints_fulfilled.rs:10:5 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: requested on the command line with `--force-warn while-true` + +warning: unused variable: `x` + --> $DIR/force_warn_expected_lints_fulfilled.rs:20:9 + | +LL | let x = 2; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | + = note: requested on the command line with `--force-warn unused-variables` + +warning: unused variable: `fox_name` + --> $DIR/force_warn_expected_lints_fulfilled.rs:28:9 + | +LL | let fox_name = "Sir Nibbles"; + | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_fox_name` + +warning: unused variable: `this_should_fulfill_the_expectation` + --> $DIR/force_warn_expected_lints_fulfilled.rs:43:9 + | +LL | let this_should_fulfill_the_expectation = "The `#[allow]` has no power here"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_fulfill_the_expectation` + +warning: variable does not need to be mutable + --> $DIR/force_warn_expected_lints_fulfilled.rs:32:9 + | +LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*"; + | ----^^^^^^^^^^^^^^^^^^^^^ + | | + | help: remove this `mut` + | + = note: requested on the command line with `--force-warn unused-mut` + +warning: 5 warnings emitted + diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs new file mode 100644 index 0000000000000..080e300232b03 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.rs @@ -0,0 +1,49 @@ +// compile-flags: --force-warn while_true +// compile-flags: --force-warn unused_variables +// compile-flags: --force-warn unused_mut +// check-pass + +#![feature(lint_reasons)] + +fn expect_early_pass_lint(terminate: bool) { + #[expect(while_true)] + //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] + //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default + while !terminate { + println!("Do you know what a spin lock is?") + } +} + +#[expect(unused_variables, reason="")] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +//~| NOTE +fn check_specific_lint() { + let _x = 2; +} + +#[expect(unused)] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +fn check_multiple_lints_with_lint_group() { + let fox_name = "Sir Nibbles"; + + let what_does_the_fox_say = "*ding* *deng* *dung*"; + + println!("The fox says: {what_does_the_fox_say}"); + println!("~ {fox_name}") +} + + +#[expect(unused)] +//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations] +fn check_overridden_expectation_lint_level() { + #[allow(unused_variables)] + let this_should_not_fulfill_the_expectation = "maybe"; + //~^ WARNING unused variable: `this_should_not_fulfill_the_expectation` [unused_variables] + //~| NOTE requested on the command line with `--force-warn unused-variables` + //~| HELP if this is intentional, prefix it with an underscore +} + +fn main() { + check_multiple_lints_with_lint_group(); + check_overridden_expectation_lint_level(); +} diff --git a/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr new file mode 100644 index 0000000000000..c74fabe27dc87 --- /dev/null +++ b/src/test/ui/lint/rfc-2383-lint-reason/force_warn_expected_lints_unfulfilled.stderr @@ -0,0 +1,38 @@ +warning: unused variable: `this_should_not_fulfill_the_expectation` + --> $DIR/force_warn_expected_lints_unfulfilled.rs:40:9 + | +LL | let this_should_not_fulfill_the_expectation = "maybe"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_not_fulfill_the_expectation` + | + = note: requested on the command line with `--force-warn unused-variables` + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:9:14 + | +LL | #[expect(while_true)] + | ^^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:17:10 + | +LL | #[expect(unused_variables, reason="")] + | ^^^^^^^^^^^^^^^^ + | + = note: + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:24:10 + | +LL | #[expect(unused)] + | ^^^^^^ + +warning: this lint expectation is unfulfilled + --> $DIR/force_warn_expected_lints_unfulfilled.rs:36:10 + | +LL | #[expect(unused)] + | ^^^^^^ + +warning: 5 warnings emitted + diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index a0f71c2b8ba93..23db542191036 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -433,7 +433,7 @@ mod tests { Some(ignore_list), ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); - let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); + let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span)); emitter.emit_diagnostic(&non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(can_reset_errors.load(Ordering::Acquire), true); @@ -457,7 +457,7 @@ mod tests { None, ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); - let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); + let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span)); emitter.emit_diagnostic(&non_fatal_diagnostic); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); @@ -494,8 +494,8 @@ mod tests { ); let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22))); - let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); - let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); + let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span)); + let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); emitter.emit_diagnostic(&bar_diagnostic); emitter.emit_diagnostic(&foo_diagnostic);