diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 5f8933aa2beba..8d7351d3a510c 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -125,9 +125,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - /// Because we want to track parent items and so forth, enable - /// deep walking so that we walk nested items in the context of - /// their outer items. + // Because we want to track parent items and so forth, enable + // deep walking so that we walk nested items in the context of + // their outer items. fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs new file mode 100644 index 0000000000000..8006fb963b198 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_select.rs @@ -0,0 +1,89 @@ +use rustc_ast::token::Token; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{AttrStyle, NodeId, token}; +use rustc_feature::{AttributeTemplate, Features}; +use rustc_hir::AttrPath; +use rustc_hir::attrs::CfgEntry; +use rustc_parse::exp; +use rustc_parse::parser::Parser; +use rustc_session::Session; +use rustc_span::{ErrorGuaranteed, Ident, Span}; + +use crate::parser::MetaItemOrLitParser; +use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry}; + +pub enum CfgSelectPredicate { + Cfg(CfgEntry), + Wildcard(Token), +} + +#[derive(Default)] +pub struct CfgSelectBranches { + /// All the conditional branches. + pub reachable: Vec<(CfgEntry, TokenStream, Span)>, + /// The first wildcard `_ => { ... }` branch. + pub wildcard: Option<(Token, TokenStream, Span)>, + /// All branches after the first wildcard, including further wildcards. + /// These branches are kept for formatting. + pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, +} + +pub fn parse_cfg_select( + p: &mut Parser<'_>, + sess: &Session, + features: Option<&Features>, + lint_node_id: NodeId, +) -> Result { + let mut branches = CfgSelectBranches::default(); + + while p.token != token::Eof { + if p.eat_keyword(exp!(Underscore)) { + let underscore = p.prev_token; + p.expect(exp!(FatArrow)).map_err(|e| e.emit())?; + + let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?; + let span = underscore.span.to(p.token.span); + + match branches.wildcard { + None => branches.wildcard = Some((underscore, tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) + } + } + } else { + let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints) + .map_err(|diag| diag.emit())?; + let cfg_span = meta.span(); + let cfg = AttributeParser::parse_single_args( + sess, + cfg_span, + cfg_span, + AttrStyle::Inner, + AttrPath { + segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(), + span: cfg_span, + }, + ParsedDescription::Macro, + cfg_span, + lint_node_id, + features, + ShouldEmit::ErrorsAndLints, + &meta, + parse_cfg_entry, + &AttributeTemplate::default(), + )?; + + p.expect(exp!(FatArrow)).map_err(|e| e.emit())?; + + let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?; + let span = cfg_span.to(p.token.span); + + match branches.wildcard { + None => branches.reachable.push((cfg, tts, span)), + Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)), + } + } + } + + Ok(branches) +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 093969586596d..65e0957ca9005 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -33,6 +33,7 @@ pub(crate) mod allow_unstable; pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_old; +pub(crate) mod cfg_select; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod crate_level; diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 473935abdcd50..046cca4c742b0 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -106,6 +106,7 @@ pub use attributes::cfg::{ CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry, }; pub use attributes::cfg_old::*; +pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; pub use interface::AttributeParser; diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index f22d5f255c292..f2e454c3d4373 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,7 +1,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; +use rustc_attr_parsing::{ + CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select, +}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select}; use rustc_span::{Ident, Span, sym}; use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; @@ -9,11 +11,11 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; /// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { for (cfg, tt, arm_span) in branches.reachable { - if attr::cfg_matches( - &cfg, + if let EvalConfigResult::True = attr::eval_config_entry( &ecx.sess, + &cfg, ecx.current_expansion.lint_node_id, - Some(ecx.ecfg.features), + ShouldEmit::ErrorsAndLints, ) { return Some((tt, arm_span)); } @@ -27,37 +29,41 @@ pub(super) fn expand_cfg_select<'cx>( sp: Span, tts: TokenStream, ) -> MacroExpanderResult<'cx> { - ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) { - Ok(branches) => { - if let Some((underscore, _, _)) = branches.wildcard { - // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. - for (predicate, _, _) in &branches.unreachable { - let span = match predicate { - CfgSelectPredicate::Wildcard(underscore) => underscore.span, - CfgSelectPredicate::Cfg(cfg) => cfg.span(), - }; - let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; - ecx.dcx().emit_warn(err); + ExpandResult::Ready( + match parse_cfg_select( + &mut ecx.new_parser_from_tts(tts), + ecx.sess, + Some(ecx.ecfg.features), + ecx.current_expansion.lint_node_id, + ) { + Ok(branches) => { + if let Some((underscore, _, _)) = branches.wildcard { + // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. + for (predicate, _, _) in &branches.unreachable { + let span = match predicate { + CfgSelectPredicate::Wildcard(underscore) => underscore.span, + CfgSelectPredicate::Cfg(cfg) => cfg.span(), + }; + let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; + ecx.dcx().emit_warn(err); + } } - } - if let Some((tts, arm_span)) = select_arm(ecx, branches) { - return ExpandResult::from_tts( - ecx, - tts, - sp, - arm_span, - Ident::with_dummy_span(sym::cfg_select), - ); - } else { - // Emit a compiler error when none of the predicates matched. - let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); - DummyResult::any(sp, guar) + if let Some((tts, arm_span)) = select_arm(ecx, branches) { + return ExpandResult::from_tts( + ecx, + tts, + sp, + arm_span, + Ident::with_dummy_span(sym::cfg_select), + ); + } else { + // Emit a compiler error when none of the predicates matched. + let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); + DummyResult::any(sp, guar) + } } - } - Err(err) => { - let guar = err.emit(); - DummyResult::any(sp, guar) - } - }) + Err(guar) => DummyResult::any(sp, guar), + }, + ) } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 9ac282df5b5ea..09d71f5dd5579 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -916,8 +916,8 @@ pub(crate) fn codegen_call_with_unwind_action( pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { let param = AbiParam::new(ty); if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() { - match (&tcx.sess.target.arch, tcx.sess.target.vendor.as_ref()) { - (Arch::X86_64, _) | (Arch::AArch64, "apple") => match (ty, is_signed) { + match (&tcx.sess.target.arch, tcx.sess.target.is_like_darwin) { + (Arch::X86_64, _) | (Arch::AArch64, true) => match (ty, is_signed) { (types::I8 | types::I16, true) => param.sext(), (types::I8 | types::I16, false) => param.uext(), _ => param, diff --git a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs index 91f7220667ff9..86bff32dc623c 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs @@ -5,7 +5,7 @@ use crate::prelude::*; pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { let (value, arg_ty) = - if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 { + if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { ( fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value), lib_call_arg_param(fx.tcx, types::I16, false), @@ -22,8 +22,7 @@ fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { } pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 @@ -38,8 +37,7 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value } fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c5724c20b2165..2817dcf8e976a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1819,7 +1819,7 @@ fn self_contained_components( LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)), LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target - && sess.target.vendor != "uwp" + && sess.target.abi != "uwp" && detect_self_contained_mingw(sess, linker) } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index eb2740d59b4b5..5abcf99b3d67a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -83,7 +83,7 @@ pub(crate) fn get_linker<'a>( // To comply with the Windows App Certification Kit, // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). let t = &sess.target; - if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" { + if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == "uwp" { if let Some(ref tool) = msvc_tool { let original_path = tool.path(); if let Some(root_lib_path) = original_path.ancestors().nth(4) { @@ -134,7 +134,7 @@ pub(crate) fn get_linker<'a>( // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. - assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); + assert!(cmd.get_args().is_empty() || sess.target.abi == "uwp"); match flavor { LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => { Box::new(L4Bender::new(cmd, sess)) as Box diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 08e2f35595332..bde36f45b3838 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -171,7 +171,7 @@ pub fn asm_const_to_str<'tcx>( } pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { - target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() + target.os == "windows" && target.env == "gnu" && target.abi.is_empty() } pub fn i686_decorated_name( diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 2be9ba292f976..0ef3bb319ff80 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -53,13 +53,13 @@ impl !DynSend for std::env::VarsOs {} macro_rules! already_send { ($([$ty: ty])*) => { - $(unsafe impl DynSend for $ty where $ty: Send {})* + $(unsafe impl DynSend for $ty where Self: Send {})* }; } // These structures are already `Send`. already_send!( - [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File] + [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File][std::panic::Location<'_>] [rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread] [crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); @@ -127,14 +127,14 @@ impl !DynSync for std::env::VarsOs {} macro_rules! already_sync { ($([$ty: ty])*) => { - $(unsafe impl DynSync for $ty where $ty: Sync {})* + $(unsafe impl DynSync for $ty where Self: Sync {})* }; } // These structures are already `Sync`. already_sync!( [std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8] - [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File] + [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File][std::panic::Location<'_>] [jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap] [crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 0d79d98b5d966..afa9bc36f2c5e 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -1,5 +1,5 @@ use crate::stable_hasher::{HashStable, StableHasher}; -use crate::sync::{MappedReadGuard, ReadGuard, RwLock}; +use crate::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, RwLock, WriteGuard}; /// The `Steal` struct is intended to used as the value for a query. /// Specifically, we sometimes have queries (*cough* MIR *cough*) @@ -40,9 +40,17 @@ impl Steal { ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) } + /// An escape hatch for rustc drivers to mutate `Steal` caches. + /// + /// Use at your own risk. This can badly break incremental compilation + /// and anything else that relies on the immutability of query caches. #[track_caller] - pub fn get_mut(&mut self) -> &mut T { - self.value.get_mut().as_mut().expect("attempt to read from stolen value") + pub fn risky_hack_borrow_mut(&self) -> MappedWriteGuard<'_, T> { + let borrow = self.value.borrow_mut(); + if borrow.is_none() { + panic!("attempted to read from stolen value: {}", std::any::type_name::()); + } + WriteGuard::map(borrow, |opt| opt.as_mut().unwrap()) } #[track_caller] diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 81a7ee1ff45fe..e6fa1fa5ce50a 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2322,11 +2322,6 @@ impl HumanEmitter { show_code_change { for part in parts { - let snippet = if let Ok(snippet) = sm.span_to_snippet(part.span) { - snippet - } else { - String::new() - }; let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; @@ -2402,7 +2397,7 @@ impl HumanEmitter { // LL - REMOVED <- row_num - 2 - (newlines - first_i - 1) // LL + NEWER // | <- row_num - + let snippet = sm.span_to_snippet(part.span).unwrap_or_default(); let newlines = snippet.lines().count(); if newlines > 0 && row_num > newlines { // Account for removals where the part being removed spans multiple diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 7ddd71c346006..4ba64b240ac03 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -194,6 +194,18 @@ pub enum CfgEntry { Version(Option, Span), } +impl CfgEntry { + pub fn span(&self) -> Span { + let (CfgEntry::All(_, span) + | CfgEntry::Any(_, span) + | CfgEntry::Not(_, span) + | CfgEntry::Bool(_, span) + | CfgEntry::NameValue { span, .. } + | CfgEntry::Version(_, span)) = self; + *span + } +} + /// Possible values for the `#[linkage]` attribute, allowing to specify the /// linkage type for a `MonoItem`. /// diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs index cf38957bf24aa..9c7680b921205 100644 --- a/compiler/rustc_hir_analysis/src/variance/terms.rs +++ b/compiler/rustc_hir_analysis/src/variance/terms.rs @@ -44,7 +44,7 @@ impl<'a> fmt::Debug for VarianceTerm<'a> { } } -/// The first pass over the crate simply builds up the set of inferreds. +// The first pass over the crate simply builds up the set of inferreds. pub(crate) struct TermsContext<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 191eb721b3477..ae145543e70dc 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -55,10 +55,10 @@ macro_rules! late_lint_methods { /// Each `check` method checks a single syntax node, and should not /// invoke methods recursively (unlike `Visitor`). By default they /// do nothing. -// +/// // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. - +// macro_rules! declare_late_lint_pass { ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( pub trait LateLintPass<'tcx>: LintPass { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 291f5c65dfa27..10fe23a0a65c9 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -67,7 +67,7 @@ pub fn walk_native_lib_search_dirs( // FIXME: On AIX this also has the side-effect of making the list of library search paths // non-empty, which is needed or the linker may decide to record the LIBPATH env, if // defined, as the search path instead of appending the default search paths. - if sess.target.vendor == "fortanix" + if sess.target.abi == "fortanix" || sess.target.os == "linux" || sess.target.os == "fuchsia" || sess.target.is_like_aix diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 5764a9c84eeaf..6985cc7ddcfa1 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -16,7 +16,7 @@ use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants - +/// /// Represents the result of const evaluation via the `eval_to_allocation` query. /// Not to be confused with `ConstAllocation`, which directly refers to the underlying data! /// Here we indirect via an `AllocId`. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index a4422abc6883a..782ea3906ef13 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -607,9 +607,9 @@ impl<'tcx> TyCtxt<'tcx> { /// have the same `DefKind`. /// /// Note that closures have a `DefId`, but the closure *expression* also has a - // `HirId` that is located within the context where the closure appears (and, sadly, - // a corresponding `NodeId`, since those are not yet phased out). The parent of - // the closure's `DefId` will also be the context where it appears. + /// `HirId` that is located within the context where the closure appears (and, sadly, + /// a corresponding `NodeId`, since those are not yet phased out). The parent of + /// the closure's `DefId` will also be the context where it appears. pub fn is_closure_like(self, def_id: DefId) -> bool { matches!(self.def_kind(def_id), DefKind::Closure) } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 08a71db4de853..9692d2c708938 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -1,83 +1,34 @@ -use rustc_ast::token::Token; +use rustc_ast::token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::classify; -use rustc_ast::{MetaItemInner, token}; use rustc_errors::PResult; -use rustc_span::Span; use crate::exp; use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos}; -pub enum CfgSelectPredicate { - Cfg(MetaItemInner), - Wildcard(Token), -} - -#[derive(Default)] -pub struct CfgSelectBranches { - /// All the conditional branches. - pub reachable: Vec<(MetaItemInner, TokenStream, Span)>, - /// The first wildcard `_ => { ... }` branch. - pub wildcard: Option<(Token, TokenStream, Span)>, - /// All branches after the first wildcard, including further wildcards. - /// These branches are kept for formatting. - pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, -} - -/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an -/// expression followed by a comma (and strip the comma). -fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> { - if p.token == token::OpenBrace { - // Strip the outer '{' and '}'. - match p.parse_token_tree() { - TokenTree::Token(..) => unreachable!("because of the expect above"), - TokenTree::Delimited(.., tts) => return Ok(tts), - } - } - let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| { - p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty()) - .map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No)) - })?; - if !classify::expr_is_complete(&expr) && p.token != token::CloseBrace && p.token != token::Eof { - p.expect(exp!(Comma))?; - } else { - let _ = p.eat(exp!(Comma)); - } - Ok(TokenStream::from_ast(&expr)) -} - -pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> { - let mut branches = CfgSelectBranches::default(); - - while p.token != token::Eof { - if p.eat_keyword(exp!(Underscore)) { - let underscore = p.prev_token; - p.expect(exp!(FatArrow))?; - - let tts = parse_token_tree(p)?; - let span = underscore.span.to(p.token.span); - - match branches.wildcard { - None => branches.wildcard = Some((underscore, tts, span)), - Some(_) => { - branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) - } +impl<'a> Parser<'a> { + /// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an + /// expression followed by a comma (and strip the comma). + pub fn parse_delimited_token_tree(&mut self) -> PResult<'a, TokenStream> { + if self.token == token::OpenBrace { + // Strip the outer '{' and '}'. + match self.parse_token_tree() { + TokenTree::Token(..) => unreachable!("because of the expect above"), + TokenTree::Delimited(.., tts) => return Ok(tts), } + } + let expr = self.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| { + p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty()) + .map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No)) + })?; + if !classify::expr_is_complete(&expr) + && self.token != token::CloseBrace + && self.token != token::Eof + { + self.expect(exp!(Comma))?; } else { - let meta_item = p.parse_meta_item_inner()?; - p.expect(exp!(FatArrow))?; - - let tts = parse_token_tree(p)?; - let span = meta_item.span().to(p.token.span); - - match branches.wildcard { - None => branches.reachable.push((meta_item, tts, span)), - Some(_) => { - branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span)) - } - } + let _ = self.eat(exp!(Comma)); } + Ok(TokenStream::from_ast(&expr)) } - - Ok(branches) } diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 26ff87417ab0d..50c88e8b1e62a 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -298,7 +298,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::target_thread_local); } - ins_str!(sym::target_vendor, &sess.target.vendor); + ins_sym!(sym::target_vendor, sess.target.vendor_symbol()); // If the user wants a test runner, then add the test cfg. if sess.is_test_crate() { @@ -456,7 +456,7 @@ impl CheckCfg { ); values_target_os.insert(Symbol::intern(&target.options.os)); values_target_pointer_width.insert(sym::integer(target.pointer_width)); - values_target_vendor.insert(Symbol::intern(&target.options.vendor)); + values_target_vendor.insert(target.vendor_symbol()); } } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 2d83caa07676a..73a0d9eea7326 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,7 +9,9 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![expect(internal_features)] #![feature(iter_intersperse)] +#![feature(rustc_attrs)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs index 374918d38a791..4f9d9c83761f4 100644 --- a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs +++ b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs @@ -1,10 +1,9 @@ use crate::spec::{LinkerFlavor, Lld, TargetOptions, base}; pub(crate) fn opts() -> TargetOptions { - let mut opts = base::windows_msvc::opts(); + let mut opts = + TargetOptions { abi: "uwp".into(), vendor: "uwp".into(), ..base::windows_msvc::opts() }; - opts.abi = "uwp".into(); - opts.vendor = "uwp".into(); opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]); opts diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index ab2879f6c6ea8..8ac09205fbc89 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -261,6 +261,7 @@ impl ToJson for Target { ($attr:ident) => {{ target_option_val!($attr, (stringify!($attr)).replace("_", "-")) }}; ($attr:ident, $json_name:expr) => {{ let name = $json_name; + #[allow(rustc::bad_opt_access)] if default.$attr != target.$attr { d.insert(name.into(), target.$attr.to_json()); } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2dd0fbc4517a5..08fae288c441c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2045,6 +2045,7 @@ type StaticCow = Cow<'static, T>; /// construction, all its fields logically belong to `Target` and available from `Target` /// through `Deref` impls. #[derive(PartialEq, Clone, Debug)] +#[rustc_lint_opt_ty] pub struct TargetOptions { /// Used as the `target_endian` `cfg` variable. Defaults to little endian. pub endian: Endian, @@ -2063,7 +2064,10 @@ pub struct TargetOptions { /// However, parts of the backend do check this field for specific values to enable special behavior. pub abi: StaticCow, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". - pub vendor: StaticCow, + #[rustc_lint_opt_deny_field_access( + "use `Target::is_like_*` instead of this field; see https://github.com/rust-lang/rust/issues/100343 for rationale" + )] + vendor: StaticCow, /// Linker to invoke pub linker: Option>, @@ -3323,6 +3327,10 @@ impl Target { Align::MAX } } + + pub fn vendor_symbol(&self) -> Symbol { + Symbol::intern(&self.vendor) + } } /// Either a target tuple string or a path to a JSON file. diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs index a79c642870126..37a8b1d878098 100644 --- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs @@ -5,7 +5,6 @@ use crate::spec::{ /// A base target for Nintendo 3DS devices using the devkitARM toolchain. /// /// Requires the devkitARM toolchain for 3DS targets on the host system. - pub(crate) fn target() -> Target { let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 6c02ec26fea48..631b9770fac54 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -7,7 +7,6 @@ use crate::spec::{ /// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib). /// /// Requires the VITASDK toolchain on the host system. - pub(crate) fn target() -> Target { let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs index c026f915906cb..43ebc54c2b402 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs @@ -1,15 +1,18 @@ use crate::spec::{ - Arch, Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, + Arch, Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { - let mut base = base::windows_gnu::opts(); - base.vendor = "win7".into(); - base.rustc_abi = Some(RustcAbi::X86Sse2); - base.cpu = "pentium4".into(); - base.max_atomic_width = Some(64); - base.frame_pointer = FramePointer::Always; // Required for backtraces - base.linker = Some("i686-w64-mingw32-gcc".into()); + let mut base = TargetOptions { + vendor: "win7".into(), + rustc_abi: Some(RustcAbi::X86Sse2), + cpu: "pentium4".into(), + max_atomic_width: Some(64), + frame_pointer: FramePointer::Always, // Required for backtraces + linker: Some("i686-w64-mingw32-gcc".into()), + ..base::windows_gnu::opts() + }; // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index 68131bf654264..8994c245d7b90 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -1,18 +1,22 @@ -use crate::spec::{Arch, LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, base}; +use crate::spec::{ + Arch, LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { - let mut base = base::windows_msvc::opts(); - base.vendor = "win7".into(); - base.rustc_abi = Some(RustcAbi::X86Sse2); - base.cpu = "pentium4".into(); - base.max_atomic_width = Some(64); - base.supported_sanitizers = SanitizerSet::ADDRESS; - // On Windows 7 32-bit, the alignment characteristic of the TLS Directory - // don't appear to be respected by the PE Loader, leading to crashes. As - // a result, let's disable has_thread_local to make sure TLS goes through - // the emulation layer. - // See https://github.com/rust-lang/rust/issues/138903 - base.has_thread_local = false; + let mut base = TargetOptions { + vendor: "win7".into(), + rustc_abi: Some(RustcAbi::X86Sse2), + cpu: "pentium4".into(), + max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS, + // On Windows 7 32-bit, the alignment characteristic of the TLS Directory + // don't appear to be respected by the PE Loader, leading to crashes. As + // a result, let's disable has_thread_local to make sure TLS goes through + // the emulation layer. + // See https://github.com/rust-lang/rust/issues/138903 + has_thread_local: false, + ..base::windows_msvc::opts() + }; base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs index 79035c791156d..498d8182ad589 100644 --- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs @@ -1,15 +1,17 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Cc, LinkerFlavor, Target, TargetMetadata, base}; +use crate::spec::{Arch, Cc, LinkerFlavor, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::solaris::opts(); - base.endian = Endian::Big; + let mut base = TargetOptions { + endian: Endian::Big, + // llvm calls this "v9" + cpu: "v9".into(), + vendor: "sun".into(), + max_atomic_width: Some(64), + ..base::solaris::opts() + }; base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); - // llvm calls this "v9" - base.cpu = "v9".into(); - base.vendor = "sun".into(); - base.max_atomic_width = Some(64); Target { llvm_target: "sparcv9-sun-solaris".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index 7b8d5def3a70b..39ebe62430479 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -1,16 +1,19 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetMetadata, base, + Arch, Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { - let mut base = base::solaris::opts(); + let mut base = TargetOptions { + cpu: "x86-64".into(), + plt_by_default: false, + vendor: "pc".into(), + max_atomic_width: Some(64), + stack_probes: StackProbeType::Inline, + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD, + ..base::solaris::opts() + }; base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); - base.cpu = "x86-64".into(); - base.plt_by_default = false; - base.vendor = "pc".into(); - base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::Inline; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; Target { llvm_target: "x86_64-pc-solaris".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs index 22a1a126b8912..0bd4215855264 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs @@ -1,18 +1,20 @@ -use crate::spec::{Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, base}; +use crate::spec::{Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::windows_gnu::opts(); - base.vendor = "win7".into(); - base.cpu = "x86-64".into(); - base.plt_by_default = false; + let mut base = TargetOptions { + vendor: "win7".into(), + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + linker: Some("x86_64-w64-mingw32-gcc".into()), + ..base::windows_gnu::opts() + }; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "i386pep", "--high-entropy-va"], ); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]); - base.max_atomic_width = Some(64); - base.linker = Some("x86_64-w64-mingw32-gcc".into()); Target { llvm_target: "x86_64-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 99b59154811f2..1cc2efaae5f5f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -1,12 +1,14 @@ -use crate::spec::{Arch, SanitizerSet, Target, TargetMetadata, base}; +use crate::spec::{Arch, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::windows_msvc::opts(); - base.vendor = "win7".into(); - base.cpu = "x86-64".into(); - base.plt_by_default = false; - base.max_atomic_width = Some(64); - base.supported_sanitizers = SanitizerSet::ADDRESS; + let base = TargetOptions { + vendor: "win7".into(), + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS, + ..base::windows_msvc::opts() + }; Target { llvm_target: "x86_64-pc-windows-msvc".into(), diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7d395eb780346..9e3aeed69572f 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1503,7 +1503,7 @@ macro_rules! int_impl { } } - /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// Strict shift right. Computes `self >> rhs`, panicking if `rhs` is /// larger than or equal to the number of bits in `self`. /// /// # Panics diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2996e7b00da4e..8b3b122998774 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1900,7 +1900,7 @@ macro_rules! uint_impl { } } - /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// Strict shift right. Computes `self >> rhs`, panicking if `rhs` is /// larger than or equal to the number of bits in `self`. /// /// # Panics diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index d09949e6868d6..8af197212f8bd 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1215,7 +1215,6 @@ impl LinkCollector<'_, '_> { || !did.is_local() } - #[allow(rustc::potential_query_instability)] pub(crate) fn resolve_ambiguities(&mut self) { let mut ambiguous_links = mem::take(&mut self.ambiguous_links); for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 304ae00b01a92..a4f8e9ccaab99 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -715,7 +715,7 @@ impl<'tcx> MiriMachine<'tcx> { match target.arch { Arch::Wasm32 | Arch::Wasm64 => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances Arch::AArch64 => { - if target.options.vendor.as_ref() == "apple" { + if target.is_like_darwin { // No "definitive" source, but see: // https://www.wwdcnotes.com/notes/wwdc20/10214/ // https://github.com/ziglang/zig/issues/11308 etc. diff --git a/tests/run-make/rustdoc-test-builder/builder.rs b/tests/run-make/rustdoc-test-builder/builder.rs new file mode 100644 index 0000000000000..b5a2c8ae346ea --- /dev/null +++ b/tests/run-make/rustdoc-test-builder/builder.rs @@ -0,0 +1,23 @@ +use std::ffi::OsString; +use std::path::PathBuf; +use std::process::{self, Command}; +use std::{env, fs}; + +fn main() { + let args: Vec = env::args_os().collect(); + let log_path = env::var_os("BUILDER_LOG").map(PathBuf::from).expect("BUILDER_LOG must be set"); + let real_rustc = env::var_os("REAL_RUSTC").expect("REAL_RUSTC must be set"); + + let log_contents = + args.iter().skip(1).map(|arg| arg.to_string_lossy()).collect::>().join("\n"); + fs::write(&log_path, log_contents).expect("failed to write builder log"); + + let status = Command::new(real_rustc) + .args(args.iter().skip(1)) + .status() + .expect("failed to invoke real rustc"); + + if !status.success() { + process::exit(status.code().unwrap_or(1)); + } +} diff --git a/tests/run-make/rustdoc-test-builder/doctest.rs b/tests/run-make/rustdoc-test-builder/doctest.rs new file mode 100644 index 0000000000000..1a4ff6a2fdd76 --- /dev/null +++ b/tests/run-make/rustdoc-test-builder/doctest.rs @@ -0,0 +1,3 @@ +//! ```rust +//! assert_eq!(2 + 2, 4); +//! ``` diff --git a/tests/run-make/rustdoc-test-builder/rmake.rs b/tests/run-make/rustdoc-test-builder/rmake.rs index 9aa8143dc1dc4..d10a3c92cae42 100644 --- a/tests/run-make/rustdoc-test-builder/rmake.rs +++ b/tests/run-make/rustdoc-test-builder/rmake.rs @@ -1,11 +1,14 @@ -// This test ensures that if the rustdoc test binary is not executable, it will -// gracefully fail and not panic. +// This test validates the `--test-builder` rustdoc option. +// It ensures that: +// 1. When the test-builder path points to a non-executable file, rustdoc gracefully fails +// 2. When the test-builder path points to a valid executable, it receives rustc arguments //@ needs-target-std -use run_make_support::{path, rfs, rustdoc}; +use run_make_support::{bare_rustc, path, rfs, rustc_path, rustdoc, target}; fn main() { + // Test 1: Verify that a non-executable test-builder fails gracefully let absolute_path = path("foo.rs").canonicalize().expect("failed to get absolute path"); let output = rustdoc() .input("foo.rs") @@ -19,4 +22,37 @@ fn main() { output.assert_stdout_contains("Failed to spawn "); // ... and that we didn't panic. output.assert_not_ice(); + + // Some targets (for example wasm) cannot execute doctests directly even with a runner, + // so only exercise the success path when the target can run on the host. + if target().contains("wasm") || std::env::var_os("REMOTE_TEST_CLIENT").is_some() { + return; + } + + // Test 2: Verify that a valid test-builder is invoked with correct arguments + // Build a custom test-builder that logs its arguments and forwards to rustc. + // Use `bare_rustc` so we compile for the host architecture even in cross builds. + let builder_bin = path("builder-bin"); + bare_rustc().input("builder.rs").output(&builder_bin).run(); + + let log_path = path("builder.log"); + let _ = std::fs::remove_file(&log_path); + + // Run rustdoc with our custom test-builder + rustdoc() + .input("doctest.rs") + .arg("--test") + .arg("-Zunstable-options") + .arg("--test-builder") + .arg(&builder_bin) + .env("REAL_RUSTC", rustc_path()) + .env("BUILDER_LOG", &log_path) + .run(); + + // Verify the custom builder was invoked with rustc-style arguments + let log_contents = rfs::read_to_string(&log_path); + assert!( + log_contents.contains("--crate-type"), + "expected builder to receive rustc arguments, got:\n{log_contents}" + ); } diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 9241141ef9a6c..2a627cc05b93b 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -60,3 +60,38 @@ cfg_select! { cfg_select! {} //~^ ERROR none of the predicates in this `cfg_select` evaluated to true + +cfg_select! { + => {} + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>` +} + +cfg_select! { + () => {} + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(` +} + +cfg_select! { + "str" => {} + //~^ ERROR malformed `cfg_select` macro input [E0539] +} + +cfg_select! { + a::b => {} + //~^ ERROR malformed `cfg_select` macro input [E0539] +} + +cfg_select! { + a() => {} + //~^ ERROR invalid predicate `a` [E0537] +} + +cfg_select! { + a + 1 => {} + //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `+` +} + +cfg_select! { + cfg!() => {} + //~^ ERROR expected one of `(`, `::`, `=>`, or `=`, found `!` +} diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 7280f35c16f93..3a5d2b0a1e1ee 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -21,5 +21,51 @@ error: none of the predicates in this `cfg_select` evaluated to true LL | cfg_select! {} | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>` + --> $DIR/cfg_select.rs:65:5 + | +LL | => {} + | ^^ + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(` + --> $DIR/cfg_select.rs:70:5 + | +LL | () => {} + | ^ + +error[E0539]: malformed `cfg_select` macro input + --> $DIR/cfg_select.rs:75:5 + | +LL | "str" => {} + | ^^^^^ expected a valid identifier here + | + +error[E0539]: malformed `cfg_select` macro input + --> $DIR/cfg_select.rs:80:5 + | +LL | a::b => {} + | ^^^^ expected a valid identifier here + | + +error[E0537]: invalid predicate `a` + --> $DIR/cfg_select.rs:85:5 + | +LL | a() => {} + | ^^^ + +error: expected one of `(`, `::`, `=>`, or `=`, found `+` + --> $DIR/cfg_select.rs:90:7 + | +LL | a + 1 => {} + | ^ expected one of `(`, `::`, `=>`, or `=` + +error: expected one of `(`, `::`, `=>`, or `=`, found `!` + --> $DIR/cfg_select.rs:95:8 + | +LL | cfg!() => {} + | ^ expected one of `(`, `::`, `=>`, or `=` + +error: aborting due to 9 previous errors; 1 warning emitted +Some errors have detailed explanations: E0537, E0539. +For more information about an error, try `rustc --explain E0537`.