diff --git a/RELEASES.md b/RELEASES.md index b14cc499b46d0..0dffe931e6eb1 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,88 @@ +Version 1.92.0 (2025-12-11) +========================== + + + +Language +-------- +- [Document `MaybeUninit` representation and validity](https://github.com/rust-lang/rust/pull/140463) +- [Allow `&raw [mut | const]` for union field in safe code](https://github.com/rust-lang/rust/pull/141469) +- [Prefer item bounds of associated types over where-bounds for auto-traits and `Sized`](https://github.com/rust-lang/rust/pull/144064) +- [Do not materialize `X` in `[X; 0]` when `X` is unsizing a const](https://github.com/rust-lang/rust/pull/145277) +- [Support combining `#[track_caller]` and `#[no_mangle]` (requires every declaration specifying `#[track_caller]` as well)](https://github.com/rust-lang/rust/pull/145724) +- [Make never type lints `never_type_fallback_flowing_into_unsafe` and `dependency_on_unit_never_type_fallback` deny-by-default](https://github.com/rust-lang/rust/pull/146167) +- [Allow specifying multiple bounds for same associated item, except in trait objects](https://github.com/rust-lang/rust/pull/146593) +- [Slightly strengthen higher-ranked region handling in coherence](https://github.com/rust-lang/rust/pull/146725) +- [The `unused_must_use` lint no longer warns on `Result<(), Uninhabited>` (for instance, `Result<(), !>`), or `ControlFlow`](https://github.com/rust-lang/rust/pull/147382). This avoids having to check for an error that can never happen. + + + +Compiler +-------- +- [Make `mips64el-unknown-linux-muslabi64` link dynamically](https://github.com/rust-lang/rust/pull/146858) +- [Remove current code for embedding command-line args in PDB](https://github.com/rust-lang/rust/pull/147022) + Command-line information is typically not needed by debugging tools, and the removed code + was causing problems for incremental builds even on targets that don't use PDB debuginfo. + + + +Libraries +--------- +- [Specialize `Iterator::eq{_by}` for `TrustedLen` iterators](https://github.com/rust-lang/rust/pull/137122) +- [Simplify `Extend` for tuples](https://github.com/rust-lang/rust/pull/138799) +- [Added details to `Debug` for `EncodeWide`](https://github.com/rust-lang/rust/pull/140153). +- [`iter::Repeat::last`](https://github.com/rust-lang/rust/pull/147258) and [`count`](https://github.com/rust-lang/rust/pull/146410) will now panic, rather than looping infinitely. + + + +Stabilized APIs +--------------- + +- [`NonZero::div_ceil`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.div_ceil) +- [`Location::file_as_c_str`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file_as_c_str) +- [`RwLockWriteGuard::downgrade`](https://doc.rust-lang.org/stable/std/sync/struct.RwLockWriteGuard.html#method.downgrade) +- [`Box::new_zeroed`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed) +- [`Box::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.new_zeroed_slice) +- [`Rc::new_zeroed`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed) +- [`Rc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.new_zeroed_slice) +- [`Arc::new_zeroed`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed) +- [`Arc::new_zeroed_slice`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.new_zeroed_slice) +- [`btree_map::Entry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.insert_entry) +- [`btree_map::VacantEntry::insert_entry`](https://doc.rust-lang.org/stable/std/collections/btree_map/struct.VacantEntry.html#method.insert_entry) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CGroup%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CLiteral%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CPunct%3E-for-TokenStream) +- [`impl Extend for proc_macro::TokenStream`](https://doc.rust-lang.org/stable/proc_macro/struct.TokenStream.html#impl-Extend%3CIdent%3E-for-TokenStream) + +These previously stable APIs are now stable in const contexts: + +- [`<[_]>::rotate_left`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_left) +- [`<[_]>::rotate_right`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.rotate_right) + + + +Cargo +----- +- [Added a new chapter](https://github.com/rust-lang/cargo/issues/16119) to the Cargo book, ["Optimizing Build Performance"](https://doc.rust-lang.org/stable/cargo/guide/build-performance.html). + + + +Rustdoc +----- +- [If a trait item appears in rustdoc search, hide the corresponding impl items](https://github.com/rust-lang/rust/pull/145898). Previously a search for "last" would show both `Iterator::last` as well as impl methods like `std::vec::IntoIter::last`. Now these impl methods will be hidden, freeing up space for inherent methods like `BTreeSet::last`. +- [Relax rules for identifiers in search](https://github.com/rust-lang/rust/pull/147860). Previously you could only search for identifiers that were valid in rust code, now searches only need to be valid as part of an identifier. For example, you can now perform a search that starts with a digit. + + + +Compatibility Notes +------------------- +* [Fix backtraces with `-C panic=abort` on Linux by generating unwind tables by default](https://github.com/rust-lang/rust/pull/143613). Build with `-C force-unwind-tables=no` to keep omitting unwind tables. +- As part of the larger effort refactoring compiler built-in attributes and their diagnostics, [the future-compatibility lint `invalid_macro_export_arguments` is upgraded to deny-by-default and will be reported in dependencies too.](https://github.com/rust-lang/rust/pull/143857) +- [Update the minimum external LLVM to 20](https://github.com/rust-lang/rust/pull/145071) +- [Prevent downstream `impl DerefMut for Pin`](https://github.com/rust-lang/rust/pull/145608) +- [Don't apply temporary lifetime extension rules to the arguments of non-extended `pin!` and formatting macros](https://github.com/rust-lang/rust/pull/145838) + + Version 1.91.1 (2025-11-10) =========================== diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index e6e88eff2d5bc..0e7db7c9503cb 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -44,6 +44,7 @@ use hir::{BodyId, HirId}; use rustc_abi::ExternAbi; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::{Asyncness, ResolverAstLowering}; @@ -87,6 +88,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl); match sig_id { Ok(sig_id) => { + self.add_inline_attribute_if_needed(span); + let is_method = self.is_method(sig_id, span); let (param_count, c_variadic) = self.param_count(sig_id); let decl = self.lower_delegation_decl(sig_id, param_count, c_variadic, span); @@ -100,6 +103,31 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn add_inline_attribute_if_needed(&mut self, span: Span) { + const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; + let create_inline_attr_slice = + || [hir::Attribute::Parsed(AttributeKind::Inline(InlineAttr::Hint, span))]; + + let new_attributes = match self.attrs.get(&PARENT_ID) { + Some(attrs) => { + // Check if reuse already specifies any inline attribute, if so, do nothing + if attrs + .iter() + .any(|a| matches!(a, hir::Attribute::Parsed(AttributeKind::Inline(..)))) + { + return; + } + + self.arena.alloc_from_iter( + attrs.into_iter().map(|a| a.clone()).chain(create_inline_attr_slice()), + ) + } + None => self.arena.alloc_from_iter(create_inline_attr_slice()), + }; + + self.attrs.insert(PARENT_ID, new_attributes); + } + fn get_delegation_sig_id( &self, item_id: NodeId, diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index bd228315b2c95..490e28ed64c5d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -2,16 +2,16 @@ use std::convert::identity; use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; -use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; +use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token}; use rustc_errors::{Applicability, PResult}; use rustc_feature::{AttrSuggestionStyle, AttributeTemplate, Features, template}; use rustc_hir::attrs::CfgEntry; +use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrPath, RustcVersion}; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; use rustc_session::config::ExpectedValues; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::{ParseSess, feature_err}; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; @@ -23,10 +23,7 @@ use crate::session_diagnostics::{ AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, ParsedDescription, }; -use crate::{ - AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, - try_gate_cfg, -}; +use crate::{AttributeParser, fluent_generated, parse_version, session_diagnostics, try_gate_cfg}; pub const CFG_TEMPLATE: AttributeTemplate = template!( List: &["predicate"], @@ -195,43 +192,46 @@ fn parse_name_value( } }; - Ok(CfgEntry::NameValue { name, name_span, value, span }) + match cx.sess.psess.check_config.expecteds.get(&name) { + Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => cx + .emit_lint( + UNEXPECTED_CFGS, + AttributeLintKind::UnexpectedCfgValue((name, name_span), value), + span, + ), + None if cx.sess.psess.check_config.exhaustive_names => cx.emit_lint( + UNEXPECTED_CFGS, + AttributeLintKind::UnexpectedCfgName((name, name_span), value), + span, + ), + _ => { /* not unexpected */ } + } + + Ok(CfgEntry::NameValue { name, value: value.map(|(v, _)| v), span }) } -pub fn eval_config_entry( - sess: &Session, - cfg_entry: &CfgEntry, - id: NodeId, - emit_lints: ShouldEmit, -) -> EvalConfigResult { +pub fn eval_config_entry(sess: &Session, cfg_entry: &CfgEntry) -> EvalConfigResult { match cfg_entry { CfgEntry::All(subs, ..) => { - let mut all = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, emit_lints); - // We cannot short-circuit because `eval_config_entry` emits some lints + let res = eval_config_entry(sess, sub); if !res.as_bool() { - all.get_or_insert(res); + return res; } } - all.unwrap_or_else(|| EvalConfigResult::True) + EvalConfigResult::True } CfgEntry::Any(subs, span) => { - let mut any = None; for sub in subs { - let res = eval_config_entry(sess, sub, id, emit_lints); - // We cannot short-circuit because `eval_config_entry` emits some lints + let res = eval_config_entry(sess, sub); if res.as_bool() { - any.get_or_insert(res); + return res; } } - any.unwrap_or_else(|| EvalConfigResult::False { - reason: cfg_entry.clone(), - reason_span: *span, - }) + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } CfgEntry::Not(sub, span) => { - if eval_config_entry(sess, sub, id, emit_lints).as_bool() { + if eval_config_entry(sess, sub).as_bool() { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } else { EvalConfigResult::True @@ -244,32 +244,8 @@ pub fn eval_config_entry( EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } } } - CfgEntry::NameValue { name, name_span, value, span } => { - if let ShouldEmit::ErrorsAndLints = emit_lints { - match sess.psess.check_config.expecteds.get(name) { - Some(ExpectedValues::Some(values)) - if !values.contains(&value.map(|(v, _)| v)) => - { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), - ); - } - None if sess.psess.check_config.exhaustive_names => { - id.emit_span_lint( - sess, - UNEXPECTED_CFGS, - *span, - BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), - ); - } - _ => { /* not unexpected */ } - } - } - - if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { + CfgEntry::NameValue { name, value, span } => { + if sess.psess.config.contains(&(*name, *value)) { EvalConfigResult::True } else { EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs index 70228d1e15101..adae3fa635f43 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -2,6 +2,7 @@ use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Nod use rustc_ast_pretty::pprust; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; use rustc_hir::RustcVersion; +use rustc_hir::lints::AttributeLintKind; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_session::lint::builtin::UNEXPECTED_CFGS; @@ -51,10 +52,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgValue( + BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), + )), ); } None if sess.psess.check_config.exhaustive_names => { @@ -62,10 +63,10 @@ pub fn cfg_matches( sess, UNEXPECTED_CFGS, cfg.span, - BuiltinLintDiag::UnexpectedCfgName( + BuiltinLintDiag::AttributeLint(AttributeLintKind::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), + )), ); } _ => { /* not unexpected */ } diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index b24e3065622d2..7bc9080ba0229 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -26,13 +26,7 @@ pub(crate) fn expand_cfg( ExpandResult::Ready(match parse_cfg(cx, sp, tts) { Ok(cfg) => { - let matches_cfg = attr::eval_config_entry( - cx.sess, - &cfg, - cx.current_expansion.lint_node_id, - ShouldEmit::ErrorsAndLints, - ) - .as_bool(); + let matches_cfg = attr::eval_config_entry(cx.sess, &cfg).as_bool(); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index b77a121ca0b95..dc8077b2a1ffb 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,7 +1,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ - CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select, + CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select, }; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_span::{Ident, Span, sym}; @@ -10,21 +10,13 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; /// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { - let mut result = None; for (cfg, tt, arm_span) in branches.reachable { - if let EvalConfigResult::True = attr::eval_config_entry( - &ecx.sess, - &cfg, - ecx.current_expansion.lint_node_id, - ShouldEmit::ErrorsAndLints, - ) { - // FIXME(#149215) Ideally we should short-circuit here, but `eval_config_entry` currently emits lints so we cannot do this yet. - result.get_or_insert((tt, arm_span)); + if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) { + return Some((tt, arm_span)); } } - let wildcard = branches.wildcard.map(|(_, tt, span)| (tt, span)); - result.or(wildcard) + branches.wildcard.map(|(_, tt, span)| (tt, span)) } pub(super) fn expand_cfg_select<'cx>( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d35c3b6bb189e..70db6794742d0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -13,8 +13,7 @@ use find_msvc_tools; use itertools::Itertools; use regex::Regex; use rustc_arena::TypedArena; -use rustc_ast::CRATE_NODE_ID; -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_attr_parsing::eval_config_entry; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -3029,9 +3028,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() - } + Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(), None => true, } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 0b3ac472e0e83..492c845df1710 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -163,10 +163,7 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec .iter() .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) .take_while(|attr| { - !is_cfg(attr) - || strip_unconfigured - .cfg_true(attr, strip_unconfigured.lint_node_id, ShouldEmit::Nothing) - .as_bool() + !is_cfg(attr) || strip_unconfigured.cfg_true(attr, ShouldEmit::Nothing).as_bool() }) .collect() } @@ -309,14 +306,7 @@ impl<'a> StripUnconfigured<'a> { ); } - if !attr::eval_config_entry( - self.sess, - &cfg_predicate, - ast::CRATE_NODE_ID, - ShouldEmit::ErrorsAndLints, - ) - .as_bool() - { + if !attr::eval_config_entry(self.sess, &cfg_predicate).as_bool() { return vec![trace_attr]; } @@ -400,23 +390,17 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| { - !is_cfg(attr) - || self.cfg_true(attr, self.lint_node_id, ShouldEmit::ErrorsAndLints).as_bool() - }) + attrs + .iter() + .all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool()) } - pub(crate) fn cfg_true( - &self, - attr: &Attribute, - node: NodeId, - emit_errors: ShouldEmit, - ) -> EvalConfigResult { + pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult { let Some(cfg) = AttributeParser::parse_single( self.sess, attr, attr.span, - node, + self.lint_node_id, self.features, emit_errors, parse_cfg, @@ -426,7 +410,7 @@ impl<'a> StripUnconfigured<'a> { return EvalConfigResult::True; }; - eval_config_entry(self.sess, &cfg, self.lint_node_id, emit_errors) + eval_config_entry(self.sess, &cfg) } /// If attributes are not allowed on expressions, emit an error for `attr` diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 20fb321307ac5..90563b21d2e80 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2213,7 +2213,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, node.node_id(), ShouldEmit::ErrorsAndLints); + let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index d3cc1dd6cf751..aff79d0558387 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -190,7 +190,7 @@ pub enum CfgEntry { Any(ThinVec, Span), Not(Box, Span), Bool(bool, Span), - NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span }, + NameValue { name: Symbol, value: Option, span: Span }, Version(Option, Span), } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4520dd515885e..a31c2bbb8d6b2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2191,7 +2191,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); - } else if adt_kind != AdtKind::Union && !remaining_fields.is_empty() { + } else if adt_kind != AdtKind::Union + && !remaining_fields.is_empty() + //~ non_exhaustive already reported, which will only happen for extern modules + && !variant.field_list_has_applicable_non_exhaustive() + { debug!(?remaining_fields); let private_fields: Vec<&ty::FieldDef> = variant .fields diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index bc1c246b8f03a..0553bc95caa29 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -416,6 +416,8 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreign function interfaces + lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance .note = this is dangerous because dereferencing the resulting pointer is undefined behavior .note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index ff364e5f814ab..589594a3ec5e6 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -169,12 +169,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::UnexpectedCfgName(name, value) => { - check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag); - } - BuiltinLintDiag::UnexpectedCfgValue(name, value) => { - check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag); - } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { @@ -310,8 +304,8 @@ pub fn decorate_builtin_lint( } pub fn decorate_attribute_lint( - _sess: &Session, - _tcx: Option>, + sess: &Session, + tcx: Option>, kind: &AttributeLintKind, diag: &mut Diag<'_, ()>, ) { @@ -367,5 +361,11 @@ pub fn decorate_attribute_lint( suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }, } .decorate_lint(diag), + &AttributeLintKind::UnexpectedCfgName(name, value) => { + check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag) + } + &AttributeLintKind::UnexpectedCfgValue(name, value) => { + check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag) + } } } diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 9e38ea6b685bd..38094c67c34a0 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -669,7 +669,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } - ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"), + ty::UnsafeBinder(_) => { + FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None } + } ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..) diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 19ba27a27eafe..376310838cc74 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -636,8 +636,6 @@ pub enum BuiltinLintDiag { }, BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), - UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), - UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. @@ -733,6 +731,8 @@ pub enum AttributeLintKind { attribute_name_span: Span, sugg_spans: (Span, Span), }, + UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), + UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), } pub type RegisteredTools = FxIndexSet; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 250657bc6806b..e08460c3d4c9a 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -2,8 +2,7 @@ use std::ops::ControlFlow; use std::path::{Path, PathBuf}; use rustc_abi::ExternAbi; -use rustc_ast::CRATE_NODE_ID; -use rustc_attr_parsing::{ShouldEmit, eval_config_entry}; +use rustc_attr_parsing::eval_config_entry; use rustc_data_structures::fx::FxHashSet; use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType}; use rustc_hir::find_attr; @@ -188,9 +187,7 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => { - eval_config_entry(sess, cfg, CRATE_NODE_ID, ShouldEmit::ErrorsAndLints).as_bool() - } + Some(ref cfg) => eval_config_entry(sess, cfg).as_bool(), None => true, } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 33c111708e366..a675c62ddf705 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3070,7 +3070,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } - let item_was = if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + let item_was = if let CfgEntry::NameValue { value: Some(feature), .. } = cfg.0 { errors::ItemWas::BehindFeature { feature, span: cfg.1 } } else { errors::ItemWas::CfgOut { span: cfg.1 } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 8b3e943b4ccd0..d14d0ad2f0ea6 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1324,7 +1324,7 @@ impl Read for &File { /// /// # Platform-specific behavior /// - /// This function currently returns `true` on Unix an `false` on Windows. + /// This function currently returns `true` on Unix and `false` on Windows. /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior @@ -1385,7 +1385,7 @@ impl Write for &File { /// /// # Platform-specific behavior /// - /// This function currently returns `true` on Unix an `false` on Windows. + /// This function currently returns `true` on Unix and `false` on Windows. /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 09c98bd7c88b4..a699cd23fb607 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3,6 +3,9 @@ //! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules. //! However, this contains ~all test parts we expect people to be able to build and run locally. +// (This file should be split up, but having tidy block all changes is not helpful.) +// ignore-tidy-filelength + use std::collections::HashSet; use std::env::split_paths; use std::ffi::{OsStr, OsString}; @@ -17,6 +20,7 @@ use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; +use crate::core::build_steps::test::compiletest::CompiletestMode; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, @@ -39,6 +43,8 @@ use crate::utils::helpers::{ use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify}; +mod compiletest; + /// Runs `cargo test` on various internal tools used by bootstrap. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CrateBootstrap { @@ -1085,7 +1091,7 @@ impl Step for RustdocJSNotStd { builder.ensure(Compiletest { test_compiler: self.compiler, target: self.target, - mode: "rustdoc-js", + mode: CompiletestMode::RustdocJs, suite: "rustdoc-js", path: "tests/rustdoc-js", compare_mode: None, @@ -1478,7 +1484,7 @@ macro_rules! test { builder.ensure(Compiletest { test_compiler: self.test_compiler, target: self.target, - mode: $mode, + mode: const { $mode }, suite: $suite, path: $path, compare_mode: (const { @@ -1493,34 +1499,39 @@ macro_rules! test { }; } -test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true }); +test!(Ui { path: "tests/ui", mode: CompiletestMode::Ui, suite: "ui", default: true }); -test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true }); +test!(Crashes { + path: "tests/crashes", + mode: CompiletestMode::Crashes, + suite: "crashes", + default: true, +}); test!(CodegenLlvm { path: "tests/codegen-llvm", - mode: "codegen", + mode: CompiletestMode::Codegen, suite: "codegen-llvm", default: true }); test!(CodegenUnits { path: "tests/codegen-units", - mode: "codegen-units", + mode: CompiletestMode::CodegenUnits, suite: "codegen-units", default: true, }); test!(Incremental { path: "tests/incremental", - mode: "incremental", + mode: CompiletestMode::Incremental, suite: "incremental", default: true, }); test!(Debuginfo { path: "tests/debuginfo", - mode: "debuginfo", + mode: CompiletestMode::Debuginfo, suite: "debuginfo", default: true, compare_mode: Some("split-dwarf"), @@ -1528,7 +1539,7 @@ test!(Debuginfo { test!(UiFullDeps { path: "tests/ui-fulldeps", - mode: "ui", + mode: CompiletestMode::Ui, suite: "ui-fulldeps", default: true, IS_HOST: true, @@ -1536,14 +1547,14 @@ test!(UiFullDeps { test!(Rustdoc { path: "tests/rustdoc", - mode: "rustdoc", + mode: CompiletestMode::Rustdoc, suite: "rustdoc", default: true, IS_HOST: true, }); test!(RustdocUi { path: "tests/rustdoc-ui", - mode: "ui", + mode: CompiletestMode::Ui, suite: "rustdoc-ui", default: true, IS_HOST: true, @@ -1551,7 +1562,7 @@ test!(RustdocUi { test!(RustdocJson { path: "tests/rustdoc-json", - mode: "rustdoc-json", + mode: CompiletestMode::RustdocJson, suite: "rustdoc-json", default: true, IS_HOST: true, @@ -1559,40 +1570,46 @@ test!(RustdocJson { test!(Pretty { path: "tests/pretty", - mode: "pretty", + mode: CompiletestMode::Pretty, suite: "pretty", default: true, IS_HOST: true, }); -test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true }); +test!(RunMake { + path: "tests/run-make", + mode: CompiletestMode::RunMake, + suite: "run-make", + default: true, +}); test!(RunMakeCargo { path: "tests/run-make-cargo", - mode: "run-make", + mode: CompiletestMode::RunMake, suite: "run-make-cargo", default: true }); test!(AssemblyLlvm { path: "tests/assembly-llvm", - mode: "assembly", + mode: CompiletestMode::Assembly, suite: "assembly-llvm", default: true }); /// Runs the coverage test suite at `tests/coverage` in some or all of the /// coverage test modes. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Coverage { pub compiler: Compiler, pub target: TargetSelection, - pub mode: &'static str, + pub(crate) mode: CompiletestMode, } impl Coverage { const PATH: &'static str = "tests/coverage"; const SUITE: &'static str = "coverage"; - const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"]; + const ALL_MODES: &[CompiletestMode] = + &[CompiletestMode::CoverageMap, CompiletestMode::CoverageRun]; } impl Step for Coverage { @@ -1608,7 +1625,7 @@ impl Step for Coverage { // - `./x test coverage-run -- tests/coverage/trivial.rs` run = run.suite_path(Self::PATH); for mode in Self::ALL_MODES { - run = run.alias(mode); + run = run.alias(mode.as_str()); } run } @@ -1631,15 +1648,15 @@ impl Step for Coverage { for path in &run.paths { match path { PathSet::Set(_) => { - for mode in Self::ALL_MODES { - if path.assert_single_path().path == Path::new(mode) { + for &mode in Self::ALL_MODES { + if path.assert_single_path().path == Path::new(mode.as_str()) { modes.push(mode); break; } } } PathSet::Suite(_) => { - modes.extend(Self::ALL_MODES); + modes.extend_from_slice(Self::ALL_MODES); break; } } @@ -1647,7 +1664,9 @@ impl Step for Coverage { // Skip any modes that were explicitly skipped/excluded on the command-line. // FIXME(Zalathar): Integrate this into central skip handling somehow? - modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode))); + modes.retain(|mode| { + !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode.as_str())) + }); // FIXME(Zalathar): Make these commands skip all coverage tests, as expected: // - `./x test --skip=tests` @@ -1678,7 +1697,7 @@ impl Step for Coverage { test!(CoverageRunRustdoc { path: "tests/coverage-run-rustdoc", - mode: "coverage-run", + mode: CompiletestMode::CoverageRun, suite: "coverage-run-rustdoc", default: true, IS_HOST: true, @@ -1712,7 +1731,7 @@ impl Step for MirOpt { builder.ensure(Compiletest { test_compiler: self.compiler, target, - mode: "mir-opt", + mode: CompiletestMode::MirOpt, suite: "mir-opt", path: "tests/mir-opt", compare_mode: None, @@ -1755,7 +1774,7 @@ struct Compiletest { /// The compiler that we're testing. test_compiler: Compiler, target: TargetSelection, - mode: &'static str, + mode: CompiletestMode, suite: &'static str, path: &'static str, compare_mode: Option<&'static str>, @@ -1791,7 +1810,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let suite_path = self.path; // Skip codegen tests if they aren't enabled in configuration. - if !builder.config.codegen_tests && mode == "codegen" { + if !builder.config.codegen_tests && mode == CompiletestMode::Codegen { return; } @@ -1829,7 +1848,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the target, }); } - if mode == "run-make" { + if mode == CompiletestMode::RunMake { builder.tool_exe(Tool::RunMakeSupport); } @@ -1886,7 +1905,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // suites, `run-make` and `run-make-cargo`. That way, contributors who do not need to run // the `run-make` tests that need in-tree cargo do not need to spend time building in-tree // cargo. - if mode == "run-make" { + if mode == CompiletestMode::RunMake { // We need to pass the compiler that was used to compile run-make-support, // because we have to use the same compiler to compile rmake.rs recipes. let stage0_rustc_path = builder.compiler(0, test_compiler.host); @@ -1910,17 +1929,18 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" - || mode == "run-make" - || (mode == "ui" && is_rustdoc) - || mode == "rustdoc-js" - || mode == "rustdoc-json" - || suite == "coverage-run-rustdoc" + if matches!( + mode, + CompiletestMode::RunMake + | CompiletestMode::Rustdoc + | CompiletestMode::RustdocJs + | CompiletestMode::RustdocJson + ) || matches!(suite, "rustdoc-ui" | "coverage-run-rustdoc") { cmd.arg("--rustdoc-path").arg(builder.rustdoc_for_compiler(test_compiler)); } - if mode == "rustdoc-json" { + if mode == CompiletestMode::RustdocJson { // Use the stage0 compiler for jsondocck let json_compiler = builder.compiler(0, builder.host_target); cmd.arg("--jsondocck-path") @@ -1930,7 +1950,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the ); } - if matches!(mode, "coverage-map" | "coverage-run") { + if matches!(mode, CompiletestMode::CoverageMap | CompiletestMode::CoverageRun) { let coverage_dump = builder.tool_exe(Tool::CoverageDump); cmd.arg("--coverage-dump-path").arg(coverage_dump); } @@ -1957,7 +1977,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--sysroot-base").arg(sysroot); cmd.arg("--suite").arg(suite); - cmd.arg("--mode").arg(mode); + cmd.arg("--mode").arg(mode.as_str()); cmd.arg("--target").arg(target.rustc_target_arg()); cmd.arg("--host").arg(&*test_compiler.host.triple); cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); @@ -2036,7 +2056,7 @@ Please disable assertions with `rust.debug-assertions = false`. if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); - } else if mode == "rustdoc-js" { + } else if mode == CompiletestMode::RustdocJs { panic!("need nodejs to run rustdoc-js suite"); } if builder.config.rust_optimize_tests { @@ -2055,7 +2075,7 @@ Please disable assertions with `rust.debug-assertions = false`. let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] }; flags.push(format!( "-Cdebuginfo={}", - if mode == "codegen" { + if mode == CompiletestMode::Codegen { // codegen tests typically check LLVM IR and are sensitive to additional debuginfo. // So do not apply `rust.debuginfo-level-tests` for codegen tests. if builder.config.rust_debuginfo_level_tests @@ -2122,7 +2142,7 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--android-cross-path").arg(android_cross_path); } - if mode == "debuginfo" { + if mode == CompiletestMode::Debuginfo { if let Some(debuggers::Gdb { gdb }) = debuggers::discover_gdb(builder, android.as_ref()) { cmd.arg("--gdb").arg(gdb.as_ref()); @@ -2155,7 +2175,7 @@ Please disable assertions with `rust.debug-assertions = false`. // in rustdoc-js mode, allow filters to be rs files or js files. // use a late-initialized Vec to avoid cloning for other modes. let mut paths_v; - if mode == "rustdoc-js" { + if mode == CompiletestMode::RustdocJs { paths_v = paths.to_vec(); for p in &mut paths_v { if let Some(ext) = p.extension() @@ -2237,7 +2257,9 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--host-rustcflags").arg(link_llvm); } - if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") { + if !builder.config.dry_run() + && matches!(mode, CompiletestMode::RunMake | CompiletestMode::CoverageRun) + { // The llvm/bin directory contains many useful cross-platform // tools. Pass the path to run-make tests so they can use them. // (The coverage-run tests also need these tools to process @@ -2249,7 +2271,7 @@ Please disable assertions with `rust.debug-assertions = false`. cmd.arg("--llvm-bin-dir").arg(llvm_bin_path); } - if !builder.config.dry_run() && mode == "run-make" { + if !builder.config.dry_run() && mode == CompiletestMode::RunMake { // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = @@ -2269,7 +2291,7 @@ Please disable assertions with `rust.debug-assertions = false`. // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if !builder.config.dry_run() && mode == "run-make" { + if !builder.config.dry_run() && mode == CompiletestMode::RunMake { let mut cflags = builder.cc_handled_clags(target, CLang::C); cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx); @@ -2385,7 +2407,7 @@ Please disable assertions with `rust.debug-assertions = false`. builder.metrics.begin_test_suite( build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), - mode: mode.into(), + mode: mode.to_string(), compare_mode: None, target: self.target.triple.to_string(), host: self.test_compiler.host.triple.to_string(), @@ -2408,7 +2430,7 @@ Please disable assertions with `rust.debug-assertions = false`. builder.metrics.begin_test_suite( build_helper::metrics::TestSuiteMetadata::Compiletest { suite: suite.into(), - mode: mode.into(), + mode: mode.to_string(), compare_mode: Some(compare_mode.into()), target: self.target.triple.to_string(), host: self.test_compiler.host.triple.to_string(), diff --git a/src/bootstrap/src/core/build_steps/test/compiletest.rs b/src/bootstrap/src/core/build_steps/test/compiletest.rs new file mode 100644 index 0000000000000..359f6bb1a6efb --- /dev/null +++ b/src/bootstrap/src/core/build_steps/test/compiletest.rs @@ -0,0 +1,71 @@ +use std::fmt; + +/// Enum of all the "test modes" understood by compiletest. +/// +/// Some of these mode names happen to overlap with the names of test suite +/// directories, but the relationship between modes and suites is not 1:1. +/// For example: +/// - Mode `ui` is used by suites `tests/ui` and `tests/rustdoc-ui` +/// - Suite `tests/coverage` uses modes `coverage-map` and `coverage-run` +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) enum CompiletestMode { + // tidy-alphabetical-start + Assembly, + Codegen, + CodegenUnits, + CoverageMap, + CoverageRun, + Crashes, + Debuginfo, + Incremental, + MirOpt, + Pretty, + RunMake, + Rustdoc, + RustdocJs, + RustdocJson, + Ui, + // tidy-alphabetical-end +} + +impl CompiletestMode { + /// Returns a string representing this mode, which can be passed to + /// compiletest via a command-line argument. + /// + /// These mode names must be kept in sync with the ones understood by + /// compiletest's `TestMode`, but they change so rarely that doing so + /// manually should not be burdensome. + pub(crate) const fn as_str(self) -> &'static str { + match self { + // tidy-alphabetical-start + Self::Assembly => "assembly", + Self::Codegen => "codegen", + Self::CodegenUnits => "codegen-units", + Self::CoverageMap => "coverage-map", + Self::CoverageRun => "coverage-run", + Self::Crashes => "crashes", + Self::Debuginfo => "debuginfo", + Self::Incremental => "incremental", + Self::MirOpt => "mir-opt", + Self::Pretty => "pretty", + Self::RunMake => "run-make", + Self::Rustdoc => "rustdoc", + Self::RustdocJs => "rustdoc-js", + Self::RustdocJson => "rustdoc-json", + Self::Ui => "ui", + // tidy-alphabetical-end + } + } +} + +impl fmt::Display for CompiletestMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl fmt::Debug for CompiletestMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(self, f) + } +} diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b8ba1b4c2c340..709d646bb359a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -346,7 +346,7 @@ fn test_test_coverage() { let mut cache = run_build(&config.paths.clone(), config); let modes = - cache.all::().iter().map(|(step, ())| step.mode).collect::>(); + cache.inspect_all_steps_of_type::(|step, ()| step.mode.as_str()); assert_eq!(modes, expected); } } diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs index 5098e2f03c439..8c5b3529979d7 100644 --- a/src/bootstrap/src/utils/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -270,16 +270,18 @@ impl Cache { #[cfg(test)] impl Cache { - pub fn all(&mut self) -> Vec<(S, S::Output)> { - let cache = self.cache.get_mut(); - let type_id = TypeId::of::(); - let mut v = cache - .remove(&type_id) - .map(|b| b.downcast::>().expect("correct type")) - .map(|m| m.into_iter().collect::>()) + pub(crate) fn inspect_all_steps_of_type( + &self, + map_fn: impl Fn(&S, &S::Output) -> T, + ) -> Vec { + let cache = self.cache.borrow(); + let mut values = cache + .get(&TypeId::of::()) + .map(|any| any.downcast_ref::>().expect("correct type")) + .map(|m| m.iter().map(|(step, output)| map_fn(step, output)).collect::>()) .unwrap_or_default(); - v.sort_by_key(|(s, _)| s.clone()); - v + values.sort(); + values } pub fn contains(&self) -> bool { diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 4d7f1a4aafc93..3af53fa58e18c 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -4,8 +4,8 @@ The `#[doc]` attribute lets you control various aspects of how `rustdoc` does its job. The most basic function of `#[doc]` is to handle the actual documentation -text. That is, `///` is syntax sugar for `#[doc]`. This means that these two -are the same: +text. That is, `///` is syntax sugar for `#[doc]` (as is `//!` for `#![doc]`). +This means that these two are the same: ```rust,no_run /// This is a doc comment. diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f3bd467db3e41..ff4cd81d33ff6 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -255,8 +255,17 @@ fn parse_config(args: Vec) -> Config { } } - let target = opt_str2(matches.opt_str("target")); + let host = matches.opt_str("host").expect("`--host` must be unconditionally specified"); + let target = matches.opt_str("target").expect("`--target` must be unconditionally specified"); + let android_cross_path = matches.opt_str("android-cross-path").map(Utf8PathBuf::from); + + // FIXME: `adb_path` should be an `Option`... + let adb_path = matches.opt_str("adb-path").map(Utf8PathBuf::from).unwrap_or_default(); + // FIXME: `adb_test_dir` should be an `Option`... + let adb_test_dir = matches.opt_str("adb-test-dir").map(Utf8PathBuf::from).unwrap_or_default(); + let adb_device_status = target.contains("android") && !adb_test_dir.as_str().is_empty(); + // FIXME: `cdb_version` is *derived* from cdb, but it's *not* technically a config! let cdb = debuggers::discover_cdb(matches.opt_str("cdb"), &target); let cdb_version = cdb.as_deref().and_then(debuggers::query_cdb_version); @@ -433,7 +442,7 @@ fn parse_config(args: Vec) -> Config { optimize_tests: matches.opt_present("optimize-tests"), rust_randomized_layout: matches.opt_present("rust-randomized-layout"), target, - host: opt_str2(matches.opt_str("host")), + host, cdb, cdb_version, gdb, @@ -443,11 +452,9 @@ fn parse_config(args: Vec) -> Config { llvm_version, system_llvm: matches.opt_present("system-llvm"), android_cross_path, - adb_path: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-path"))), - adb_test_dir: Utf8PathBuf::from(opt_str2(matches.opt_str("adb-test-dir"))), - adb_device_status: opt_str2(matches.opt_str("target")).contains("android") - && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) - && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), + adb_path, + adb_test_dir, + adb_device_status, verbose: matches.opt_present("verbose"), only_modified: matches.opt_present("only-modified"), color, @@ -493,13 +500,6 @@ fn parse_config(args: Vec) -> Config { } } -fn opt_str2(maybestr: Option) -> String { - match maybestr { - None => "(none)".to_owned(), - Some(s) => s, - } -} - /// Called by `main` after the config has been parsed. fn run_tests(config: Arc) { debug!(?config, "run_tests"); diff --git a/tests/pretty/delegation_inline_attribute.pp b/tests/pretty/delegation_inline_attribute.pp new file mode 100644 index 0000000000000..4b3b2aa8f80a2 --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.pp @@ -0,0 +1,94 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation_inline_attribute.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[attr = MacroUse {arguments: UseAll}] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +mod to_reuse { + fn foo(x: usize) -> usize { x } +} + +// Check that #[inline(hint)] is added to foo reuse +#[attr = Inline(Hint)] +fn bar(arg0: _) -> _ { to_reuse::foo(self + 1) } + +trait Trait { + fn foo(&self) { } + fn foo1(&self) { } + fn foo2(&self) { } + fn foo3(&self) { } + fn foo4(&self) { } +} + +impl Trait for u8 { } + +struct S(u8); + +mod to_import { + fn check(arg: &'_ u8) -> &'_ u8 { arg } +} + +impl Trait for S { + // Check that #[inline(hint)] is added to foo reuse + #[attr = Inline(Hint)] + fn foo(self: _) + -> + _ { + { + // Check that #[inline(hint)] is added to foo0 reuse inside another reuse + #[attr = Inline(Hint)] + fn foo0(arg0: _) -> _ { to_reuse::foo(self + 1) } + + // Check that #[inline(hint)] is added when other attributes present in inner reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = MustUse] + #[attr = Cold] + #[attr = Inline(Hint)] + fn foo1(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(never)] is preserved in inner reuse + #[attr = Inline(Never)] + fn foo2(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(always)] is preserved in inner reuse + #[attr = Inline(Always)] + fn foo3(arg0: _) -> _ { to_reuse::foo(self / 2) } + + // Check that #[inline(never)] is preserved when there are other attributes in inner reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Inline(Never)] + #[attr = MustUse] + #[attr = Cold] + fn foo4(arg0: _) -> _ { to_reuse::foo(self / 2) } + }.foo() + } + + // Check that #[inline(hint)] is added when there are other attributes present in trait reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = MustUse] + #[attr = Cold] + #[attr = Inline(Hint)] + fn foo1(self: _) -> _ { self.0.foo1() } + + // Check that #[inline(never)] is preserved in trait reuse + #[attr = Inline(Never)] + fn foo2(self: _) -> _ { self.0.foo2() } + + // Check that #[inline(always)] is preserved in trait reuse + #[attr = Inline(Always)] + fn foo3(self: _) -> _ { self.0.foo3() } + + // Check that #[inline(never)] is preserved when there are other attributes in trait reuse + #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}] + #[attr = Inline(Never)] + #[attr = MustUse] + #[attr = Cold] + fn foo4(self: _) -> _ { self.0.foo4() } +} + +fn main() { } diff --git a/tests/pretty/delegation_inline_attribute.rs b/tests/pretty/delegation_inline_attribute.rs new file mode 100644 index 0000000000000..0716cfc51f5d9 --- /dev/null +++ b/tests/pretty/delegation_inline_attribute.rs @@ -0,0 +1,104 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation_inline_attribute.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod to_reuse { + pub fn foo(x: usize) -> usize { + x + } +} + +// Check that #[inline(hint)] is added to foo reuse +reuse to_reuse::foo as bar { + self + 1 +} + +trait Trait { + fn foo(&self) {} + fn foo1(&self) {} + fn foo2(&self) {} + fn foo3(&self) {} + fn foo4(&self) {} +} + +impl Trait for u8 {} + +struct S(u8); + +mod to_import { + pub fn check(arg: &u8) -> &u8 { arg } +} + +impl Trait for S { + // Check that #[inline(hint)] is added to foo reuse + reuse Trait::foo { + // Check that #[inline(hint)] is added to foo0 reuse inside another reuse + reuse to_reuse::foo as foo0 { + self + 1 + } + + // Check that #[inline(hint)] is added when other attributes present in inner reuse + #[cold] + #[must_use] + #[deprecated] + reuse to_reuse::foo as foo1 { + self / 2 + } + + // Check that #[inline(never)] is preserved in inner reuse + #[inline(never)] + reuse to_reuse::foo as foo2 { + self / 2 + } + + // Check that #[inline(always)] is preserved in inner reuse + #[inline(always)] + reuse to_reuse::foo as foo3 { + self / 2 + } + + // Check that #[inline(never)] is preserved when there are other attributes in inner reuse + #[cold] + #[must_use] + #[inline(never)] + #[deprecated] + reuse to_reuse::foo as foo4 { + self / 2 + } + } + + // Check that #[inline(hint)] is added when there are other attributes present in trait reuse + #[cold] + #[must_use] + #[deprecated] + reuse Trait::foo1 { + self.0 + } + + // Check that #[inline(never)] is preserved in trait reuse + #[inline(never)] + reuse Trait::foo2 { + self.0 + } + + // Check that #[inline(always)] is preserved in trait reuse + #[inline(always)] + reuse Trait::foo3 { + self.0 + } + + // Check that #[inline(never)] is preserved when there are other attributes in trait reuse + #[cold] + #[must_use] + #[inline(never)] + #[deprecated] + reuse Trait::foo4 { + self.0 + } +} + +fn main() { +} diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index f8ad02f2fccce..b5f7a14eb2fc0 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -12,6 +12,7 @@ fn b(e: C) { } trait G { + #[attr = Inline(Hint)] fn b(arg0: _) -> _ { b({ }) } } @@ -19,6 +20,7 @@ fn add(a: u32, b: u32) -> u32 { a + b } } +#[attr = Inline(Hint)] fn add(arg0: _, arg1: _) -> _ { m::add(arg0, arg1) } fn main() { { let _ = add(1, 2); }; } diff --git a/tests/run-make/no-builtins-linker-plugin-lto/main.rs b/tests/run-make/no-builtins-linker-plugin-lto/main.rs new file mode 100644 index 0000000000000..f96605be89499 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/main.rs @@ -0,0 +1,3 @@ +fn main() { + no_builtins::foo(); +} diff --git a/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs b/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs new file mode 100644 index 0000000000000..a56c1d6b41334 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/no_builtins.rs @@ -0,0 +1,4 @@ +#![no_builtins] + +#[inline(never)] +pub fn foo() {} diff --git a/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs b/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs new file mode 100644 index 0000000000000..7133085677377 --- /dev/null +++ b/tests/run-make/no-builtins-linker-plugin-lto/rmake.rs @@ -0,0 +1,53 @@ +//@ only-x86_64-unknown-linux-gnu + +use std::fs; +use std::path::Path; + +use run_make_support::{cwd, has_extension, llvm_ar, llvm_bcanalyzer, rust_lib_name, rustc}; + +// A regression test for #146133. + +fn main() { + // Compile a `#![no_builtins]` rlib crate with `-Clinker-plugin-lto`. + // It is acceptable to generate bitcode for rlib, so there is no need to check something. + rustc().input("no_builtins.rs").crate_type("rlib").linker_plugin_lto("on").run(); + + // Checks that rustc's LTO doesn't emit any bitcode to the linker. + let stdout = rustc() + .input("main.rs") + .extern_("no_builtins", rust_lib_name("no_builtins")) + .lto("thin") + .print("link-args") + .arg("-Csave-temps") + .arg("-Clinker-features=-lld") + .run() + .stdout_utf8(); + for object in stdout + .split_whitespace() + .map(|s| s.trim_matches('"')) + .filter(|path| has_extension(path, "rlib") || has_extension(path, "o")) + { + let object_path = if !fs::exists(object).unwrap() { + cwd().join(object) + } else { + Path::new(object).to_path_buf() + }; + if has_extension(object, "rlib") { + let ar_stdout = llvm_ar().arg("t").arg(&object_path).run().stdout_utf8(); + llvm_ar().extract().arg(&object_path).run(); + for object in ar_stdout.split_whitespace().filter(|o| has_extension(o, "o")) { + let object_path = cwd().join(object); + not_bitcode(&object_path); + } + } else { + not_bitcode(&object_path); + } + } +} + +fn not_bitcode(object: &Path) { + llvm_bcanalyzer() + .input(object) + .run_fail() + .assert_stderr_contains("llvm-bcanalyzer: Invalid record at top-level"); +} diff --git a/tests/ui/check-cfg/nested-cfg.rs b/tests/ui/check-cfg/nested-cfg.rs new file mode 100644 index 0000000000000..2b3a21f88dc59 --- /dev/null +++ b/tests/ui/check-cfg/nested-cfg.rs @@ -0,0 +1,8 @@ +//@ check-pass + +#[cfg(unknown)] //~ WARN unexpected `cfg` condition name +#[cfg(false)] +#[cfg(unknown)] // Should not warn +fn foo() {} + +fn main() {} diff --git a/tests/ui/check-cfg/nested-cfg.stderr b/tests/ui/check-cfg/nested-cfg.stderr new file mode 100644 index 0000000000000..6fdae732bbe58 --- /dev/null +++ b/tests/ui/check-cfg/nested-cfg.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition name: `unknown` + --> $DIR/nested-cfg.rs:3:7 + | +LL | #[cfg(unknown)] + | ^^^^^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(unknown)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default +help: found config with similar value + | +LL - #[cfg(unknown)] +LL + #[cfg(target_os = "unknown")] + | +help: found config with similar value + | +LL - #[cfg(unknown)] +LL + #[cfg(target_vendor = "unknown")] + | + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.rs b/tests/ui/feature-gates/feature-gate-link_cfg.rs index d30ee3bcfdb14..286c3d0a4977d 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.rs +++ b/tests/ui/feature-gates/feature-gate-link_cfg.rs @@ -1,4 +1,4 @@ -#[link(name = "foo", cfg(foo))] +#[link(name = "foo", cfg(false))] //~^ ERROR: is unstable extern "C" {} diff --git a/tests/ui/feature-gates/feature-gate-link_cfg.stderr b/tests/ui/feature-gates/feature-gate-link_cfg.stderr index bfe7f74a92137..0e9707c6c9620 100644 --- a/tests/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,8 +1,8 @@ error[E0658]: link cfg is unstable --> $DIR/feature-gate-link_cfg.rs:1:22 | -LL | #[link(name = "foo", cfg(foo))] - | ^^^^^^^^ +LL | #[link(name = "foo", cfg(false))] + | ^^^^^^^^^^ | = help: add `#![feature(link_cfg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/link-native-libs/link-cfg-works.rs b/tests/ui/link-native-libs/link-cfg-works.rs index 7b936bc43b1a0..0e02933ce01c2 100644 --- a/tests/ui/link-native-libs/link-cfg-works.rs +++ b/tests/ui/link-native-libs/link-cfg-works.rs @@ -7,7 +7,7 @@ extern crate link_cfg_works_transitive_dylib; extern crate link_cfg_works_transitive_rlib; -#[link(name = "foo", cfg(foo))] +#[link(name = "foo", cfg(false))] extern "C" {} fn main() {} diff --git a/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs new file mode 100644 index 0000000000000..5d4279fc834d1 --- /dev/null +++ b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.rs @@ -0,0 +1,10 @@ +#![feature(unsafe_binders)] +#![expect(incomplete_features)] +#![deny(improper_ctypes)] + +extern "C" { + fn exit_2(x: unsafe<'a> &'a ()); + //~^ ERROR `extern` block uses type `unsafe<'a> &'a ()`, which is not FFI-safe +} + +fn main() {} diff --git a/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr new file mode 100644 index 0000000000000..4b8d51690f1a0 --- /dev/null +++ b/tests/ui/lint/improper-ctypes/unsafe-binder-basic.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `unsafe<'a> &'a ()`, which is not FFI-safe + --> $DIR/unsafe-binder-basic.rs:6:18 + | +LL | fn exit_2(x: unsafe<'a> &'a ()); + | ^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: unsafe binders are incompatible with foreign function interfaces +note: the lint level is defined here + --> $DIR/unsafe-binder-basic.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs index d992ec82e2fd2..f0c51b2942f16 100644 --- a/tests/ui/macros/cfg.rs +++ b/tests/ui/macros/cfg.rs @@ -2,5 +2,6 @@ fn main() { cfg!(); //~ ERROR macro requires a cfg-pattern cfg!(123); //~ ERROR malformed `cfg` macro input cfg!(foo = 123); //~ ERROR malformed `cfg` macro input - cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern + cfg!(false, false); //~ ERROR expected 1 cfg-pattern + cfg!(foo); //~ WARN unexpected `cfg` condition name: `foo` } diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index 9a4c187f37b27..06529a5b7a61f 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -29,9 +29,20 @@ LL | cfg!(foo = 123); error: expected 1 cfg-pattern --> $DIR/cfg.rs:5:5 | -LL | cfg!(foo, bar); - | ^^^^^^^^^^^^^^ +LL | cfg!(false, false); + | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +warning: unexpected `cfg` condition name: `foo` + --> $DIR/cfg.rs:6:10 + | +LL | cfg!(foo); + | ^^^ + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(foo)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 2a627cc05b93b..a54c385747fa6 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -89,9 +89,11 @@ cfg_select! { cfg_select! { a + 1 => {} //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `+` + //~| WARN unexpected `cfg` condition name } cfg_select! { cfg!() => {} //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `!` + //~| WARN unexpected `cfg` condition name } diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 3a5d2b0a1e1ee..d79e1b9b5c10a 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -60,12 +60,32 @@ LL | a + 1 => {} | ^ expected one of `(`, `::`, `=>`, or `=` error: expected one of `(`, `::`, `=>`, or `=`, found `!` - --> $DIR/cfg_select.rs:95:8 + --> $DIR/cfg_select.rs:96:8 | LL | cfg!() => {} | ^ expected one of `(`, `::`, `=>`, or `=` -error: aborting due to 9 previous errors; 1 warning emitted +warning: unexpected `cfg` condition name: `a` + --> $DIR/cfg_select.rs:90:5 + | +LL | a + 1 => {} + | ^ help: found config with similar value: `target_feature = "a"` + | + = help: expected names are: `FALSE` and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(a)` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition name: `cfg` + --> $DIR/cfg_select.rs:96:5 + | +LL | cfg!() => {} + | ^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(cfg)` + = note: see for more information about checking conditional configuration + +error: aborting due to 9 previous errors; 3 warnings emitted Some errors have detailed explanations: E0537, E0539. For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs b/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs new file mode 100644 index 0000000000000..18e63db0cdd11 --- /dev/null +++ b/tests/ui/privacy/auxiliary/non_exhaustive_with_private.rs @@ -0,0 +1,13 @@ +// Auxiliary crate for testing non-exhaustive struct with private fields + +#[non_exhaustive] +pub struct Foo { + pub my_field: u32, + private_field: i32, +} + +#[non_exhaustive] +pub struct Bar { + pub my_field: u32, + pub missing_field: i32, +} diff --git a/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs new file mode 100644 index 0000000000000..0553ff6c781e9 --- /dev/null +++ b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.rs @@ -0,0 +1,17 @@ +//@ aux-build:non_exhaustive_with_private.rs + +extern crate non_exhaustive_with_private; + +use non_exhaustive_with_private::{Bar, Foo}; + +fn main() { + let foo = Foo { + //~^ ERROR cannot create non-exhaustive struct using struct expression + my_field: 10, + }; + + let bar = Bar { + //~^ ERROR cannot create non-exhaustive struct using struct expression + my_field: 10, + }; +} diff --git a/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr new file mode 100644 index 0000000000000..85bf7e4847d73 --- /dev/null +++ b/tests/ui/privacy/non-exhaustive-with-private-fields-147513.stderr @@ -0,0 +1,23 @@ +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/non-exhaustive-with-private-fields-147513.rs:8:15 + | +LL | let foo = Foo { + | _______________^ +LL | | +LL | | my_field: 10, +LL | | }; + | |_____^ + +error[E0639]: cannot create non-exhaustive struct using struct expression + --> $DIR/non-exhaustive-with-private-fields-147513.rs:13:15 + | +LL | let bar = Bar { + | _______________^ +LL | | +LL | | my_field: 10, +LL | | }; + | |_____^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0639`. diff --git a/triagebot.toml b/triagebot.toml index 6ad8dd6b4c886..c459f69d06bb6 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1680,12 +1680,6 @@ days-threshold = 28 # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html [issue-links] -# Prevents mentions in commits to avoid users being spammed -# Documentation at: https://forge.rust-lang.org/triagebot/no-mentions.html -[no-mentions] -# Subtree update authors can't fix it, no point in warning. -exclude-titles = ["subtree update"] - # Allow members to formally register concerns (`@rustbot concern my concern`) # Documentation at: https://forge.rust-lang.org/triagebot/concern.html [concern]