diff options
207 files changed, 3261 insertions, 1748 deletions
diff --git a/Cargo.lock b/Cargo.lock index f9f8362fb7e..538e88355ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,7 +311,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.63.0" +version = "0.64.0" dependencies = [ "anyhow", "atty", @@ -970,9 +970,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc6d233563261f8db6ffb83bbaad5a73837a6e6b28868e926337ebbdece0be3" +checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" dependencies = [ "curl-sys", "libc", @@ -985,9 +985,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.51+curl-7.80.0" +version = "0.4.55+curl-7.83.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d130987e6a6a34fe0889e1083022fa48cd90e6709a84be3fb8dd95801de5af20" +checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" dependencies = [ "cc", "libc", @@ -1898,6 +1898,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] +name = "jemalloc-sys" +version = "0.5.0+5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f655c3ecfa6b0d03634595b4b54551d4bd5ac208b9e0124873949a7ab168f70b" +dependencies = [ + "cc", + "fs_extra", + "libc", +] + +[[package]] name = "jobserver" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3360,9 +3371,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" name = "rustc-main" version = "0.0.0" dependencies = [ + "jemalloc-sys", "rustc_codegen_ssa", "rustc_driver", - "tikv-jemalloc-sys", ] [[package]] @@ -5235,17 +5246,6 @@ name = "tier-check" version = "0.1.0" [[package]] -name = "tikv-jemalloc-sys" -version = "0.4.1+5.2.1-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a26331b05179d4cb505c8d6814a7e18d298972f0a551b0e3cefccff927f86d3" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - -[[package]] name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index b642e891956..5e0bb1a7f95 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -10,13 +10,13 @@ rustc_driver = { path = "../rustc_driver" } # crate is intended to be used by codegen backends, which may not be in-tree. rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } -[dependencies.tikv-jemalloc-sys] -version = '0.4.0' +[dependencies.jemalloc-sys] +version = "0.5.0" optional = true features = ['unprefixed_malloc_on_supported_platforms'] [features] -jemalloc = ['tikv-jemalloc-sys'] +jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] max_level_info = ['rustc_driver/max_level_info'] rustc_use_parallel_compiler = ['rustc_driver/rustc_use_parallel_compiler'] diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 4edd095af10..0de1a781913 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -22,12 +22,10 @@ // The two crates we link to here, `std` and `rustc_driver`, are both dynamic // libraries. So we must reference jemalloc symbols one way or another, because // this file is the only object code in the rustc executable. -#[cfg(feature = "tikv-jemalloc-sys")] -use tikv_jemalloc_sys as jemalloc_sys; fn main() { // See the comment at the top of this file for an explanation of this. - #[cfg(feature = "tikv-jemalloc-sys")] + #[cfg(feature = "jemalloc-sys")] { use std::os::raw::{c_int, c_void}; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 14e5d2ae623..0520c9ac60c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1463,10 +1463,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let GenericBound::Trait(ref poly, modify) = *bound { match (ctxt, modify) { (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { - let mut err = self.err_handler().struct_span_err( - poly.span, - &format!("`?Trait` is not permitted in supertraits"), - ); + let mut err = self + .err_handler() + .struct_span_err(poly.span, "`?Trait` is not permitted in supertraits"); let path_str = pprust::path_to_string(&poly.trait_ref.path); err.note(&format!("traits are `?{}` by default", path_str)); err.emit(); @@ -1474,7 +1473,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { let mut err = self.err_handler().struct_span_err( poly.span, - &format!("`?Trait` is not permitted in trait object types"), + "`?Trait` is not permitted in trait object types", ); err.emit(); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2704cb8d785..c8f1e1dbb01 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -454,6 +454,15 @@ pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> { sess.first_attr_value_str_by_name(attrs, sym::crate_name) } +#[derive(Clone, Debug)] +pub struct Condition { + pub name: Symbol, + pub name_span: Span, + pub value: Option<Symbol>, + pub value_span: Option<Span>, + pub span: Span, +} + /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( cfg: &ast::MetaItem, @@ -462,70 +471,42 @@ pub fn cfg_matches( features: Option<&Features>, ) -> bool { eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg, sess, features); - let error = |span, msg| { - sess.span_diagnostic.span_err(span, msg); - true - }; - if cfg.path.segments.len() != 1 { - return error(cfg.path.span, "`cfg` predicate key must be an identifier"); - } - match &cfg.kind { - MetaItemKind::List(..) => { - error(cfg.span, "unexpected parentheses after `cfg` predicate key") - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - handle_errors( - sess, - lit.span, - AttrError::UnsupportedLiteral( - "literal in `cfg` predicate value must be a string", - lit.kind.is_bytestr(), - ), + try_gate_cfg(cfg.name, cfg.span, sess, features); + if let Some(names_valid) = &sess.check_config.names_valid { + if !names_valid.contains(&cfg.name) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + lint_node_id, + "unexpected `cfg` condition name", + BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None), ); - true } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - let name = ident.name; - let value = cfg.value_str(); - if let Some(names_valid) = &sess.check_config.names_valid { - if !names_valid.contains(&name) { - sess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - "unexpected `cfg` condition name", - BuiltinLintDiagnostics::UnexpectedCfg((name, ident.span), None), - ); - } - } - if let Some(value) = value { - if let Some(values) = &sess.check_config.values_valid.get(&name) { - if !values.contains(&value) { - sess.buffer_lint_with_diagnostic( - UNEXPECTED_CFGS, - cfg.span, - lint_node_id, - "unexpected `cfg` condition value", - BuiltinLintDiagnostics::UnexpectedCfg( - (name, ident.span), - Some((value, cfg.name_value_literal_span().unwrap())), - ), - ); - } - } + } + if let Some(value) = cfg.value { + if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) { + if !values.contains(&value) { + sess.buffer_lint_with_diagnostic( + UNEXPECTED_CFGS, + cfg.span, + lint_node_id, + "unexpected `cfg` condition value", + BuiltinLintDiagnostics::UnexpectedCfg( + (cfg.name, cfg.name_span), + cfg.value_span.map(|vs| (value, vs)), + ), + ); } - sess.config.contains(&(name, value)) } } + sess.config.contains(&(cfg.name, cfg.value)) }) } -fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| cfg.has_name(sym)); +fn try_gate_cfg(name: Symbol, span: Span, sess: &ParseSess, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(&gated_cfg, cfg.span, sess, feats); + gate_cfg(&gated_cfg, span, sess, feats); } } @@ -563,11 +544,11 @@ pub fn eval_condition( cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>, - eval: &mut impl FnMut(&ast::MetaItem) -> bool, + eval: &mut impl FnMut(Condition) -> bool, ) -> bool { match cfg.kind { ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { - try_gate_cfg(cfg, sess, features); + try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { (sym, span) @@ -649,6 +630,25 @@ pub fn eval_condition( !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) } + sym::target => { + if let Some(features) = features && !features.cfg_target_compact { + feature_err( + sess, + sym::cfg_target_compact, + cfg.span, + &"compact `cfg(target(..))` is experimental and subject to change" + ).emit(); + } + + mis.iter().fold(true, |res, mi| { + let mut mi = mi.meta_item().unwrap().clone(); + if let [seg, ..] = &mut mi.path.segments[..] { + seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); + } + + res & eval_condition(&mi, sess, features, eval) + }) + } _ => { struct_span_err!( sess.span_diagnostic, @@ -662,7 +662,32 @@ pub fn eval_condition( } } } - ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => eval(cfg), + ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { + sess.span_diagnostic + .span_err(cfg.path.span, "`cfg` predicate key must be an identifier"); + true + } + MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => { + handle_errors( + sess, + lit.span, + AttrError::UnsupportedLiteral( + "literal in `cfg` predicate value must be a string", + lit.kind.is_bytestr(), + ), + ); + true + } + ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { + let ident = cfg.ident().expect("multi-segment cfg predicate"); + eval(Condition { + name: ident.name, + name_span: ident.span, + value: cfg.value_str(), + value_span: cfg.name_value_literal_span(), + span: cfg.span, + }) + } } } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index c95c1c40a34..c3f9f0cf362 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,6 +4,7 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![feature(let_chains)] #![feature(let_else)] #[macro_use] diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 48b8230857a..35f805ce76e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -522,10 +522,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => None, }; - if defined_hir.is_some() { + if let Some(def_hir) = defined_hir { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); - let upvar_def_span = self.infcx.tcx.hir().span(defined_hir.unwrap()); - let upvar_span = upvars_map.get(&defined_hir.unwrap()).unwrap().span; + let upvar_def_span = self.infcx.tcx.hir().span(def_hir); + let upvar_span = upvars_map.get(&def_hir).unwrap().span; diag.span_label(upvar_def_span, "variable defined here"); diag.span_label(upvar_span, "variable captured here"); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 0fd23fd281e..53369afae27 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -257,7 +257,7 @@ pub struct Substructure<'a> { pub type_ident: Ident, /// ident of the method pub method_ident: Ident, - /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)][ptr]` arguments + /// dereferenced access to any [`Self_`] or [`Ptr(Self_, _)`][ptr] arguments /// /// [`Self_`]: ty::Ty::Self_ /// [ptr]: ty::Ty::Ptr @@ -1039,7 +1039,9 @@ impl<'a> MethodDef<'a> { let span = trait_.span; let mut patterns = Vec::new(); for i in 0..self_args.len() { - let struct_path = cx.path(span, vec![type_ident]); + // We could use `type_ident` instead of `Self`, but in the case of a type parameter + // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343 + let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); let (pat, ident_expr) = trait_.create_struct_pattern( cx, struct_path, diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 407ca2301e1..71e98bb447a 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -22,21 +22,16 @@ struct ProcMacroDerive { attrs: Vec<Symbol>, } -enum ProcMacroDefType { - Attr, - Bang, -} - struct ProcMacroDef { id: NodeId, function_name: Ident, span: Span, - def_type: ProcMacroDefType, } enum ProcMacro { Derive(ProcMacroDerive), - Def(ProcMacroDef), + Attr(ProcMacroDef), + Bang(ProcMacroDef), } struct CollectProcMacros<'a> { @@ -128,11 +123,10 @@ impl<'a> CollectProcMacros<'a> { fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Def(ProcMacroDef { + self.macros.push(ProcMacro::Attr(ProcMacroDef { id: item.id, span: item.span, function_name: item.ident, - def_type: ProcMacroDefType::Attr, })); } else { let msg = if !self.in_root { @@ -147,11 +141,10 @@ impl<'a> CollectProcMacros<'a> { fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.kind.is_pub() { - self.macros.push(ProcMacro::Def(ProcMacroDef { + self.macros.push(ProcMacro::Bang(ProcMacroDef { id: item.id, span: item.span, function_name: item.ident, - def_type: ProcMacroDefType::Bang, })); } else { let msg = if !self.in_root { @@ -308,6 +301,17 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| { cx.expr_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty, method])) }; + let attr_or_bang = |cx: &mut ExtCtxt<'_>, ca: &ProcMacroDef, ident| { + cx.resolver.declare_proc_macro(ca.id); + cx.expr_call( + span, + proc_macro_ty_method_path(cx, ident), + vec![ + cx.expr_str(ca.span, ca.function_name.name), + local_path(cx, ca.span, ca.function_name), + ], + ) + }; macros .iter() .map(|m| match m { @@ -329,22 +333,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { ], ) } - ProcMacro::Def(ca) => { - cx.resolver.declare_proc_macro(ca.id); - let ident = match ca.def_type { - ProcMacroDefType::Attr => attr, - ProcMacroDefType::Bang => bang, - }; - - cx.expr_call( - span, - proc_macro_ty_method_path(cx, ident), - vec![ - cx.expr_str(ca.span, ca.function_name.name), - local_path(cx, ca.span, ca.function_name), - ], - ) - } + ProcMacro::Attr(ca) => attr_or_bang(cx, &ca, attr), + ProcMacro::Bang(ca) => attr_or_bang(cx, &ca, bang), }) .collect() }; diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 41f88f119e2..479328a557c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -61,24 +61,6 @@ enum ExtremumOperation { Min, } -trait EnumClone { - fn clone(&self) -> Self; -} - -impl EnumClone for AtomicOrdering { - fn clone(&self) -> Self { - match *self { - AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, - AtomicOrdering::Unordered => AtomicOrdering::Unordered, - AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, - AtomicOrdering::Acquire => AtomicOrdering::Acquire, - AtomicOrdering::Release => AtomicOrdering::Release, - AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease, - AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent, - } - } -} - pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, @@ -103,9 +85,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { match order { // TODO(antoyo): does this make sense? AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, - _ => order.clone(), + _ => order, }; - let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size)); + let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering, Size::from_bytes(size)); let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); let return_value = func.new_local(None, previous_value.get_type(), "return_value"); self.llbb().add_assignment(None, previous_var, previous_value); @@ -1384,9 +1366,8 @@ impl ToGccOrdering for AtomicOrdering { let ordering = match self { - AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. AtomicOrdering::Unordered => __ATOMIC_RELAXED, - AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Relaxed => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, AtomicOrdering::Release => __ATOMIC_RELEASE, AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 37409dbb447..1d9a4655db6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -381,9 +381,8 @@ pub enum AtomicOrdering { impl AtomicOrdering { pub fn from_generic(ao: rustc_codegen_ssa::common::AtomicOrdering) -> Self { match ao { - rustc_codegen_ssa::common::AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, rustc_codegen_ssa::common::AtomicOrdering::Unordered => AtomicOrdering::Unordered, - rustc_codegen_ssa::common::AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, + rustc_codegen_ssa::common::AtomicOrdering::Relaxed => AtomicOrdering::Monotonic, rustc_codegen_ssa::common::AtomicOrdering::Acquire => AtomicOrdering::Acquire, rustc_codegen_ssa::common::AtomicOrdering::Release => AtomicOrdering::Release, rustc_codegen_ssa::common::AtomicOrdering::AcquireRelease => { diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 17071ba1b5b..6c29692bd3b 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -105,12 +105,7 @@ impl Command { } Program::Lld(ref p, flavor) => { let mut c = process::Command::new(p); - c.arg("-flavor").arg(match flavor { - LldFlavor::Wasm => "wasm", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Ld64 => "darwin", - }); + c.arg("-flavor").arg(flavor.as_str()); if let LldFlavor::Wasm = flavor { // LLVM expects host-specific formatting for @file // arguments, but we always generate posix formatted files diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 04ec1e7f3c1..00f85852493 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2698,37 +2698,20 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { - if sess.target.lld_flavor == LldFlavor::Ld64 { - let tools_path = sess.get_tools_search_paths(false); - let ld64_exe = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .map(|p| { - p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" }) - }) - .find(|p| p.exists()) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found")); - cmd.cmd().arg({ - let mut arg = OsString::from("-fuse-ld="); - arg.push(ld64_exe); - arg - }); - } else { - let tools_path = sess.get_tools_search_paths(false); - let lld_path = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .find(|p| { - p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }) - .exists() - }) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); - cmd.cmd().arg({ - let mut arg = OsString::from("-B"); - arg.push(lld_path); - arg - }); - } + let tools_path = sess.get_tools_search_paths(false); + let gcc_ld_dir = tools_path + .into_iter() + .map(|p| p.join("gcc-ld")) + .find(|p| { + p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() + }) + .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); + cmd.arg({ + let mut arg = OsString::from("-B"); + arg.push(gcc_ld_dir); + arg + }); + cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str())); } } } else { diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 1574b30497b..8ca1a6084cf 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -11,6 +11,7 @@ use rustc_span::Span; use crate::base; use crate::traits::*; +#[derive(Copy, Clone)] pub enum IntPredicate { IntEQ, IntNE, @@ -24,6 +25,7 @@ pub enum IntPredicate { IntSLE, } +#[derive(Copy, Clone)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -43,6 +45,7 @@ pub enum RealPredicate { RealPredicateTrue, } +#[derive(Copy, Clone)] pub enum AtomicRmwBinOp { AtomicXchg, AtomicAdd, @@ -57,17 +60,17 @@ pub enum AtomicRmwBinOp { AtomicUMin, } +#[derive(Copy, Clone)] pub enum AtomicOrdering { - NotAtomic, Unordered, - Monotonic, - // Consume, // Not specified yet. + Relaxed, Acquire, Release, AcquireRelease, SequentiallyConsistent, } +#[derive(Copy, Clone)] pub enum SynchronizationScope { SingleThread, CrossThread, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6d6d3ae01f4..0ed4c3f1d94 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -388,17 +388,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 2 => (SequentiallyConsistent, SequentiallyConsistent), 3 => match split[2] { "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), + "relaxed" => (Relaxed, Relaxed), "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), + "rel" => (Release, Relaxed), "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Relaxed), "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), }, 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + ("acq", "failrelaxed") if is_cxchg => (Acquire, Relaxed), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Relaxed), _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), }, _ => bx.sess().fatal("Atomic intrinsic not in correct format"), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index b6a7bcae932..3185b952ab8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; for elem in place_ref.projection[base..].iter() { - cg_base = match elem.clone() { + cg_base = match *elem { mir::ProjectionElem::Deref => { // a box with a non-zst allocator should not be directly dereferenced if cg_base.layout.ty.is_box() && !cg_base.layout.field(cx, 1).is_zst() { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 4c84bd090cb..0c954ac6e5f 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -520,13 +520,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { frame .instance .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value) - .or_else(|e| { + .map_err(|e| { self.tcx.sess.delay_span_bug( self.cur_span(), format!("failed to normalize {}", e.get_type_for_failure()).as_str(), ); - Err(InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)) + InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric) }) } @@ -1009,11 +1009,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug } } - write!( - fmt, - ": {:?}", - self.ecx.dump_allocs(allocs.into_iter().filter_map(|x| x).collect()) - ) + write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect())) } Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) { Some(alloc_id) => write!( diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index dc49a45fe73..955480a1a74 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -906,16 +906,12 @@ where } // We still require the sizes to match. if src.layout.size != dest.layout.size { - // FIXME: This should be an assert instead of an error, but if we transmute within an - // array length computation, `typeck` may not have yet been run and errored out. In fact - // most likely we *are* running `typeck` right now. Investigate whether we can bail out - // on `typeck_results().has_errors` at all const eval entry points. - debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); - self.tcx.sess.delay_span_bug( + span_bug!( self.cur_span(), - "size-changing transmute, should have been caught by transmute checking", + "size-changing transmute, should have been caught by transmute checking: {:#?}\ndest: {:#?}", + src, + dest ); - throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 76ae17f28c6..0d072046d58 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -13,8 +13,6 @@ #![feature(control_flow_enum)] #![feature(core_intrinsics)] #![feature(extend_one)] -#![feature(generator_trait)] -#![feature(generators)] #![feature(let_else)] #![feature(hash_raw_entry)] #![feature(hasher_prefixfree_extras)] @@ -114,9 +112,6 @@ pub mod unhash; pub use ena::undo_log; pub use ena::unify; -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - pub struct OnDrop<F: Fn()>(pub F); impl<F: Fn()> OnDrop<F> { @@ -135,26 +130,6 @@ impl<F: Fn()> Drop for OnDrop<F> { } } -struct IterFromGenerator<G>(G); - -impl<G: Generator<Return = ()> + Unpin> Iterator for IterFromGenerator<G> { - type Item = G::Yield; - - fn next(&mut self) -> Option<Self::Item> { - match Pin::new(&mut self.0).resume(()) { - GeneratorState::Yielded(n) => Some(n), - GeneratorState::Complete(_) => None, - } - } -} - -/// An adapter for turning a generator closure into an iterator, similar to `iter::from_fn`. -pub fn iter_from_generator<G: Generator<Return = ()> + Unpin>( - generator: G, -) -> impl Iterator<Item = G::Yield> { - IterFromGenerator(generator) -} - // See comments in src/librustc_middle/lib.rs #[doc(hidden)] pub fn __noop_fix_for_27438() {} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e48ce602185..bb671b8705e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -266,7 +266,7 @@ where } } -pub trait ProcMacro { +pub trait BangProcMacro { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, @@ -275,7 +275,7 @@ pub trait ProcMacro { ) -> Result<TokenStream, ErrorGuaranteed>; } -impl<F> ProcMacro for F +impl<F> BangProcMacro for F where F: Fn(TokenStream) -> TokenStream, { @@ -640,7 +640,7 @@ pub enum SyntaxExtensionKind { /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. - Box<dyn ProcMacro + sync::Sync + sync::Send>, + Box<dyn BangProcMacro + sync::Sync + sync::Send>, ), /// An AST-based function-like macro. diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index b3679b31c6c..eb59c5a1854 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -17,7 +17,7 @@ pub struct BangProcMacro { pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>, } -impl base::ProcMacro for BangProcMacro { +impl base::BangProcMacro for BangProcMacro { fn expand<'cx>( &self, ecx: &'cx mut ExtCtxt<'_>, @@ -72,11 +72,11 @@ impl base::AttrProcMacro for AttrProcMacro { } } -pub struct ProcMacroDerive { +pub struct DeriveProcMacro { pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>, } -impl MultiItemModifier for ProcMacroDerive { +impl MultiItemModifier for DeriveProcMacro { fn expand( &self, ecx: &mut ExtCtxt<'_>, diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1956327dfab..5a02661513c 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -319,6 +319,8 @@ declare_features! ( (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. (active, cfg_target_abi, "1.55.0", Some(80970), None), + /// Allows `cfg(target(abi = "..."))`. + (active, cfg_target_compact, "1.63.0", Some(96901), None), /// Allows `cfg(target_has_atomic_load_store = "...")`. (active, cfg_target_has_atomic, "1.60.0", Some(94039), None), /// Allows `cfg(target_has_atomic_equal_alignment = "...")`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index afbf48fceb5..e6c9c6693c5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -937,7 +937,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // // maybe move the check to a MIR pass? tcx.ensure().check_mod_liveness(module); - tcx.ensure().check_mod_intrinsics(module); }); }); } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index c152815eeca..f2ec80b0c1b 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -69,13 +69,7 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { let verbose_entry_exit = match env::var_os(String::from(env) + "_ENTRY_EXIT") { None => false, - Some(v) => { - if &v == "0" { - false - } else { - true - } - } + Some(v) => &v != "0", }; let layer = tracing_tree::HierarchicalLayer::default() diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 4c5d13dfa6c..eb008fd2693 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -3,6 +3,7 @@ #![feature(drain_filter)] #![feature(generators)] #![feature(generic_associated_types)] +#![feature(iter_from_generator)] #![feature(let_chains)] #![feature(let_else)] #![feature(nll)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 8d044be195a..95892d83414 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -418,10 +418,11 @@ impl<'tcx> Collector<'tcx> { // involved or not, library reordering and kind overriding without // explicit `:rename` in particular. if lib.has_modifiers() || passed_lib.has_modifiers() { - self.tcx.sess.span_err( - self.tcx.def_span(lib.foreign_module.unwrap()), - "overriding linking modifiers from command line is not supported" - ); + let msg = "overriding linking modifiers from command line is not supported"; + match lib.foreign_module { + Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg), + None => self.tcx.sess.err(msg), + }; } if passed_lib.kind != NativeLibKind::Unspecified { lib.kind = passed_lib.kind; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 1420871b025..7f0b595347f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -11,7 +11,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; -use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; +use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -837,7 +837,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>(); ( trait_name, - SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })), + SyntaxExtensionKind::Derive(Box::new(DeriveProcMacro { client })), helper_attrs, ) } @@ -1565,10 +1565,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { src_hash, start_pos, end_pos, - mut lines, - mut multibyte_chars, - mut non_narrow_chars, - mut normalized_pos, + lines, + multibyte_chars, + non_narrow_chars, + normalized_pos, name_hash, .. } = source_file_to_import; @@ -1605,24 +1605,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let source_length = (end_pos - start_pos).to_usize(); - // Translate line-start positions and multibyte character - // position into frame of reference local to file. - // `SourceMap::new_imported_source_file()` will then translate those - // coordinates to their new global frame of reference when the - // offset of the SourceFile is known. - for pos in &mut lines { - *pos = *pos - start_pos; - } - for mbc in &mut multibyte_chars { - mbc.pos = mbc.pos - start_pos; - } - for swc in &mut non_narrow_chars { - *swc = *swc - start_pos; - } - for np in &mut normalized_pos { - np.pos = np.pos - start_pos; - } - let local_version = sess.source_map().new_imported_source_file( name, src_hash, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1e83434b9d0..339d2fc0867 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -4,7 +4,6 @@ use crate::rmeta::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_data_structures::iter_from_generator; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; use rustc_hir as hir; @@ -39,6 +38,7 @@ use rustc_span::{ use rustc_target::abi::VariantIdx; use std::borrow::Borrow; use std::hash::Hash; +use std::iter; use std::num::NonZeroUsize; use tracing::{debug, trace}; @@ -536,9 +536,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_crate_root(&mut self) -> LazyValue<CrateRoot> { let tcx = self.tcx; - let mut i = self.position(); + let mut i = 0; + let preamble_bytes = self.position() - i; // Encode the crate deps + i = self.position(); let crate_deps = self.encode_crate_deps(); let dylib_dependency_formats = self.encode_dylib_dependency_formats(); let dep_bytes = self.position() - i; @@ -564,7 +566,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let native_libraries = self.encode_native_libraries(); let native_lib_bytes = self.position() - i; + i = self.position(); let foreign_modules = self.encode_foreign_modules(); + let foreign_modules_bytes = self.position() - i; // Encode DefPathTable i = self.position(); @@ -584,6 +588,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { i = self.position(); let incoherent_impls = self.encode_incoherent_impls(); let incoherent_impls_bytes = self.position() - i; + // Encode MIR. i = self.position(); self.encode_mir(); @@ -596,6 +601,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let item_bytes = self.position() - i; // Encode the allocation index + i = self.position(); let interpret_alloc_index = { let mut interpret_alloc_index = Vec::new(); let mut n = 0; @@ -618,6 +624,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } self.lazy_array(interpret_alloc_index) }; + let interpret_alloc_index_bytes = self.position() - i; // Encode the proc macro data. This affects 'tables', // so we need to do this before we encode the tables @@ -662,9 +669,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let source_map = self.encode_source_map(); let source_map_bytes = self.position() - i; + i = self.position(); let attrs = tcx.hir().krate_attrs(); let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator); - let root = self.lazy(CrateRoot { name: tcx.crate_name(LOCAL_CRATE), extra_filename: tcx.sess.opts.cg.extra_filename.clone(), @@ -707,9 +714,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { expn_hashes, def_path_hash_map, }); + let final_bytes = self.position() - i; let total_bytes = self.position(); + let computed_total_bytes = preamble_bytes + + dep_bytes + + lib_feature_bytes + + lang_item_bytes + + diagnostic_item_bytes + + native_lib_bytes + + foreign_modules_bytes + + def_path_table_bytes + + traits_bytes + + impls_bytes + + incoherent_impls_bytes + + mir_bytes + + item_bytes + + interpret_alloc_index_bytes + + proc_macro_data_bytes + + tables_bytes + + debugger_visualizers_bytes + + exported_symbols_bytes + + hygiene_bytes + + def_path_hash_map_bytes + + source_map_bytes + + final_bytes; + assert_eq!(total_bytes, computed_total_bytes); + if tcx.sess.meta_stats() { let mut zero_bytes = 0; for e in self.opaque.data.iter() { @@ -718,27 +750,41 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - eprintln!("metadata stats:"); - eprintln!(" dep bytes: {}", dep_bytes); - eprintln!(" lib feature bytes: {}", lib_feature_bytes); - eprintln!(" lang item bytes: {}", lang_item_bytes); - eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes); - eprintln!(" native bytes: {}", native_lib_bytes); - eprintln!(" debugger visualizers bytes: {}", debugger_visualizers_bytes); - eprintln!(" source_map bytes: {}", source_map_bytes); - eprintln!(" traits bytes: {}", traits_bytes); - eprintln!(" impls bytes: {}", impls_bytes); - eprintln!(" incoherent_impls bytes: {}", incoherent_impls_bytes); - eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); - eprintln!(" def-path table bytes: {}", def_path_table_bytes); - eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes); - eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); - eprintln!(" mir bytes: {}", mir_bytes); - eprintln!(" item bytes: {}", item_bytes); - eprintln!(" table bytes: {}", tables_bytes); - eprintln!(" hygiene bytes: {}", hygiene_bytes); - eprintln!(" zero bytes: {}", zero_bytes); - eprintln!(" total bytes: {}", total_bytes); + let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64; + let p = |label, bytes| { + eprintln!("{:>21}: {:>8} bytes ({:4.1}%)", label, bytes, perc(bytes)); + }; + + eprintln!(""); + eprintln!( + "{} metadata bytes, of which {} bytes ({:.1}%) are zero", + total_bytes, + zero_bytes, + perc(zero_bytes) + ); + p("preamble", preamble_bytes); + p("dep", dep_bytes); + p("lib feature", lib_feature_bytes); + p("lang item", lang_item_bytes); + p("diagnostic item", diagnostic_item_bytes); + p("native lib", native_lib_bytes); + p("foreign modules", foreign_modules_bytes); + p("def-path table", def_path_table_bytes); + p("traits", traits_bytes); + p("impls", impls_bytes); + p("incoherent_impls", incoherent_impls_bytes); + p("mir", mir_bytes); + p("item", item_bytes); + p("interpret_alloc_index", interpret_alloc_index_bytes); + p("proc-macro-data", proc_macro_data_bytes); + p("tables", tables_bytes); + p("debugger visualizers", debugger_visualizers_bytes); + p("exported symbols", exported_symbols_bytes); + p("hygiene", hygiene_bytes); + p("def-path hashes", def_path_hash_map_bytes); + p("source_map", source_map_bytes); + p("final", final_bytes); + eprintln!(""); } root @@ -1088,7 +1134,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { - record_array!(self.tables.children[def_id] <- iter_from_generator(|| { + record_array!(self.tables.children[def_id] <- iter::from_generator(|| { for item_id in md.item_ids { match tcx.hir().item(*item_id).kind { // Foreign items are planted into their parent modules diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index bb6b10149ab..cb6fd006c3e 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -149,8 +149,6 @@ pub enum InvalidProgramInfo<'tcx> { /// (which unfortunately typeck does not reject). /// Not using `FnAbiError` as that contains a nested `LayoutError`. FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), - /// An invalid transmute happened. - TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), /// SizeOf of unsized type was requested. SizeOfUnsizedType(Ty<'tcx>), } @@ -166,11 +164,6 @@ impl fmt::Display for InvalidProgramInfo<'_> { } Layout(ref err) => write!(f, "{}", err), FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err), - TransmuteSizeDiff(from_ty, to_ty) => write!( - f, - "transmuting `{}` to `{}` is not possible, because these types do not have the same size", - from_ty, to_ty - ), SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty), } } diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index 1bc53d3c9f1..c1e1cfef9f8 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -167,8 +167,7 @@ impl<'tcx> MirPatch<'tcx> { if loc.statement_index > body[loc.block].statements.len() { let term = body[loc.block].terminator(); for i in term.successors() { - stmts_and_targets - .push((Statement { source_info, kind: stmt.clone() }, i.clone())); + stmts_and_targets.push((Statement { source_info, kind: stmt.clone() }, i)); } delta += 1; continue; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 0c936b7ae10..68b81efaa00 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -804,10 +804,6 @@ rustc_queries! { desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) } } - query check_mod_intrinsics(key: LocalDefId) -> () { - desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) } - } - query check_mod_liveness(key: LocalDefId) -> () { desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } } diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index de4cc67893b..f7ced066062 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,8 +1,10 @@ use crate::mir::Mutability; +use crate::ty::subst::GenericArgKind; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; use std::fmt::Debug; use std::hash::Hash; +use std::iter; use self::SimplifiedTypeGen::*; @@ -72,6 +74,10 @@ pub enum TreatParams { /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. /// +/// **This function should only be used if you need to store or retrieve the type from some +/// hashmap. If you want to quickly decide whether two types may unify, use the [DeepRejectCtxt] +/// instead.** +/// /// The idea is to get something simple that we can use to quickly decide if two types could unify, /// for example during method lookup. If this function returns `Some(x)` it can only unify with /// types for which this method returns either `Some(x)` as well or `None`. @@ -182,3 +188,218 @@ impl<D: Copy + Debug + Eq> SimplifiedTypeGen<D> { } } } + +/// Given generic arguments from an obligation and an impl, +/// could these two be unified after replacing parameters in the +/// the impl with inference variables. +/// +/// For obligations, parameters won't be replaced by inference +/// variables and only unify with themselves. We treat them +/// the same way we treat placeholders. +/// +/// We also use this function during coherence. For coherence the +/// impls only have to overlap for some value, so we treat parameters +/// on both sides like inference variables. This behavior is toggled +/// using the `treat_obligation_params` field. +#[derive(Debug, Clone, Copy)] +pub struct DeepRejectCtxt { + pub treat_obligation_params: TreatParams, +} + +impl DeepRejectCtxt { + pub fn generic_args_may_unify( + self, + obligation_arg: ty::GenericArg<'_>, + impl_arg: ty::GenericArg<'_>, + ) -> bool { + match (obligation_arg.unpack(), impl_arg.unpack()) { + // We don't fast reject based on regions for now. + (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, + (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { + self.types_may_unify(obl, imp) + } + (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { + self.consts_may_unify(obl, imp) + } + _ => bug!("kind mismatch: {obligation_arg} {impl_arg}"), + } + } + + pub fn types_may_unify(self, obligation_ty: Ty<'_>, impl_ty: Ty<'_>) -> bool { + match impl_ty.kind() { + // Start by checking whether the type in the impl may unify with + // pretty much everything. Just return `true` in that case. + ty::Param(_) | ty::Projection(_) | ty::Error(_) => return true, + // These types only unify with inference variables or their own + // variant. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Str + | ty::Array(..) + | ty::Slice(..) + | ty::RawPtr(..) + | ty::Dynamic(..) + | ty::Ref(..) + | ty::Never + | ty::Tuple(..) + | ty::FnPtr(..) + | ty::Foreign(..) + | ty::Opaque(..) => {} + ty::FnDef(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), + } + + let k = impl_ty.kind(); + match *obligation_ty.kind() { + // Purely rigid types, use structural equivalence. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Foreign(_) => obligation_ty == impl_ty, + ty::Ref(_, obl_ty, obl_mutbl) => match k { + &ty::Ref(_, impl_ty, impl_mutbl) => { + obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) + } + _ => false, + }, + ty::Adt(obl_def, obl_substs) => match k { + &ty::Adt(impl_def, impl_substs) => { + obl_def == impl_def + && iter::zip(obl_substs, impl_substs) + .all(|(obl, imp)| self.generic_args_may_unify(obl, imp)) + } + _ => false, + }, + ty::Slice(obl_ty) => { + matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) + } + ty::Array(obl_ty, obl_len) => match k { + &ty::Array(impl_ty, impl_len) => { + self.types_may_unify(obl_ty, impl_ty) + && self.consts_may_unify(obl_len, impl_len) + } + _ => false, + }, + ty::Tuple(obl) => match k { + &ty::Tuple(imp) => { + obl.len() == imp.len() + && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + ty::RawPtr(obl) => match k { + ty::RawPtr(imp) => obl.mutbl == imp.mutbl && self.types_may_unify(obl.ty, imp.ty), + _ => false, + }, + ty::Dynamic(obl_preds, ..) => { + // Ideally we would walk the existential predicates here or at least + // compare their length. But considering that the relevant `Relate` impl + // actually sorts and deduplicates these, that doesn't work. + matches!(k, ty::Dynamic(impl_preds, ..) if + obl_preds.principal_def_id() == impl_preds.principal_def_id() + ) + } + ty::FnPtr(obl_sig) => match k { + ty::FnPtr(impl_sig) => { + let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } = + obl_sig.skip_binder(); + let impl_sig = impl_sig.skip_binder(); + + abi == impl_sig.abi + && c_variadic == impl_sig.c_variadic + && unsafety == impl_sig.unsafety + && inputs_and_output.len() == impl_sig.inputs_and_output.len() + && iter::zip(inputs_and_output, impl_sig.inputs_and_output) + .all(|(obl, imp)| self.types_may_unify(obl, imp)) + } + _ => false, + }, + + // Opaque types in impls should be forbidden, but that doesn't + // stop compilation. So this match arm should never return true + // if compilation succeeds. + ty::Opaque(..) => matches!(k, ty::Opaque(..)), + + // Impls cannot contain these types as these cannot be named directly. + ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false, + + ty::Placeholder(..) => false, + + // Depending on the value of `treat_obligation_params`, we either + // treat generic parameters like placeholders or like inference variables. + ty::Param(_) => match self.treat_obligation_params { + TreatParams::AsPlaceholder => false, + TreatParams::AsInfer => true, + }, + + ty::Infer(_) => true, + + // As we're walking the whole type, it may encounter projections + // inside of binders and what not, so we're just going to assume that + // projections can unify with other stuff. + // + // Looking forward to lazy normalization this is the safer strategy anyways. + ty::Projection(_) => true, + + ty::Error(_) => true, + + ty::GeneratorWitness(..) | ty::Bound(..) => { + bug!("unexpected obligation type: {:?}", obligation_ty) + } + } + } + + pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool { + match impl_ct.val() { + ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { + return true; + } + ty::ConstKind::Value(_) => {} + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + bug!("unexpected impl arg: {:?}", impl_ct) + } + } + + let k = impl_ct.val(); + match obligation_ct.val() { + ty::ConstKind::Param(_) => match self.treat_obligation_params { + TreatParams::AsPlaceholder => false, + TreatParams::AsInfer => true, + }, + + // As we don't necessarily eagerly evaluate constants, + // they might unify with any value. + ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => true, + ty::ConstKind::Value(obl) => match k { + ty::ConstKind::Value(imp) => { + // FIXME(valtrees): Once we have valtrees, we can just + // compare them directly here. + match (obl.try_to_scalar_int(), imp.try_to_scalar_int()) { + (Some(obl), Some(imp)) => obl == imp, + _ => true, + } + } + _ => true, + }, + + ty::ConstKind::Infer(_) => true, + + ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { + bug!("unexpected obl const: {:?}", obligation_ct) + } + } + } +} diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a973a5c9b50..2dabc696388 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1469,7 +1469,7 @@ impl ParamConst { } } -/// Use this rather than `TyKind`, whenever possible. +/// Use this rather than `RegionKind`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fb0537c543d..0a0c7659b08 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -52,11 +52,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } ExprKind::Repeat { value, count } => { - let value_operand = unpack!( - block = - this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No) - ); - block.and(Rvalue::Repeat(value_operand, count)) + if Some(0) == count.try_eval_usize(this.tcx, this.param_env) { + this.build_zero_repeat(block, value, scope, source_info) + } else { + let value_operand = unpack!( + block = this.as_operand( + block, + scope, + &this.thir[value], + None, + NeedsTemporary::No + ) + ); + block.and(Rvalue::Repeat(value_operand, count)) + } } ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( @@ -516,6 +525,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + fn build_zero_repeat( + &mut self, + mut block: BasicBlock, + value: ExprId, + scope: Option<region::Scope>, + outer_source_info: SourceInfo, + ) -> BlockAnd<Rvalue<'tcx>> { + let this = self; + let value = &this.thir[value]; + let elem_ty = value.ty; + if let Some(Category::Constant) = Category::of(&value.kind) { + // Repeating a const does nothing + } else { + // For a non-const, we may need to generate an appropriate `Drop` + let value_operand = + unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No)); + if let Operand::Move(to_drop) = value_operand { + let success = this.cfg.start_new_block(); + this.cfg.terminate( + block, + outer_source_info, + TerminatorKind::Drop { place: to_drop, target: success, unwind: None }, + ); + this.diverge_from(block); + block = success; + } + this.record_operands_moved(&[value_operand]); + } + block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new())) + } + fn limit_capture_mutability( &mut self, upvar_span: Span, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 569012e152b..ccbb518e72d 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -435,11 +435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } thir::InlineAsmOperand::SymFn { value, span } => { mir::InlineAsmOperand::SymFn { - value: Box::new(Constant { - span, - user_ty: None, - literal: value.into(), - }), + value: Box::new(Constant { span, user_ty: None, literal: value }), } } thir::InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index c15b3db1caa..3774a395035 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } else if let [success, fail] = *make_target_blocks(self) { assert_eq!(value.ty(), ty); - let expect = self.literal_operand(test.span, value.into()); + let expect = self.literal_operand(test.span, value); let val = Operand::Copy(place); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); } else { @@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks = make_target_blocks(self); // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. - let lo = self.literal_operand(test.span, lo.into()); - let hi = self.literal_operand(test.span, hi.into()); + let lo = self.literal_operand(test.span, lo); + let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place); let [success, fail] = *target_blocks else { @@ -370,7 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: Place<'tcx>, mut ty: Ty<'tcx>, ) { - let mut expect = self.literal_operand(source_info.span, value.into()); + let mut expect = self.literal_operand(source_info.span, value); let mut val = Operand::Copy(place); // If we're using `b"..."` as a pattern, we need to insert an diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 53f9706f021..a5f8a5847c2 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -1033,6 +1033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.block_data(start).terminator().kind, TerminatorKind::Assert { .. } | TerminatorKind::Call { .. } + | TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::InlineAsm { .. } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 880f86aff5d..f694e009ab9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -121,27 +121,27 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> { traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), - traits::NonStructuralMatchTy::Dynamic => { + with_no_trimmed_paths!(match non_sm_ty.kind { + traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTyKind::Dynamic => { "trait objects cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Opaque => { + traits::NonStructuralMatchTyKind::Opaque => { "opaque types cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Closure => { + traits::NonStructuralMatchTyKind::Closure => { "closures cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Generator => { + traits::NonStructuralMatchTyKind::Generator => { "generators cannot be used in patterns".to_string() } - traits::NonStructuralMatchTy::Param => { + traits::NonStructuralMatchTyKind::Param => { bug!("use of a constant whose type is a parameter inside a pattern") } - traits::NonStructuralMatchTy::Projection => { + traits::NonStructuralMatchTyKind::Projection => { bug!("use of a constant whose type is a projection inside a pattern") } - traits::NonStructuralMatchTy::Foreign => { + traits::NonStructuralMatchTyKind::Foreign => { bug!("use of a value of a foreign type inside a pattern") } }) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ee02151152c..a9ca8921797 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -201,7 +201,6 @@ use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_session::Limit; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use rustc_target::abi::Size; -use smallvec::SmallVec; use std::iter; use std::ops::Range; use std::path::PathBuf; @@ -226,6 +225,44 @@ pub struct InliningMap<'tcx> { inlines: GrowableBitSet<usize>, } +/// Struct to store mono items in each collecting and if they should +/// be inlined. We call `instantiation_mode` to get their inlining +/// status when inserting new elements, which avoids calling it in +/// `inlining_map.lock_mut()`. See the `collect_items_rec` implementation +/// below. +struct MonoItems<'tcx> { + // If this is false, we do not need to compute whether items + // will need to be inlined. + compute_inlining: bool, + + // The TyCtxt used to determine whether the a item should + // be inlined. + tcx: TyCtxt<'tcx>, + + // The collected mono items. The bool field in each element + // indicates whether this element should be inlined. + items: Vec<(Spanned<MonoItem<'tcx>>, bool /*inlined*/)>, +} + +impl<'tcx> MonoItems<'tcx> { + #[inline] + fn push(&mut self, item: Spanned<MonoItem<'tcx>>) { + self.extend([item]); + } + + #[inline] + fn extend<T: IntoIterator<Item = Spanned<MonoItem<'tcx>>>>(&mut self, iter: T) { + self.items.extend(iter.into_iter().map(|mono_item| { + let inlined = if !self.compute_inlining { + false + } else { + mono_item.node.instantiation_mode(self.tcx) == InstantiationMode::LocalCopy + }; + (mono_item, inlined) + })) + } +} + impl<'tcx> InliningMap<'tcx> { fn new() -> InliningMap<'tcx> { InliningMap { @@ -235,7 +272,13 @@ impl<'tcx> InliningMap<'tcx> { } } - fn record_accesses(&mut self, source: MonoItem<'tcx>, new_targets: &[(MonoItem<'tcx>, bool)]) { + fn record_accesses<'a>( + &mut self, + source: MonoItem<'tcx>, + new_targets: &'a [(Spanned<MonoItem<'tcx>>, bool)], + ) where + 'tcx: 'a, + { let start_index = self.targets.len(); let new_items_count = new_targets.len(); let new_items_count_total = new_items_count + self.targets.len(); @@ -243,9 +286,9 @@ impl<'tcx> InliningMap<'tcx> { self.targets.reserve(new_items_count); self.inlines.ensure(new_items_count_total); - for (i, (target, inline)) in new_targets.iter().enumerate() { - self.targets.push(*target); - if *inline { + for (i, (Spanned { node: mono_item, .. }, inlined)) in new_targets.into_iter().enumerate() { + self.targets.push(*mono_item); + if *inlined { self.inlines.insert(i + start_index); } } @@ -321,7 +364,7 @@ pub fn collect_crate_mono_items( // start monomorphizing from. fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> { debug!("collecting roots"); - let mut roots = Vec::new(); + let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() }; { let entry_fn = tcx.entry_fn(()); @@ -347,8 +390,11 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< // whose predicates hold. Luckily, items that aren't instantiable // can't actually be used, so we can just skip codegenning them. roots + .items .into_iter() - .filter_map(|root| root.node.is_instantiable(tcx).then_some(root.node)) + .filter_map(|(Spanned { node: mono_item, .. }, _)| { + mono_item.is_instantiable(tcx).then_some(mono_item) + }) .collect() } @@ -368,7 +414,7 @@ fn collect_items_rec<'tcx>( } debug!("BEGIN collect_items_rec({})", starting_point.node); - let mut neighbors = Vec::new(); + let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() }; let recursion_depth_reset; // @@ -483,10 +529,9 @@ fn collect_items_rec<'tcx>( &format!("the above error was encountered while instantiating `{}`", formatted_item), ); } + inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items); - record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); - - for neighbour in neighbors { + for (neighbour, _) in neighbors.items { collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); } @@ -497,25 +542,6 @@ fn collect_items_rec<'tcx>( debug!("END collect_items_rec({})", starting_point.node); } -fn record_accesses<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - caller: MonoItem<'tcx>, - callees: impl Iterator<Item = &'a MonoItem<'tcx>>, - inlining_map: MTRef<'_, MTLock<InliningMap<'tcx>>>, -) { - let is_inlining_candidate = |mono_item: &MonoItem<'tcx>| { - mono_item.instantiation_mode(tcx) == InstantiationMode::LocalCopy - }; - - // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. - // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` - // instead to avoid creating this `SmallVec`. - let accesses: SmallVec<[_; 128]> = - callees.map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); - - inlining_map.lock_mut().record_accesses(caller, &accesses); -} - /// Format instance name that is already known to be too long for rustc. /// Show only the first and last 32 characters to avoid blasting /// the user's terminal with thousands of lines of type-name. @@ -627,7 +653,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { struct MirNeighborCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, - output: &'a mut Vec<Spanned<MonoItem<'tcx>>>, + output: &'a mut MonoItems<'tcx>, instance: Instance<'tcx>, } @@ -905,7 +931,7 @@ fn visit_drop_use<'tcx>( ty: Ty<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { let instance = Instance::resolve_drop_in_place(tcx, ty); visit_instance_use(tcx, instance, is_direct_call, source, output); @@ -916,7 +942,7 @@ fn visit_fn_use<'tcx>( ty: Ty<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { if let ty::FnDef(def_id, substs) = *ty.kind() { let instance = if is_direct_call { @@ -934,7 +960,7 @@ fn visit_instance_use<'tcx>( instance: ty::Instance<'tcx>, is_direct_call: bool, source: Span, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); if !should_codegen_locally(tcx, &instance) { @@ -1117,7 +1143,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( trait_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, source: Span, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars()); @@ -1159,7 +1185,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( struct RootCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, mode: MonoItemCollectionMode, - output: &'a mut Vec<Spanned<MonoItem<'tcx>>>, + output: &'a mut MonoItems<'tcx>, entry_fn: Option<(DefId, EntryFnType)>, } @@ -1305,7 +1331,7 @@ fn item_requires_monomorphization(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn create_mono_items_for_default_impls<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { match item.kind { hir::ItemKind::Impl(ref impl_) => { @@ -1361,11 +1387,7 @@ fn create_mono_items_for_default_impls<'tcx>( } /// Scans the miri alloc in order to find function calls, closures, and drop-glue. -fn collect_miri<'tcx>( - tcx: TyCtxt<'tcx>, - alloc_id: AllocId, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, -) { +fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) { match tcx.global_alloc(alloc_id) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); @@ -1396,7 +1418,7 @@ fn collect_miri<'tcx>( fn collect_neighbours<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); @@ -1407,7 +1429,7 @@ fn collect_neighbours<'tcx>( fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, - output: &mut Vec<Spanned<MonoItem<'tcx>>>, + output: &mut MonoItems<'tcx>, ) { match value { ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => collect_miri(tcx, ptr.provenance, output), diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 37e34656941..bb6d892138a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2291,16 +2291,9 @@ impl<'a> Parser<'a> { .span_label(else_span, "expected an `if` or a block after this `else`") .span_suggestion( cond.span.shrink_to_lo(), - "add an `if` if this is the condition to an chained `if` statement after the `else`", + "add an `if` if this is the condition of a chained `else if` statement", "if ".to_string(), Applicability::MaybeIncorrect, - ).multipart_suggestion( - "... otherwise, place this expression inside of a block if it is not an `if` condition", - vec![ - (cond.span.shrink_to_lo(), "{ ".to_string()), - (cond.span.shrink_to_hi(), " }".to_string()), - ], - Applicability::MaybeIncorrect, ) .emit(); self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)? diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 510280ee386..a2d8e5168c4 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -30,7 +30,6 @@ mod diagnostic_items; pub mod entry; pub mod hir_id_validator; pub mod hir_stats; -mod intrinsicck; mod lang_items; pub mod layout_test; mod lib_features; @@ -54,7 +53,6 @@ pub fn provide(providers: &mut Providers) { loops::provide(providers); naked_functions::provide(providers); liveness::provide(providers); - intrinsicck::provide(providers); reachable::provide(providers); stability::provide(providers); upvars::provide(providers); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 8737e45487e..f44eac63cef 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1270,7 +1270,9 @@ impl<S: Encoder> Encodable<S> for SourceFile { // the lines list is sorted and individual lines are // probably not that long. Because of that we can store lines // as a difference list, using as little space as possible - // for the differences. + // for the differences. But note that the first line is + // always encoded as a `BytePos` because its position is + // often much larger than any of the differences. let max_line_length = if lines.len() == 1 { 0 } else { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 020ae3ad0c7..d60b4d3d021 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -345,20 +345,27 @@ impl SourceMap { let end_pos = Pos::from_usize(start_pos + source_len); let start_pos = Pos::from_usize(start_pos); + // Translate these positions into the new global frame of reference, + // now that the offset of the SourceFile is known. + // + // These are all unsigned values. `original_start_pos` may be larger or + // smaller than `start_pos`, but `pos` is always larger than both. + // Therefore, `(pos - original_start_pos) + start_pos` won't overflow + // but `start_pos - original_start_pos` might. So we use the former + // form rather than pre-computing the offset into a local variable. The + // compiler backend can optimize away the repeated computations in a + // way that won't trigger overflow checks. for pos in &mut file_local_lines { - *pos = *pos + start_pos; + *pos = (*pos - original_start_pos) + start_pos; } - for mbc in &mut file_local_multibyte_chars { - mbc.pos = mbc.pos + start_pos; + mbc.pos = (mbc.pos - original_start_pos) + start_pos; } - for swc in &mut file_local_non_narrow_chars { - *swc = *swc + start_pos; + *swc = (*swc - original_start_pos) + start_pos; } - for nc in &mut file_local_normalized_pos { - nc.pos = nc.pos + start_pos; + nc.pos = (nc.pos - original_start_pos) + start_pos; } let source_file = Lrc::new(SourceFile { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5c9c16350e4..406e9a4113e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -427,6 +427,7 @@ symbols! { cfg_panic, cfg_sanitize, cfg_target_abi, + cfg_target_compact, cfg_target_feature, cfg_target_has_atomic, cfg_target_has_atomic_equal_alignment, @@ -1375,6 +1376,7 @@ symbols! { sym, sync, t32, + target, target_abi, target_arch, target_endian, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 832eeec3e8b..6dd245b047c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -108,6 +108,15 @@ pub enum LldFlavor { } impl LldFlavor { + pub fn as_str(&self) -> &'static str { + match self { + LldFlavor::Wasm => "wasm", + LldFlavor::Ld64 => "darwin", + LldFlavor::Ld => "gnu", + LldFlavor::Link => "link", + } + } + fn from_str(s: &str) -> Option<Self> { Some(match s { "darwin" => LldFlavor::Ld64, @@ -121,13 +130,7 @@ impl LldFlavor { impl ToJson for LldFlavor { fn to_json(&self) -> Json { - match *self { - LldFlavor::Ld64 => "darwin", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Wasm => "wasm", - } - .to_json() + self.as_str().to_json() } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index a7893c0193f..e7f0e47f12c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -20,7 +20,7 @@ use rustc_hir::CRATE_HIR_ID; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::specialization_graph::OverlapMode; -use rustc_middle::ty::fast_reject::{self, TreatParams}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt}; @@ -79,26 +79,21 @@ where // Before doing expensive operations like entering an inference context, do // a quick check via fast_reject to tell if the impl headers could possibly // unify. + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer }; let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); - - // Check if any of the input types definitely do not unify. - if iter::zip( - impl1_ref.iter().flat_map(|tref| tref.substs.types()), - impl2_ref.iter().flat_map(|tref| tref.substs.types()), - ) - .any(|(ty1, ty2)| { - let t1 = fast_reject::simplify_type(tcx, ty1, TreatParams::AsInfer); - let t2 = fast_reject::simplify_type(tcx, ty2, TreatParams::AsInfer); - - if let (Some(t1), Some(t2)) = (t1, t2) { - // Simplified successfully - t1 != t2 - } else { - // Types might unify - false + let may_overlap = match (impl1_ref, impl2_ref) { + (Some(a), Some(b)) => iter::zip(a.substs, b.substs) + .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)), + (None, None) => { + let self_ty1 = tcx.type_of(impl1_def_id); + let self_ty2 = tcx.type_of(impl2_def_id); + drcx.types_may_unify(self_ty1, self_ty2) } - }) { + _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"), + }; + + if !may_overlap { // Some types involved are definitely different, so the impls couldn't possibly overlap. debug!("overlapping_impls: fast_reject early-exit"); return no_overlap(); @@ -519,7 +514,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// 3. Before this local type, no generic type parameter of the impl must /// be reachable through fundamental types. /// - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental. -/// - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is +/// - while `impl<T> Trait<LocalType> for Box<T>` results in an error, as `T` is /// reachable through the fundamental type `Box`. /// 4. Every type in the local key parameter not known in C, going /// through the parameter's type tree, must appear only as a subtree of diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 266fcc777ef..0cefa802c85 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -273,6 +273,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { error: &SelectionError<'tcx>, fallback_has_occurred: bool, ) { + self.set_tainted_by_errors(); let tcx = self.tcx; let mut span = obligation.cause.span; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 81819534e8b..dcfdff68640 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -62,7 +62,7 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::NonStructuralMatchTy; +pub use self::structural_match::{NonStructuralMatchTy, NonStructuralMatchTyKind}; pub use self::util::{ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, elaborate_trait_ref, elaborate_trait_refs, diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 7d418198195..ed7d16f7a54 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -89,8 +89,8 @@ impl<'tcx> OnUnimplementedDirective { None, ) })?; - attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| { - if let Some(symbol) = item.value_str() && let Err(guar) = parse_value(symbol) { + attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { + if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { errored = Some(guar); } true @@ -226,14 +226,12 @@ impl<'tcx> OnUnimplementedDirective { condition, &tcx.sess.parse_sess, Some(tcx.features()), - &mut |c| { - c.ident().map_or(false, |ident| { - let value = c.value_str().map(|s| { - OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map) - }); + &mut |cfg| { + let value = cfg.value.map(|v| { + OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map) + }); - options.contains(&(ident.name, value)) - }) + options.contains(&(cfg.name, value)) }, ) { debug!("evaluate: skipping {:?} due to condition", command); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 07720ba71ca..c8b4303e1e0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -539,8 +539,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { + // Before we create the substitutions and everything, first + // consider a "quick reject". This avoids creating more types + // and so forth that we need to. + let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); + if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { + return; + } + self.infcx.probe(|_| { - if let Ok(_substs) = self.match_impl(impl_def_id, obligation) { + if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { candidates.vec.push(ImplCandidate(impl_def_id)); } }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b0b17d0f9e6..c7ebc194ea5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -33,11 +33,11 @@ use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::abstract_const::NotConstEvaluatable; -use rustc_middle::ty::fast_reject::{self, TreatParams}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; +use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::sym; @@ -2043,7 +2043,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Normalized<'tcx, SubstsRef<'tcx>> { - match self.match_impl(impl_def_id, obligation) { + let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); + match self.match_impl(impl_def_id, impl_trait_ref, obligation) { Ok(substs) => substs, Err(()) => { self.infcx.tcx.sess.delay_span_bug( @@ -2070,17 +2071,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_impl( &mut self, impl_def_id: DefId, + impl_trait_ref: EarlyBinder<ty::TraitRef<'tcx>>, obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { - let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap(); - - // Before we create the substitutions and everything, first - // consider a "quick reject". This avoids creating more types - // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { - return Err(()); - } - let placeholder_obligation = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; @@ -2137,40 +2130,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can avoid creating type variables and doing the full // substitution if we find that any of the input types, when // simplified, do not match. - - iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs).any( - |(obligation_arg, impl_arg)| { - match (obligation_arg.unpack(), impl_arg.unpack()) { - (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => { - // Note, we simplify parameters for the obligation but not the - // impl so that we do not reject a blanket impl but do reject - // more concrete impls if we're searching for `T: Trait`. - let simplified_obligation_ty = fast_reject::simplify_type( - self.tcx(), - obligation_ty, - TreatParams::AsPlaceholder, - ); - let simplified_impl_ty = - fast_reject::simplify_type(self.tcx(), impl_ty, TreatParams::AsInfer); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty - } - (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => { - // Lifetimes can never cause a rejection. - false - } - (GenericArgKind::Const(_), GenericArgKind::Const(_)) => { - // Conservatively ignore consts (i.e. assume they might - // unify later) until we have `fast_reject` support for - // them (if we'll ever need it, even). - false - } - _ => unreachable!(), - } - }, - ) + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; + iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs) + .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp)) } /// Normalize `where_clause_trait_ref` and try to match it against diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 67e3bf80486..5465395768c 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -11,7 +11,13 @@ use rustc_span::Span; use std::ops::ControlFlow; #[derive(Debug)] -pub enum NonStructuralMatchTy<'tcx> { +pub struct NonStructuralMatchTy<'tcx> { + pub ty: Ty<'tcx>, + pub kind: NonStructuralMatchTyKind<'tcx>, +} + +#[derive(Debug)] +pub enum NonStructuralMatchTyKind<'tcx> { Adt(AdtDef<'tcx>), Param, Dynamic, @@ -137,25 +143,32 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { - return ControlFlow::Break(NonStructuralMatchTy::Param); + let kind = NonStructuralMatchTyKind::Param; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Dynamic(..) => { - return ControlFlow::Break(NonStructuralMatchTy::Dynamic); + let kind = NonStructuralMatchTyKind::Dynamic; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Foreign(_) => { - return ControlFlow::Break(NonStructuralMatchTy::Foreign); + let kind = NonStructuralMatchTyKind::Foreign; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Opaque(..) => { - return ControlFlow::Break(NonStructuralMatchTy::Opaque); + let kind = NonStructuralMatchTyKind::Opaque; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Projection(..) => { - return ControlFlow::Break(NonStructuralMatchTy::Projection); + let kind = NonStructuralMatchTyKind::Projection; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Closure(..) => { - return ControlFlow::Break(NonStructuralMatchTy::Closure); + let kind = NonStructuralMatchTyKind::Closure; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::Generator(..) | ty::GeneratorWitness(..) => { - return ControlFlow::Break(NonStructuralMatchTy::Generator); + let kind = NonStructuralMatchTyKind::Generator; + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -215,7 +228,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); - return ControlFlow::Break(NonStructuralMatchTy::Adt(adt_def)); + let kind = NonStructuralMatchTyKind::Adt(adt_def); + return ControlFlow::Break(NonStructuralMatchTy { ty, kind }); } // structural-match does not care about the diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 3e76738cc5d..a6d7fecb2e8 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1,3 +1,5 @@ +use crate::check::wfcheck::for_item; + use super::coercion::CoerceMany; use super::compare_method::check_type_bounds; use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; @@ -871,6 +873,14 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } } } + DefKind::GlobalAsm => { + let it = tcx.hir().item(id); + let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; + for_item(tcx, it).with_fcx(|fcx| { + fcx.check_asm(asm, it.hir_id()); + Default::default() + }) + } _ => {} } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 09b0dc0a0ea..ea81f1ef90c 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -51,6 +51,7 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; +use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -294,7 +295,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_lang_item_path(lang_item, expr, hir_id) } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), - ExprKind::InlineAsm(asm) => self.check_expr_asm(asm), + ExprKind::InlineAsm(asm) => { + // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). + self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); + self.check_expr_asm(asm) + } ExprKind::Break(destination, ref expr_opt) => { self.check_expr_break(destination, expr_opt.as_deref(), expr) } @@ -530,8 +535,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; - if let ty::FnDef(..) = ty.kind() { + if let ty::FnDef(did, ..) = *ty.kind() { let fn_sig = ty.fn_sig(tcx); + if tcx.fn_sig(did).abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { + let from = fn_sig.inputs().skip_binder()[0]; + let to = fn_sig.output().skip_binder(); + // We defer the transmute to the end of typeck, once all inference vars have + // been resolved or we errored. This is important as we can only check transmute + // on concrete types, but the output type may not be known yet (it would only + // be known if explicitly specified via turbofish). + self.deferred_transmute_checks.borrow_mut().push((from, to, expr.span)); + } if !tcx.features().unsized_fn_params { // We want to remove some Sized bounds from std functions, // but don't want to expose the removal to stable Rust. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a02d8c89772..34cc02f180b 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -47,6 +47,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(in super::super) fn check_transmutes(&self) { + let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut(); + debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len()); + for (from, to, span) in deferred_transmute_checks.drain(..) { + self.check_transmute(span, from, to); + } + } + + pub(in super::super) fn check_asms(&self) { + let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut(); + debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); + for (asm, hir_id) in deferred_asm_checks.drain(..) { + let enclosing_id = self.tcx.hir().enclosing_body_owner(hir_id); + self.check_asm(asm, enclosing_id); + } + } + pub(in super::super) fn check_method_argument_types( &self, sp: Span, @@ -845,7 +862,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] { format!(",found `{}`", ty) } else { - "".into() + String::new() }; labels.push(( first_span, @@ -857,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((ty, _)) = final_arg_types[other_input_idx] { format!(",found `{}`", ty) } else { - "".into() + String::new() }; labels.push(( second_span, @@ -875,7 +892,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let provided_ty = if let Some((ty, _)) = final_arg_types[dst_arg] { format!(",found `{}`", ty) } else { - "".into() + String::new() }; labels.push(( provided_args[dst_arg].span, @@ -1744,8 +1761,7 @@ fn label_fn_like<'tcx>( .get_if_local(def_id) .and_then(|node| node.body_id()) .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); + .flat_map(|id| tcx.hir().body(id).params); for param in params { spans.push_span_label(param.span, String::new()); diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 5cd63cae8ad..08a64d8e673 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -50,6 +50,10 @@ pub struct Inherited<'a, 'tcx> { pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>, + pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, Span)>>, + + pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>, + pub(super) deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, @@ -113,6 +117,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { deferred_sized_obligations: RefCell::new(Vec::new()), deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), + deferred_transmute_checks: RefCell::new(Vec::new()), + deferred_asm_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), body_id, diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index 9c840777baf..027868be8bb 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -1,37 +1,16 @@ -use hir::intravisit::walk_inline_asm; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::Idx; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy}; +use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy}; use rustc_session::lint; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::{Pointer, VariantIdx}; -use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType}; +use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType}; -fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }); -} - -pub fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_intrinsics, ..*providers }; -} - -struct ItemVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -struct ExprVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - typeck_results: &'tcx ty::TypeckResults<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} +use super::FnCtxt; /// If the type is `Option<T>`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. @@ -60,14 +39,15 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { ty } -impl<'tcx> ExprVisitor<'tcx> { - fn def_id_is_transmute(&self, def_id: DefId) -> bool { - self.tcx.is_intrinsic(def_id) && self.tcx.item_name(def_id) == sym::transmute - } - - fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { - let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env); - let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env); +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { + let convert = |ty: Ty<'tcx>| { + let ty = self.resolve_vars_if_possible(ty); + let ty = self.tcx.normalize_erasing_regions(self.param_env, ty); + (SizeSkeleton::compute(ty, self.tcx, self.param_env), ty) + }; + let (sk_from, from) = convert(from); + let (sk_to, to) = convert(to); // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { @@ -139,7 +119,8 @@ impl<'tcx> ExprVisitor<'tcx> { target_features: &FxHashSet<Symbol>, ) -> Option<InlineAsmType> { // Check the type against the allowed types for inline asm. - let ty = self.typeck_results.expr_ty_adjusted(expr); + let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); + let ty = self.resolve_vars_if_possible(ty); let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, @@ -152,10 +133,24 @@ impl<'tcx> ExprVisitor<'tcx> { ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), + // Somewhat of a hack: fallback in the presence of errors does not actually + // fall back to i32, but to ty::Error. For integer inference variables this + // means that they don't get any fallback and stay as `{integer}`. + // Since compilation can't succeed anyway, it's fine to use this to avoid printing + // "cannot use value of type `{integer}`", even though that would absolutely + // work due due i32 fallback if the current function had no other errors. + ty::Infer(InferTy::IntVar(_)) => { + assert!(self.is_tainted_by_errors()); + Some(InlineAsmType::I32) + } ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32), ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), + ty::Infer(InferTy::FloatVar(_)) => { + assert!(self.is_tainted_by_errors()); + Some(InlineAsmType::F32) + } ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), ty::FnPtr(_) => Some(asm_ty_isize), @@ -208,6 +203,11 @@ impl<'tcx> ExprVisitor<'tcx> { return None; }; + if ty.has_infer_types_or_consts() { + assert!(self.is_tainted_by_errors()); + return None; + } + // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. if !ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), self.param_env) { @@ -230,10 +230,10 @@ impl<'tcx> ExprVisitor<'tcx> { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg); - err.span_label( - in_expr.span, - &format!("type `{}`", self.typeck_results.expr_ty_adjusted(in_expr)), - ); + + let in_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(in_expr); + let in_expr_ty = self.resolve_vars_if_possible(in_expr_ty); + err.span_label(in_expr.span, &format!("type `{in_expr_ty}`")); err.span_label(expr.span, &format!("type `{ty}`")); err.note( "asm inout arguments must have the same type, \ @@ -337,12 +337,14 @@ impl<'tcx> ExprVisitor<'tcx> { Some(asm_ty) } - fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) { + pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: hir::HirId) { let hir = self.tcx.hir(); - let enclosing_id = hir.enclosing_body_owner(hir_id); let enclosing_def_id = hir.local_def_id(enclosing_id).to_def_id(); let target_features = self.tcx.asm_target_features(enclosing_def_id); - let asm_arch = self.tcx.sess.asm_arch.unwrap(); + let Some(asm_arch) = self.tcx.sess.asm_arch else { + self.tcx.sess.delay_span_bug(DUMMY_SP, "target architecture does not support asm"); + return; + }; for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { // Validate register classes against currently enabled target // features. We check that at least one type is available for @@ -358,6 +360,11 @@ impl<'tcx> ExprVisitor<'tcx> { // Some explicit registers cannot be used depending on the // target. Reject those here. if let InlineAsmRegOrRegClass::Reg(reg) = reg { + if let InlineAsmReg::Err = reg { + // `validate` will panic on `Err`, as an error must + // already have been reported. + continue; + } if let Err(msg) = reg.validate( asm_arch, self.tcx.sess.relocation_model(), @@ -374,6 +381,9 @@ impl<'tcx> ExprVisitor<'tcx> { if !op.is_clobber() { let mut missing_required_features = vec![]; let reg_class = reg.reg_class(); + if let InlineAsmRegClass::Err = reg_class { + continue; + } for &(_, feature) in reg_class.supported_types(asm_arch) { match feature { Some(feature) => { @@ -482,33 +492,6 @@ impl<'tcx> ExprVisitor<'tcx> { ); } } - // These are checked in ItemVisitor. - hir::InlineAsmOperand::Const { .. } - | hir::InlineAsmOperand::SymFn { .. } - | hir::InlineAsmOperand::SymStatic { .. } => {} - } - } - } -} - -impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> { - fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let owner_def_id = self.tcx.hir().body_owner_def_id(body_id); - let body = self.tcx.hir().body(body_id); - let param_env = self.tcx.param_env(owner_def_id.to_def_id()); - let typeck_results = self.tcx.typeck(owner_def_id); - ExprVisitor { tcx: self.tcx, param_env, typeck_results }.visit_body(body); - self.visit_body(body); - } - - fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) { - for (op, op_sp) in asm.operands.iter() { - match *op { - // These are checked in ExprVisitor. - hir::InlineAsmOperand::In { .. } - | hir::InlineAsmOperand::Out { .. } - | hir::InlineAsmOperand::InOut { .. } - | hir::InlineAsmOperand::SplitInOut { .. } => {} // No special checking is needed for these: // - Typeck has checked that Const operands are integers. // - AST lowering guarantees that SymStatic points to a static. @@ -534,31 +517,5 @@ impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> { } } } - walk_inline_asm(self, asm, id); - } -} - -impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - match expr.kind { - hir::ExprKind::Path(ref qpath) => { - let res = self.typeck_results.qpath_res(qpath, expr.hir_id); - if let Res::Def(DefKind::Fn, did) = res - && self.def_id_is_transmute(did) - { - let typ = self.typeck_results.node_type(expr.hir_id); - let sig = typ.fn_sig(self.tcx); - let from = sig.inputs().skip_binder()[0]; - let to = sig.output().skip_binder(); - self.check_transmute(expr.span, from, to); - } - } - - hir::ExprKind::InlineAsm(asm) => self.check_asm(asm, expr.hir_id), - - _ => {} - } - - intravisit::walk_expr(self, expr); } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index f9c0ea82e02..4e54d554c6e 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Obligation { cause: cause.clone(), param_env: self.param_env, - predicate: predicate.clone(), + predicate: *predicate, recursion_depth: 0, }, )); @@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = self_ty.span.ctxt().outer_expn_data().call_site; let mut spans: MultiSpan = span.into(); spans.push_span_label(span, derive_msg.to_string()); - let entry = spanned_predicates.entry(spans.into()); + let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } @@ -704,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident.span.into() }; spans.push_span_label(ident.span, "in this trait".to_string()); - let entry = spanned_predicates.entry(spans.into()); + let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } @@ -748,7 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } spans.push_span_label(self_ty.span, String::new()); - let entry = spanned_predicates.entry(spans.into()); + let entry = spanned_predicates.entry(spans); entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p); } _ => {} @@ -1460,7 +1460,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { derives.push(( self_name.clone(), - self_span.clone(), + self_span, parent_diagnostic_name.to_string(), )); } diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 280fae5fe6d..7e686d0f5e9 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -81,6 +81,7 @@ mod gather_locals; mod generator_interior; mod inherited; pub mod intrinsic; +mod intrinsicck; pub mod method; mod op; mod pat; @@ -487,6 +488,12 @@ fn typeck_with_fallback<'tcx>( fcx.select_all_obligations_or_error(); + if !fcx.infcx.is_tainted_by_errors() { + fcx.check_transmutes(); + } + + fcx.check_asms(); + if fn_sig.is_some() { fcx.regionck_fn(id, body, span, wf_tys); } else { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index c99d9d8f923..637f6459525 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -705,7 +705,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let predicates = errors .iter() .filter_map(|error| { - error.obligation.predicate.clone().to_opt_poly_trait_pred() + error.obligation.predicate.to_opt_poly_trait_pred() }); for pred in predicates { self.infcx.suggest_restricting_param_bound( diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 50966868ec7..a6c7573b787 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -41,7 +41,7 @@ use std::ops::ControlFlow; /// ```ignore (illustrative) /// F: for<'b, 'tcx> where 'tcx FnOnce(FnCtxt<'b, 'tcx>) /// ``` -struct CheckWfFcxBuilder<'tcx> { +pub(super) struct CheckWfFcxBuilder<'tcx> { inherited: super::InheritedBuilder<'tcx>, id: hir::HirId, span: Span, @@ -49,7 +49,7 @@ struct CheckWfFcxBuilder<'tcx> { } impl<'tcx> CheckWfFcxBuilder<'tcx> { - fn with_fcx<F>(&mut self, f: F) + pub(super) fn with_fcx<F>(&mut self, f: F) where F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> FxHashSet<Ty<'tcx>>, { @@ -827,7 +827,9 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ); } - if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() { + if let Some(non_structural_match_ty) = + traits::search_for_structural_match_violation(param.span, tcx, ty) + { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. @@ -853,19 +855,23 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { ) .emit(); } else { - struct_span_err!( + let mut diag = struct_span_err!( tcx.sess, hir_ty.span, E0741, "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \ the type of a const parameter", - ty, - ) - .span_label( - hir_ty.span, - format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), - ) - .emit(); + non_structural_match_ty.ty, + ); + + if ty == non_structural_match_ty.ty { + diag.span_label( + hir_ty.span, + format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"), + ); + } + + diag.emit(); } } } else { @@ -966,7 +972,7 @@ fn check_associated_item( }) } -fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { +pub(super) fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> { for_id(tcx, item.def_id, item.span) } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 16096ea3d74..4fe5b26dc05 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -263,8 +263,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.fix_scalar_builtin_expr(e); self.fix_index_builtin_expr(e); - self.visit_node_id(e.span, e.hir_id); - match e.kind { hir::ExprKind::Closure(_, _, body, _, _) => { let body = self.fcx.tcx.hir().body(body); @@ -291,6 +289,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { _ => {} } + self.visit_node_id(e.span, e.hir_id); intravisit::walk_expr(self, e); } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 4ffd199b133..454c71d4971 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -63,6 +63,7 @@ This API is completely unstable and subject to change. #![feature(hash_drain_filter)] #![feature(if_let_guard)] #![feature(is_sorted)] +#![feature(iter_intersperse)] #![feature(label_break_value)] #![feature(let_chains)] #![feature(let_else)] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 0eaa2639863..39dfd98ddcc 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -383,15 +383,23 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_lowercase(&self) -> String { - let mut s = String::with_capacity(self.len()); - for (i, c) in self[..].char_indices() { + let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase); + + // Safety: we know this is a valid char boundary since + // out.len() is only progressed if ascii bytes are found + let rest = unsafe { self.get_unchecked(out.len()..) }; + + // Safety: We have written only valid ASCII to our vec + let mut s = unsafe { String::from_utf8_unchecked(out) }; + + for (i, c) in rest[..].char_indices() { if c == 'Σ' { // Σ maps to σ, except at the end of a word where it maps to ς. // This is the only conditional (contextual) but language-independent mapping // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - map_uppercase_sigma(self, i, &mut s) + map_uppercase_sigma(rest, i, &mut s) } else { match conversions::to_lower(c) { [a, '\0', _] => s.push(a), @@ -466,8 +474,16 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { - let mut s = String::with_capacity(self.len()); - for c in self[..].chars() { + let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase); + + // Safety: we know this is a valid char boundary since + // out.len() is only progressed if ascii bytes are found + let rest = unsafe { self.get_unchecked(out.len()..) }; + + // Safety: We have written only valid ASCII to our vec + let mut s = unsafe { String::from_utf8_unchecked(out) }; + + for c in rest.chars() { match conversions::to_upper(c) { [a, '\0', _] => s.push(a), [a, b, '\0'] => { @@ -619,3 +635,51 @@ impl str { pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } + +/// Converts the bytes while the bytes are still ascii. +/// For better average performance, this is happens in chunks of `2*size_of::<usize>()`. +/// Returns a vec with the converted bytes. +#[inline] +#[cfg(not(test))] +#[cfg(not(no_global_oom_handling))] +fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec<u8> { + let mut out = Vec::with_capacity(b.len()); + + const USIZE_SIZE: usize = mem::size_of::<usize>(); + const MAGIC_UNROLL: usize = 2; + const N: usize = USIZE_SIZE * MAGIC_UNROLL; + const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]); + + let mut i = 0; + unsafe { + while i + N <= b.len() { + // Safety: we have checks the sizes `b` and `out` to know that our + let in_chunk = b.get_unchecked(i..i + N); + let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N); + + let mut bits = 0; + for j in 0..MAGIC_UNROLL { + // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment) + // safety: in_chunk is valid bytes in the range + bits |= in_chunk.as_ptr().cast::<usize>().add(j).read_unaligned(); + } + // if our chunks aren't ascii, then return only the prior bytes as init + if bits & NONASCII_MASK != 0 { + break; + } + + // perform the case conversions on N bytes (gets heavily autovec'd) + for j in 0..N { + // safety: in_chunk and out_chunk is valid bytes in the range + let out = out_chunk.get_unchecked_mut(j); + out.write(convert(in_chunk.get_unchecked(j))); + } + + // mark these bytes as initialised + i += N; + } + out.set_len(i); + } + + out +} diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c157aba83c2..d222fcb445f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1771,7 +1771,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// # Panics /// - /// Panics if the number of elements in the vector overflows a `usize`. + /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 273b39aa45a..7379569dd68 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1772,6 +1772,20 @@ fn to_lowercase() { assert_eq!("ΑΣΑ".to_lowercase(), "ασα"); assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); + + // a really long string that has it's lowercase form + // even longer. this tests that implementations don't assume + // an incorrect upper bound on allocations + let upper = str::repeat("İ", 512); + let lower = str::repeat("i̇", 512); + assert_eq!(upper.to_lowercase(), lower); + + // a really long ascii-only string. + // This test that the ascii hot-path + // functions correctly + let upper = str::repeat("A", 511); + let lower = str::repeat("a", 511); + assert_eq!(upper.to_lowercase(), lower); } #[test] diff --git a/library/core/src/asserting.rs b/library/core/src/asserting.rs new file mode 100644 index 00000000000..212b637d343 --- /dev/null +++ b/library/core/src/asserting.rs @@ -0,0 +1,109 @@ +// Contains the machinery necessary to print useful `assert!` messages. Not intended for public +// usage, not even nightly use-cases. +// +// Based on https://github.com/dtolnay/case-studies/tree/master/autoref-specialization. When +// 'specialization' is robust enough (5 years? 10 years? Never?), `Capture` can be specialized +// to [Printable]. + +#![allow(missing_debug_implementations)] +#![doc(hidden)] +#![unstable(feature = "generic_assert_internals", issue = "44838")] + +use crate::{ + fmt::{Debug, Formatter}, + marker::PhantomData, +}; + +// ***** TryCapture - Generic ***** + +/// Marker used by [Capture] +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub struct TryCaptureWithoutDebug; + +/// Catches an arbitrary `E` and modifies `to` accordingly +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub trait TryCaptureGeneric<E, M> { + /// Similar to [TryCapturePrintable] but generic to any `E`. + fn try_capture(&self, to: &mut Capture<E, M>); +} + +impl<E> TryCaptureGeneric<E, TryCaptureWithoutDebug> for &Wrapper<&E> { + #[inline] + fn try_capture(&self, _: &mut Capture<E, TryCaptureWithoutDebug>) {} +} + +impl<E> Debug for Capture<E, TryCaptureWithoutDebug> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> { + f.write_str("N/A") + } +} + +// ***** TryCapture - Printable ***** + +/// Marker used by [Capture] +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub struct TryCaptureWithDebug; + +/// Catches an arbitrary `E: Printable` and modifies `to` accordingly +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub trait TryCapturePrintable<E, M> { + /// Similar as [TryCaptureGeneric] but specialized to any `E: Printable`. + fn try_capture(&self, to: &mut Capture<E, M>); +} + +impl<E> TryCapturePrintable<E, TryCaptureWithDebug> for Wrapper<&E> +where + E: Printable, +{ + #[inline] + fn try_capture(&self, to: &mut Capture<E, TryCaptureWithDebug>) { + to.elem = Some(*self.0); + } +} + +impl<E> Debug for Capture<E, TryCaptureWithDebug> +where + E: Printable, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> { + match self.elem { + None => f.write_str("N/A"), + Some(ref value) => Debug::fmt(value, f), + } + } +} + +// ***** Others ***** + +/// All possible captured `assert!` elements +/// +/// # Types +/// +/// * `E`: **E**lement that is going to be displayed. +/// * `M`: **M**arker used to differentiate [Capture]s in regards to [Debug]. +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub struct Capture<E, M> { + // If None, then `E` does not implements [Printable] or `E` wasn't evaluated (`assert!( ... )` + // short-circuited). + // + // If Some, then `E` implements [Printable] and was evaluated. + pub elem: Option<E>, + phantom: PhantomData<M>, +} + +impl<M, T> Capture<M, T> { + #[inline] + pub const fn new() -> Self { + Self { elem: None, phantom: PhantomData } + } +} + +/// Necessary for the implementations of `TryCapture*` +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub struct Wrapper<T>(pub T); + +/// Tells which elements can be copied and displayed +#[unstable(feature = "generic_assert_internals", issue = "44838")] +pub trait Printable: Copy + Debug {} + +impl<T> Printable for T where T: Copy + Debug {} diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 22b76ea66ff..15362d2330a 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -362,6 +362,12 @@ pub use self::traits::Iterator; )] pub use self::range::Step; +#[unstable( + feature = "iter_from_generator", + issue = "43122", + reason = "generators are unstable" +)] +pub use self::sources::from_generator; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{empty, Empty}; #[stable(feature = "iter_from_fn", since = "1.34.0")] diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 37b6f2e2565..d34772cd304 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -1,5 +1,6 @@ mod empty; mod from_fn; +mod from_generator; mod once; mod once_with; mod repeat; @@ -21,6 +22,13 @@ pub use self::repeat_with::{repeat_with, RepeatWith}; #[stable(feature = "iter_from_fn", since = "1.34.0")] pub use self::from_fn::{from_fn, FromFn}; +#[unstable( + feature = "iter_from_generator", + issue = "43122", + reason = "generators are unstable" +)] +pub use self::from_generator::from_generator; + #[stable(feature = "iter_successors", since = "1.34.0")] pub use self::successors::{successors, Successors}; diff --git a/library/core/src/iter/sources/from_generator.rs b/library/core/src/iter/sources/from_generator.rs new file mode 100644 index 00000000000..8e7cbd34a4f --- /dev/null +++ b/library/core/src/iter/sources/from_generator.rs @@ -0,0 +1,43 @@ +use crate::ops::{Generator, GeneratorState}; +use crate::pin::Pin; + +/// Creates a new iterator where each iteration calls the provided generator. +/// +/// Similar to [`iter::from_fn`]. +/// +/// [`iter::from_fn`]: crate::iter::from_fn +/// +/// # Examples +/// +/// ``` +/// #![feature(generators)] +/// #![feature(iter_from_generator)] +/// +/// let it = std::iter::from_generator(|| { +/// yield 1; +/// yield 2; +/// yield 3; +/// }); +/// let v: Vec<_> = it.collect(); +/// assert_eq!(v, [1, 2, 3]); +/// ``` +#[inline] +#[unstable(feature = "iter_from_generator", issue = "43122", reason = "generators are unstable")] +pub fn from_generator<G: Generator<Return = ()> + Unpin>( + generator: G, +) -> impl Iterator<Item = G::Yield> { + FromGenerator(generator) +} + +struct FromGenerator<G>(G); + +impl<G: Generator<Return = ()> + Unpin> Iterator for FromGenerator<G> { + type Item = G::Yield; + + fn next(&mut self) -> Option<Self::Item> { + match Pin::new(&mut self.0).resume(()) { + GeneratorState::Yielded(n) => Some(n), + GeneratorState::Complete(()) => None, + } + } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7b04e4423b7..cfcc3ffb9c0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -310,6 +310,7 @@ pub mod ops; pub mod any; pub mod array; pub mod ascii; +pub mod asserting; #[unstable(feature = "async_iterator", issue = "79024")] pub mod async_iter; pub mod cell; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index d0746698f40..28ea45ed235 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -708,6 +708,26 @@ impl<T> Option<T> { /// let x: Option<&str> = None; /// x.expect("fruits are healthy"); // panics with `fruits are healthy` /// ``` + /// + /// # Recommended Message Style + /// + /// We recommend that `expect` messages are used to describe the reason you + /// _expect_ the `Option` should be `Some`. + /// + /// ```should_panic + /// # let slice: &[u8] = &[]; + /// let item = slice.get(0) + /// .expect("slice should not be empty"); + /// ``` + /// + /// **Hint**: If you're having trouble remembering how to phrase expect + /// error messages remember to focus on the word "should" as in "env + /// variable should be set by blah" or "the given binary should be available + /// and executable by the current user". + /// + /// For more detail on expect message styles and the reasoning behind our + /// recommendation please refer to the section on ["Common Message + /// Styles"](../../std/error/index.html#common-message-styles) in the [`std::error`](../../std/error/index.html) module docs. #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index dc229c9ff9b..d2e680ecd20 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -507,10 +507,33 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_diagnostic_item = "ptr_null"] +#[cfg(bootstrap)] pub const fn null<T>() -> *const T { invalid(0) } +/// Creates a null raw pointer. +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let p: *const i32 = ptr::null(); +/// assert!(p.is_null()); +/// ``` +#[inline(always)] +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] +#[rustc_allow_const_fn_unstable(ptr_metadata)] +#[rustc_diagnostic_item = "ptr_null"] +#[cfg(not(bootstrap))] +pub const fn null<T: ?Sized + Thin>() -> *const T { + from_raw_parts(0 as *const (), ()) +} + /// Creates a null mutable raw pointer. /// /// # Examples @@ -527,6 +550,7 @@ pub const fn null<T>() -> *const T { #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_diagnostic_item = "ptr_null_mut"] +#[cfg(bootstrap)] pub const fn null_mut<T>() -> *mut T { invalid_mut(0) } @@ -665,6 +689,28 @@ where addr as *mut T } +/// Creates a null mutable raw pointer. +/// +/// # Examples +/// +/// ``` +/// use std::ptr; +/// +/// let p: *mut i32 = ptr::null_mut(); +/// assert!(p.is_null()); +/// ``` +#[inline(always)] +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_promotable] +#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] +#[rustc_allow_const_fn_unstable(ptr_metadata)] +#[rustc_diagnostic_item = "ptr_null_mut"] +#[cfg(not(bootstrap))] +pub const fn null_mut<T: ?Sized + Thin>() -> *mut T { + from_raw_parts_mut(0 as *mut (), ()) +} + /// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5e5f8a5ab95..c4dc34fff97 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1023,6 +1023,26 @@ impl<T, E> Result<T, E> { /// let x: Result<u32, &str> = Err("emergency failure"); /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` /// ``` + /// + /// # Recommended Message Style + /// + /// We recommend that `expect` messages are used to describe the reason you + /// _expect_ the `Result` should be `Ok`. + /// + /// ```should_panic + /// let path = std::env::var("IMPORTANT_PATH") + /// .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); + /// ``` + /// + /// **Hint**: If you're having trouble remembering how to phrase expect + /// error messages remember to focus on the word "should" as in "env + /// variable should be set by blah" or "the given binary should be available + /// and executable by the current user". + /// + /// For more detail on expect message styles and the reasoning behind our recommendation please + /// refer to the section on ["Common Message + /// Styles"](../../std/error/index.html#common-message-styles) in the + /// [`std::error`](../../std/error/index.html) module docs. #[inline] #[track_caller] #[stable(feature = "result_expect", since = "1.4.0")] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 6c97305b1a8..756f1a1663c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -730,9 +730,9 @@ impl Duration { /// // subnormal float /// let res = Duration::from_secs_f64(f64::from_bits(1)); /// assert_eq!(res, Duration::new(0, 0)); - /// // conversion uses truncation, not rounding + /// // conversion uses rounding /// let res = Duration::from_secs_f64(0.999e-9); - /// assert_eq!(res, Duration::new(0, 0)); + /// assert_eq!(res, Duration::new(0, 1)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] @@ -760,17 +760,17 @@ impl Duration { /// let res = Duration::from_secs_f32(1e-20); /// assert_eq!(res, Duration::new(0, 0)); /// let res = Duration::from_secs_f32(4.2e-7); - /// assert_eq!(res, Duration::new(0, 419)); + /// assert_eq!(res, Duration::new(0, 420)); /// let res = Duration::from_secs_f32(2.7); - /// assert_eq!(res, Duration::new(2, 700_000_047)); + /// assert_eq!(res, Duration::new(2, 700_000_048)); /// let res = Duration::from_secs_f32(3e10); /// assert_eq!(res, Duration::new(30_000_001_024, 0)); /// // subnormal float /// let res = Duration::from_secs_f32(f32::from_bits(1)); /// assert_eq!(res, Duration::new(0, 0)); - /// // conversion uses truncation, not rounding + /// // conversion uses rounding /// let res = Duration::from_secs_f32(0.999e-9); - /// assert_eq!(res, Duration::new(0, 0)); + /// assert_eq!(res, Duration::new(0, 1)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use] @@ -815,7 +815,7 @@ impl Duration { /// use std::time::Duration; /// /// let dur = Duration::new(2, 700_000_000); - /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640)); + /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641)); /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] @@ -838,8 +838,7 @@ impl Duration { /// /// let dur = Duration::new(2, 700_000_000); /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611)); - /// // note that truncation is used, not rounding - /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598)); + /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_599)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ @@ -862,9 +861,8 @@ impl Duration { /// let dur = Duration::new(2, 700_000_000); /// // note that due to rounding errors result is slightly /// // different from 0.859_872_611 - /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579)); - /// // note that truncation is used, not rounding - /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598)); + /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_580)); + /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_599)); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[must_use = "this returns the result of the operation, \ @@ -1272,19 +1270,53 @@ macro_rules! try_from_secs { let mant = (bits & MANT_MASK) | (MANT_MASK + 1); let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP; - let (secs, nanos) = if exp < -30 { - // the input represents less than 1ns. + let (secs, nanos) = if exp < -31 { + // the input represents less than 1ns and can not be rounded to it (0u64, 0u32) } else if exp < 0 { // the input is less than 1 second let t = <$double_ty>::from(mant) << ($offset + exp); - let nanos = (u128::from(NANOS_PER_SEC) * u128::from(t)) >> ($mant_bits + $offset); - (0, nanos as u32) + let nanos_offset = $mant_bits + $offset; + let nanos_tmp = u128::from(NANOS_PER_SEC) * u128::from(t); + let nanos = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // f32 does not have enough presicion to trigger the second branch + // since it can not represent numbers between 0.999_999_940_395 and 1.0. + let nanos = nanos + add_ns as u32; + if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) } } else if exp < $mant_bits { - let secs = mant >> ($mant_bits - exp); + let secs = u64::from(mant >> ($mant_bits - exp)); let t = <$double_ty>::from((mant << exp) & MANT_MASK); - let nanos = (<$double_ty>::from(NANOS_PER_SEC) * t) >> $mant_bits; - (u64::from(secs), nanos as u32) + let nanos_offset = $mant_bits; + let nanos_tmp = <$double_ty>::from(NANOS_PER_SEC) * t; + let nanos = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // f32 does not have enough presicion to trigger the second branch. + // For example, it can not represent numbers between 1.999_999_880... + // and 2.0. Bigger values result in even smaller presicion of the + // fractional part. + let nanos = nanos + add_ns as u32; + if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { + (secs, nanos) + } else { + (secs + 1, 0) + } } else if exp < 64 { // the input has no fractional part let secs = u64::from(mant) << (exp - $mant_bits); @@ -1315,17 +1347,14 @@ impl Duration { /// let res = Duration::try_from_secs_f32(1e-20); /// assert_eq!(res, Ok(Duration::new(0, 0))); /// let res = Duration::try_from_secs_f32(4.2e-7); - /// assert_eq!(res, Ok(Duration::new(0, 419))); + /// assert_eq!(res, Ok(Duration::new(0, 420))); /// let res = Duration::try_from_secs_f32(2.7); - /// assert_eq!(res, Ok(Duration::new(2, 700_000_047))); + /// assert_eq!(res, Ok(Duration::new(2, 700_000_048))); /// let res = Duration::try_from_secs_f32(3e10); /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0))); /// // subnormal float: /// let res = Duration::try_from_secs_f32(f32::from_bits(1)); /// assert_eq!(res, Ok(Duration::new(0, 0))); - /// // conversion uses truncation, not rounding - /// let res = Duration::try_from_secs_f32(0.999e-9); - /// assert_eq!(res, Ok(Duration::new(0, 0))); /// /// let res = Duration::try_from_secs_f32(-5.0); /// assert!(res.is_err()); @@ -1333,6 +1362,30 @@ impl Duration { /// assert!(res.is_err()); /// let res = Duration::try_from_secs_f32(2e19); /// assert!(res.is_err()); + /// + /// // the conversion uses rounding with tie resolution to even + /// let res = Duration::try_from_secs_f32(0.999e-9); + /// assert_eq!(res, Ok(Duration::new(0, 1))); + /// + /// // this float represents exactly 976562.5e-9 + /// let val = f32::from_bits(0x3A80_0000); + /// let res = Duration::try_from_secs_f32(val); + /// assert_eq!(res, Ok(Duration::new(0, 976_562))); + /// + /// // this float represents exactly 2929687.5e-9 + /// let val = f32::from_bits(0x3B40_0000); + /// let res = Duration::try_from_secs_f32(val); + /// assert_eq!(res, Ok(Duration::new(0, 2_929_688))); + /// + /// // this float represents exactly 1.000_976_562_5 + /// let val = f32::from_bits(0x3F802000); + /// let res = Duration::try_from_secs_f32(val); + /// assert_eq!(res, Ok(Duration::new(1, 976_562))); + /// + /// // this float represents exactly 1.002_929_687_5 + /// let val = f32::from_bits(0x3F806000); + /// let res = Duration::try_from_secs_f32(val); + /// assert_eq!(res, Ok(Duration::new(1, 2_929_688))); /// ``` #[unstable(feature = "duration_checked_float", issue = "83400")] #[inline] @@ -1372,9 +1425,6 @@ impl Duration { /// // subnormal float /// let res = Duration::try_from_secs_f64(f64::from_bits(1)); /// assert_eq!(res, Ok(Duration::new(0, 0))); - /// // conversion uses truncation, not rounding - /// let res = Duration::try_from_secs_f32(0.999e-9); - /// assert_eq!(res, Ok(Duration::new(0, 0))); /// /// let res = Duration::try_from_secs_f64(-5.0); /// assert!(res.is_err()); @@ -1382,6 +1432,38 @@ impl Duration { /// assert!(res.is_err()); /// let res = Duration::try_from_secs_f64(2e19); /// assert!(res.is_err()); + /// + /// // the conversion uses rounding with tie resolution to even + /// let res = Duration::try_from_secs_f64(0.999e-9); + /// assert_eq!(res, Ok(Duration::new(0, 1))); + /// let res = Duration::try_from_secs_f64(0.999_999_999_499); + /// assert_eq!(res, Ok(Duration::new(0, 999_999_999))); + /// let res = Duration::try_from_secs_f64(0.999_999_999_501); + /// assert_eq!(res, Ok(Duration::new(1, 0))); + /// let res = Duration::try_from_secs_f64(42.999_999_999_499); + /// assert_eq!(res, Ok(Duration::new(42, 999_999_999))); + /// let res = Duration::try_from_secs_f64(42.999_999_999_501); + /// assert_eq!(res, Ok(Duration::new(43, 0))); + /// + /// // this float represents exactly 976562.5e-9 + /// let val = f64::from_bits(0x3F50_0000_0000_0000); + /// let res = Duration::try_from_secs_f64(val); + /// assert_eq!(res, Ok(Duration::new(0, 976_562))); + /// + /// // this float represents exactly 2929687.5e-9 + /// let val = f64::from_bits(0x3F68_0000_0000_0000); + /// let res = Duration::try_from_secs_f64(val); + /// assert_eq!(res, Ok(Duration::new(0, 2_929_688))); + /// + /// // this float represents exactly 1.000_976_562_5 + /// let val = f64::from_bits(0x3FF0_0400_0000_0000); + /// let res = Duration::try_from_secs_f64(val); + /// assert_eq!(res, Ok(Duration::new(1, 976_562))); + /// + /// // this float represents exactly 1.002_929_687_5 + /// let val = f64::from_bits(0x3_FF00_C000_0000_000); + /// let res = Duration::try_from_secs_f64(val); + /// assert_eq!(res, Ok(Duration::new(1, 2_929_688))); /// ``` #[unstable(feature = "duration_checked_float", issue = "83400")] #[inline] diff --git a/library/core/tests/asserting.rs b/library/core/tests/asserting.rs new file mode 100644 index 00000000000..4b626ba6f2d --- /dev/null +++ b/library/core/tests/asserting.rs @@ -0,0 +1,37 @@ +use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper}; + +macro_rules! test { + ($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => { + #[test] + fn $test_name() { + let elem = $elem; + let mut capture = Capture::new(); + assert!(capture.elem == None); + (&Wrapper(&elem)).try_capture(&mut capture); + assert!(capture.elem == $captured_elem); + assert_eq!(format!("{:?}", capture), $output); + } + }; +} + +#[derive(Debug, PartialEq)] +struct NoCopy; + +#[derive(PartialEq)] +struct NoCopyNoDebug; + +#[derive(Clone, Copy, PartialEq)] +struct NoDebug; + +test!( + capture_with_non_copyable_and_non_debugabble_elem_has_correct_params, + NoCopyNoDebug, + None, + "N/A" +); + +test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A"); + +test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A"); + +test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1"); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 004589bbc31..9ea374e1045 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -35,6 +35,7 @@ #![feature(float_minimum_maximum)] #![feature(future_join)] #![feature(future_poll_fn)] +#![feature(generic_assert_internals)] #![feature(array_try_from_fn)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] @@ -104,6 +105,7 @@ mod alloc; mod any; mod array; mod ascii; +mod asserting; mod atomic; mod bool; mod cell; diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 03fe56022b0..c5242ad04de 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -93,6 +93,18 @@ fn test_is_null() { let nmi: *mut dyn ToString = null_mut::<isize>(); assert!(nmi.is_null()); + + #[cfg(not(bootstrap))] + { + extern "C" { + type Extern; + } + let ec: *const Extern = null::<Extern>(); + assert!(ec.is_null()); + + let em: *mut Extern = null_mut::<Extern>(); + assert!(em.is_null()); + } } #[test] diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index d82669d3e23..fb05a02dc45 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -6,37 +6,37 @@ use std::ops::{Deref, DerefMut}; use std::slice; #[repr(C)] -pub struct Buffer<T: Copy> { - data: *mut T, +pub struct Buffer { + data: *mut u8, len: usize, capacity: usize, - reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>, - drop: extern "C" fn(Buffer<T>), + reserve: extern "C" fn(Buffer, usize) -> Buffer, + drop: extern "C" fn(Buffer), } -unsafe impl<T: Copy + Sync> Sync for Buffer<T> {} -unsafe impl<T: Copy + Send> Send for Buffer<T> {} +unsafe impl Sync for Buffer {} +unsafe impl Send for Buffer {} -impl<T: Copy> Default for Buffer<T> { +impl Default for Buffer { fn default() -> Self { Self::from(vec![]) } } -impl<T: Copy> Deref for Buffer<T> { - type Target = [T]; - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data as *const T, self.len) } +impl Deref for Buffer { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data as *const u8, self.len) } } } -impl<T: Copy> DerefMut for Buffer<T> { - fn deref_mut(&mut self) -> &mut [T] { +impl DerefMut for Buffer { + fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.data, self.len) } } } -impl<T: Copy> Buffer<T> { +impl Buffer { pub(super) fn new() -> Self { Self::default() } @@ -53,7 +53,7 @@ impl<T: Copy> Buffer<T> { // because in the case of small arrays, codegen can be more efficient // (avoiding a memmove call). With extend_from_slice, LLVM at least // currently is not able to make that optimization. - pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) { + pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[u8; N]) { if xs.len() > (self.capacity - self.len) { let b = self.take(); *self = (b.reserve)(b, xs.len()); @@ -64,7 +64,7 @@ impl<T: Copy> Buffer<T> { } } - pub(super) fn extend_from_slice(&mut self, xs: &[T]) { + pub(super) fn extend_from_slice(&mut self, xs: &[u8]) { if xs.len() > (self.capacity - self.len) { let b = self.take(); *self = (b.reserve)(b, xs.len()); @@ -75,7 +75,7 @@ impl<T: Copy> Buffer<T> { } } - pub(super) fn push(&mut self, v: T) { + pub(super) fn push(&mut self, v: u8) { // The code here is taken from Vec::push, and we know that reserve() // will panic if we're exceeding isize::MAX bytes and so there's no need // to check for overflow. @@ -90,7 +90,7 @@ impl<T: Copy> Buffer<T> { } } -impl Write for Buffer<u8> { +impl Write for Buffer { fn write(&mut self, xs: &[u8]) -> io::Result<usize> { self.extend_from_slice(xs); Ok(xs.len()) @@ -106,21 +106,21 @@ impl Write for Buffer<u8> { } } -impl<T: Copy> Drop for Buffer<T> { +impl Drop for Buffer { fn drop(&mut self) { let b = self.take(); (b.drop)(b); } } -impl<T: Copy> From<Vec<T>> for Buffer<T> { - fn from(mut v: Vec<T>) -> Self { +impl From<Vec<u8>> for Buffer { + fn from(mut v: Vec<u8>) -> Self { let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); mem::forget(v); // This utility function is nested in here because it can *only* // be safely called on `Buffer`s created by *this* `proc_macro`. - fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> { + fn to_vec(b: Buffer) -> Vec<u8> { unsafe { let Buffer { data, len, capacity, .. } = b; mem::forget(b); @@ -128,13 +128,13 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> { } } - extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> { + extern "C" fn reserve(b: Buffer, additional: usize) -> Buffer { let mut v = to_vec(b); v.reserve(additional); Buffer::from(v) } - extern "C" fn drop<T: Copy>(b: Buffer<T>) { + extern "C" fn drop(b: Buffer) { mem::drop(to_vec(b)); } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index cdb2bac2607..54d92ff5767 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -49,7 +49,9 @@ macro_rules! define_handles { #[repr(C)] pub(crate) struct $oty { handle: handle::Handle, - // Prevent Send and Sync impls + // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual + // way of doing this, but that requires unstable features. + // rust-analyzer uses this code and avoids unstable features. _marker: PhantomData<*mut ()>, } @@ -133,7 +135,9 @@ macro_rules! define_handles { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub(crate) struct $ity { handle: handle::Handle, - // Prevent Send and Sync impls + // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual + // way of doing this, but that requires unstable features. + // rust-analyzer uses this code and avoids unstable features. _marker: PhantomData<*mut ()>, } @@ -191,7 +195,7 @@ define_handles! { // FIXME(eddyb) generate these impls by pattern-matching on the // names of methods - also could use the presence of `fn drop` // to distinguish between 'owned and 'interned, above. -// Alternatively, special 'modes" could be listed of types in with_api +// Alternatively, special "modes" could be listed of types in with_api // instead of pattern matching on methods, here and in server decl. impl Clone for TokenStream { @@ -250,17 +254,17 @@ macro_rules! define_client_side { $(impl $name { $(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* { Bridge::with(|bridge| { - let mut b = bridge.cached_buffer.take(); + let mut buf = bridge.cached_buffer.take(); - b.clear(); - api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ()); - reverse_encode!(b; $($arg),*); + buf.clear(); + api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ()); + reverse_encode!(buf; $($arg),*); - b = bridge.dispatch.call(b); + buf = bridge.dispatch.call(buf); - let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ()); + let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ()); - bridge.cached_buffer = b; + bridge.cached_buffer = buf; r.unwrap_or_else(|e| panic::resume_unwind(e.into())) }) @@ -367,7 +371,7 @@ pub struct Client<F> { // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of // a wrapper `fn` pointer, once `const fn` can reference `static`s. pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>, + pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer, pub(super) f: F, } @@ -377,22 +381,22 @@ pub struct Client<F> { fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( mut bridge: Bridge<'_>, f: impl FnOnce(A) -> R, -) -> Buffer<u8> { +) -> Buffer { // The initial `cached_buffer` contains the input. - let mut b = bridge.cached_buffer.take(); + let mut buf = bridge.cached_buffer.take(); panic::catch_unwind(panic::AssertUnwindSafe(|| { bridge.enter(|| { - let reader = &mut &b[..]; + let reader = &mut &buf[..]; let input = A::decode(reader, &mut ()); // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = b.take()); + Bridge::with(|bridge| bridge.cached_buffer = buf.take()); let output = f(input); // Take the `cached_buffer` back out, for the output value. - b = Bridge::with(|bridge| bridge.cached_buffer.take()); + buf = Bridge::with(|bridge| bridge.cached_buffer.take()); // HACK(eddyb) Separate encoding a success value (`Ok(output)`) // from encoding a panic (`Err(e: PanicMessage)`) to avoid @@ -403,16 +407,16 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( // this is defensively trying to avoid any accidental panicking // reaching the `extern "C"` (which should `abort` but might not // at the moment, so this is also potentially preventing UB). - b.clear(); - Ok::<_, ()>(output).encode(&mut b, &mut ()); + buf.clear(); + Ok::<_, ()>(output).encode(&mut buf, &mut ()); }) })) .map_err(PanicMessage::from) .unwrap_or_else(|e| { - b.clear(); - Err::<(), _>(e).encode(&mut b, &mut ()); + buf.clear(); + Err::<(), _>(e).encode(&mut buf, &mut ()); }); - b + buf } impl Client<fn(crate::TokenStream) -> crate::TokenStream> { @@ -420,7 +424,7 @@ impl Client<fn(crate::TokenStream) -> crate::TokenStream> { extern "C" fn run( bridge: Bridge<'_>, f: impl FnOnce(crate::TokenStream) -> crate::TokenStream, - ) -> Buffer<u8> { + ) -> Buffer { run_client(bridge, |input| f(crate::TokenStream(input)).0) } Client { get_handle_counters: HandleCounters::get, run, f } @@ -434,7 +438,7 @@ impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> { extern "C" fn run( bridge: Bridge<'_>, f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, - ) -> Buffer<u8> { + ) -> Buffer { run_client(bridge, |(input, input2)| { f(crate::TokenStream(input), crate::TokenStream(input2)).0 }) diff --git a/library/proc_macro/src/bridge/closure.rs b/library/proc_macro/src/bridge/closure.rs index 06f76d2fc91..d371ae3cea0 100644 --- a/library/proc_macro/src/bridge/closure.rs +++ b/library/proc_macro/src/bridge/closure.rs @@ -6,7 +6,11 @@ use std::marker::PhantomData; pub struct Closure<'a, A, R> { call: unsafe extern "C" fn(*mut Env, A) -> R, env: *mut Env, - // Ensure Closure is !Send and !Sync + // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing + // this, but that requires unstable features. rust-analyzer uses this code + // and avoids unstable features. + // + // The `'a` lifetime parameter represents the lifetime of `Env`. _marker: PhantomData<*mut &'a mut ()>, } diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs index bcbb8681247..7d6adda48ec 100644 --- a/library/proc_macro/src/bridge/handle.rs +++ b/library/proc_macro/src/bridge/handle.rs @@ -8,6 +8,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; pub(super) type Handle = NonZeroU32; +/// A store that associates values of type `T` with numeric handles. A value can +/// be looked up using its handle. pub(super) struct OwnedStore<T: 'static> { counter: &'static AtomicUsize, data: BTreeMap<Handle, T>, @@ -49,6 +51,7 @@ impl<T> IndexMut<Handle> for OwnedStore<T> { } } +/// Like `OwnedStore`, but avoids storing any value more than once. pub(super) struct InternedStore<T: 'static> { owned: OwnedStore<T>, interner: HashMap<T, Handle>, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index f7c9df6564f..babb1cbac70 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -176,7 +176,7 @@ macro_rules! with_api { } // FIXME(eddyb) this calls `encode` for each argument, but in reverse, -// to avoid borrow conflicts from borrows started by `&mut` arguments. +// to match the ordering in `reverse_decode`. macro_rules! reverse_encode { ($writer:ident;) => {}; ($writer:ident; $first:ident $(, $rest:ident)*) => { @@ -224,15 +224,17 @@ use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; pub struct Bridge<'a> { /// Reusable buffer (only `clear`-ed, never shrunk), primarily /// used for making requests, but also for passing input to client. - cached_buffer: Buffer<u8>, + cached_buffer: Buffer, /// Server-side function that the client uses to make requests. - dispatch: closure::Closure<'a, Buffer<u8>, Buffer<u8>>, + dispatch: closure::Closure<'a, Buffer, Buffer>, /// If 'true', always invoke the default panic hook force_show_panics: bool, - // Prevent Send and Sync impls + // Prevent Send and Sync impls. `!Send`/`!Sync` is the usual way of doing + // this, but that requires unstable features. rust-analyzer uses this code + // and avoids unstable features. _marker: marker::PhantomData<*mut ()>, } @@ -252,7 +254,6 @@ mod api_tags { rpc_encode_decode!(enum $name { $($method),* }); )* - pub(super) enum Method { $($name($name)),* } diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index d50564d01a5..f79e016400f 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -7,7 +7,7 @@ use std::num::NonZeroU32; use std::ops::Bound; use std::str; -pub(super) type Writer = super::buffer::Buffer<u8>; +pub(super) type Writer = super::buffer::Buffer; pub(super) trait Encode<S>: Sized { fn encode(self, w: &mut Writer, s: &mut S); diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index 2e0400d32a0..12c754682a0 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -5,37 +5,30 @@ use super::*; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. use super::client::HandleStore; -/// Declare an associated item of one of the traits below, optionally -/// adjusting it (i.e., adding bounds to types and default bodies to methods). -macro_rules! associated_item { - (type FreeFunctions) => - (type FreeFunctions: 'static;); - (type TokenStream) => - (type TokenStream: 'static + Clone;); - (type TokenStreamBuilder) => - (type TokenStreamBuilder: 'static;); - (type TokenStreamIter) => - (type TokenStreamIter: 'static + Clone;); - (type Group) => - (type Group: 'static + Clone;); - (type Punct) => - (type Punct: 'static + Copy + Eq + Hash;); - (type Ident) => - (type Ident: 'static + Copy + Eq + Hash;); - (type Literal) => - (type Literal: 'static + Clone;); - (type SourceFile) => - (type SourceFile: 'static + Clone;); - (type MultiSpan) => - (type MultiSpan: 'static;); - (type Diagnostic) => - (type Diagnostic: 'static;); - (type Span) => - (type Span: 'static + Copy + Eq + Hash;); +pub trait Types { + type FreeFunctions: 'static; + type TokenStream: 'static + Clone; + type TokenStreamBuilder: 'static; + type TokenStreamIter: 'static + Clone; + type Group: 'static + Clone; + type Punct: 'static + Copy + Eq + Hash; + type Ident: 'static + Copy + Eq + Hash; + type Literal: 'static + Clone; + type SourceFile: 'static + Clone; + type MultiSpan: 'static; + type Diagnostic: 'static; + type Span: 'static + Copy + Eq + Hash; +} + +/// Declare an associated fn of one of the traits below, adding necessary +/// default bodies. +macro_rules! associated_fn { (fn drop(&mut self, $arg:ident: $arg_ty:ty)) => (fn drop(&mut self, $arg: $arg_ty) { mem::drop($arg) }); + (fn clone(&mut self, $arg:ident: $arg_ty:ty) -> $ret_ty:ty) => (fn clone(&mut self, $arg: $arg_ty) -> $ret_ty { $arg.clone() }); + ($($item:tt)*) => ($($item)*;) } @@ -43,12 +36,8 @@ macro_rules! declare_server_traits { ($($name:ident { $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* }),* $(,)?) => { - pub trait Types { - $(associated_item!(type $name);)* - } - $(pub trait $name: Types { - $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* + $(associated_fn!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* })* pub trait Server: Types $(+ $name)* {} @@ -89,15 +78,15 @@ macro_rules! define_dispatcher_impl { pub trait DispatcherTrait { // HACK(eddyb) these are here to allow `Self::$name` to work below. $(type $name;)* - fn dispatch(&mut self, b: Buffer<u8>) -> Buffer<u8>; + fn dispatch(&mut self, buf: Buffer) -> Buffer; } impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> { $(type $name = <MarkedTypes<S> as Types>::$name;)* - fn dispatch(&mut self, mut b: Buffer<u8>) -> Buffer<u8> { + fn dispatch(&mut self, mut buf: Buffer) -> Buffer { let Dispatcher { handle_store, server } = self; - let mut reader = &b[..]; + let mut reader = &buf[..]; match api_tags::Method::decode(&mut reader, &mut ()) { $(api_tags::Method::$name(m) => match m { $(api_tags::$name::$method => { @@ -116,12 +105,12 @@ macro_rules! define_dispatcher_impl { .map_err(PanicMessage::from) }; - b.clear(); - r.encode(&mut b, handle_store); + buf.clear(); + r.encode(&mut buf, handle_store); })* }),* } - b + buf } } } @@ -132,11 +121,11 @@ pub trait ExecutionStrategy { fn run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, - input: Buffer<u8>, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, + input: Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, force_show_panics: bool, - ) -> Buffer<u8>; + ) -> Buffer; } pub struct SameThread; @@ -145,12 +134,12 @@ impl ExecutionStrategy for SameThread { fn run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, - input: Buffer<u8>, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, + input: Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, force_show_panics: bool, - ) -> Buffer<u8> { - let mut dispatch = |b| dispatcher.dispatch(b); + ) -> Buffer { + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client( Bridge { @@ -173,19 +162,19 @@ impl ExecutionStrategy for CrossThread1 { fn run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, - input: Buffer<u8>, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, + input: Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, force_show_panics: bool, - ) -> Buffer<u8> { + ) -> Buffer { use std::sync::mpsc::channel; let (req_tx, req_rx) = channel(); let (res_tx, res_rx) = channel(); let join_handle = thread::spawn(move || { - let mut dispatch = |b| { - req_tx.send(b).unwrap(); + let mut dispatch = |buf| { + req_tx.send(buf).unwrap(); res_rx.recv().unwrap() }; @@ -214,11 +203,11 @@ impl ExecutionStrategy for CrossThread2 { fn run_bridge_and_client<D: Copy + Send + 'static>( &self, dispatcher: &mut impl DispatcherTrait, - input: Buffer<u8>, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, + input: Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, force_show_panics: bool, - ) -> Buffer<u8> { + ) -> Buffer { use std::sync::{Arc, Mutex}; enum State<T> { @@ -285,25 +274,25 @@ fn run_server< handle_counters: &'static client::HandleCounters, server: S, input: I, - run_client: extern "C" fn(Bridge<'_>, D) -> Buffer<u8>, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, force_show_panics: bool, ) -> Result<O, PanicMessage> { let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; - let mut b = Buffer::new(); - input.encode(&mut b, &mut dispatcher.handle_store); + let mut buf = Buffer::new(); + input.encode(&mut buf, &mut dispatcher.handle_store); - b = strategy.run_bridge_and_client( + buf = strategy.run_bridge_and_client( &mut dispatcher, - b, + buf, run_client, client_data, force_show_panics, ); - Result::decode(&mut &b[..], &mut dispatcher.handle_store) + Result::decode(&mut &buf[..], &mut dispatcher.handle_store) } impl client::Client<fn(crate::TokenStream) -> crate::TokenStream> { diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 438304e1664..c2d30616019 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1,4 +1,140 @@ -//! Traits for working with Errors. +//! Interfaces for working with Errors. +//! +//! # Error Handling In Rust +//! +//! The Rust language provides two complementary systems for constructing / +//! representing, reporting, propagating, reacting to, and discarding errors. +//! These responsibilities are collectively known as "error handling." The +//! components of the first system, the panic runtime and interfaces, are most +//! commonly used to represent bugs that have been detected in your program. The +//! components of the second system, `Result`, the error traits, and user +//! defined types, are used to represent anticipated runtime failure modes of +//! your program. +//! +//! ## The Panic Interfaces +//! +//! The following are the primary interfaces of the panic system and the +//! responsibilities they cover: +//! +//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +//! * [`PanicInfo`] (Reporting) +//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) +//! +//! The following are the primary interfaces of the error system and the +//! responsibilities they cover: +//! +//! * [`Result`] (Propagating, Reacting) +//! * The [`Error`] trait (Reporting) +//! * User defined types (Constructing / Representing) +//! * [`match`] and [`downcast`] (Reacting) +//! * The question mark operator ([`?`]) (Propagating) +//! * The partially stable [`Try`] traits (Propagating, Constructing) +//! * [`Termination`] (Reporting) +//! +//! ## Converting Errors into Panics +//! +//! The panic and error systems are not entirely distinct. Often times errors +//! that are anticipated runtime failures in an API might instead represent bugs +//! to a caller. For these situations the standard library provides APIs for +//! constructing panics with an `Error` as it's source. +//! +//! * [`Result::unwrap`] +//! * [`Result::expect`] +//! +//! These functions are equivalent, they either return the inner value if the +//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +//! as the source. The only difference between them is that with `expect` you +//! provide a panic error message to be printed alongside the source, whereas +//! `unwrap` has a default message indicating only that you unwraped an `Err`. +//! +//! Of the two, `expect` is generally preferred since its `msg` field allows you +//! to convey your intent and assumptions which makes tracking down the source +//! of a panic easier. `unwrap` on the other hand can still be a good fit in +//! situations where you can trivially show that a piece of code will never +//! panick, such as `"127.0.0.1".parse::<std::net::IpAddr>().unwrap()` or early +//! prototyping. +//! +//! # Common Message Styles +//! +//! There are two common styles for how people word `expect` messages. Using +//! the message to present information to users encountering a panic +//! ("expect as error message") or using the message to present information +//! to developers debugging the panic ("expect as precondition"). +//! +//! In the former case the expect message is used to describe the error that +//! has occurred which is considered a bug. Consider the following example: +//! +//! ```should_panic +//! // Read environment variable, panic if it is not present +//! let path = std::env::var("IMPORTANT_PATH").unwrap(); +//! ``` +//! +//! In the "expect as error message" style we would use expect to describe +//! that the environment variable was not set when it should have been: +//! +//! ```should_panic +//! let path = std::env::var("IMPORTANT_PATH") +//! .expect("env variable `IMPORTANT_PATH` is not set"); +//! ``` +//! +//! In the "expect as precondition" style, we would instead describe the +//! reason we _expect_ the `Result` should be `Ok`. With this style we would +//! prefer to write: +//! +//! ```should_panic +//! let path = std::env::var("IMPORTANT_PATH") +//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +//! ``` +//! +//! The "expect as error message" style does not work as well with the +//! default output of the std panic hooks, and often ends up repeating +//! information that is already communicated by the source error being +//! unwrapped: +//! +//! ```text +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +//! ``` +//! +//! In this example we end up mentioning that an env variable is not set, +//! followed by our source message that says the env is not present, the +//! only additional information we're communicating is the name of the +//! environment variable being checked. +//! +//! The "expect as precondition" style instead focuses on source code +//! readability, making it easier to understand what must have gone wrong in +//! situations where panics are being used to represent bugs exclusively. +//! Also, by framing our expect in terms of what "SHOULD" have happened to +//! prevent the source error, we end up introducing new information that is +//! independent from our source error. +//! +//! ```text +//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +//! ``` +//! +//! In this example we are communicating not only the name of the +//! environment variable that should have been set, but also an explanation +//! for why it should have been set, and we let the source error display as +//! a clear contradiction to our expectation. +//! +//! **Hint**: If you're having trouble remembering how to phrase +//! expect-as-precondition style error messages remember to focus on the word +//! "should" as in "env variable should be set by blah" or "the given binary +//! should be available and executable by the current user". +//! +//! [`panic_any`]: crate::panic::panic_any +//! [`PanicInfo`]: crate::panic::PanicInfo +//! [`catch_unwind`]: crate::panic::catch_unwind +//! [`resume_unwind`]: crate::panic::resume_unwind +//! [`downcast`]: crate::error::Error +//! [`Termination`]: crate::process::Termination +//! [`Try`]: crate::ops::Try +//! [panic hook]: crate::panic::set_hook +//! [`set_hook`]: crate::panic::set_hook +//! [`take_hook`]: crate::panic::take_hook +//! [panic-handler]: <https://doc.rust-lang.org/nomicon/panic-handler.html> +//! [`match`]: ../../std/keyword.match.html +//! [`?`]: ../../std/result/index.html#the-question-mark-operator- #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 9e31b8b32a1..ecee123a9b6 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -1,3 +1,5 @@ +// FIXME: This is currently disabled on *BSD. + use super::{sockaddr_un, SocketAddr}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 872058b36e6..0b1d9b07132 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -1,24 +1,7 @@ -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(doc, target_os = "android", target_os = "linux"))] use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; use super::{sockaddr_un, SocketAddr}; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(doc, target_os = "android", target_os = "linux"))] use crate::io::{IoSlice, IoSliceMut}; use crate::net::Shutdown; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; @@ -403,7 +386,8 @@ impl UnixDatagram { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; /// use std::io::IoSliceMut; @@ -433,15 +417,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary_from( &self, @@ -460,7 +436,8 @@ impl UnixDatagram { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData}; /// use std::io::IoSliceMut; @@ -490,15 +467,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, @@ -609,7 +578,8 @@ impl UnixDatagram { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; /// use std::io::IoSlice; @@ -633,15 +603,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>( &self, @@ -658,7 +620,8 @@ impl UnixDatagram { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixDatagram, SocketAncillary}; /// use std::io::IoSlice; @@ -682,15 +645,7 @@ impl UnixDatagram { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs index 8ce82208854..6da3e350bf1 100644 --- a/library/std/src/os/unix/net/mod.rs +++ b/library/std/src/os/unix/net/mod.rs @@ -1,27 +1,11 @@ //! Unix-specific networking functionality. +#![allow(irrefutable_let_patterns)] #![stable(feature = "unix_socket", since = "1.10.0")] mod addr; -#[doc(cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -)))] -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[doc(cfg(any(target_os = "android", target_os = "linux")))] +#[cfg(any(doc, target_os = "android", target_os = "linux"))] mod ancillary; mod datagram; mod listener; @@ -31,16 +15,7 @@ mod tests; #[stable(feature = "unix_socket", since = "1.10.0")] pub use self::addr::*; -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub use self::ancillary::*; #[stable(feature = "unix_socket", since = "1.10.0")] diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index cd1aa01fa0f..2a5790e9d5c 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -1,13 +1,4 @@ -#[cfg(any( - doc, - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(doc, target_os = "android", target_os = "linux"))] use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary}; use super::{sockaddr_un, SocketAddr}; use crate::fmt; @@ -511,7 +502,8 @@ impl UnixStream { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData}; /// use std::io::IoSliceMut; @@ -541,15 +533,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn recv_vectored_with_ancillary( &self, @@ -567,7 +551,8 @@ impl UnixStream { /// /// # Examples /// - /// ```no_run + #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")] + #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")] /// #![feature(unix_socket_ancillary_data)] /// use std::os::unix::net::{UnixStream, SocketAncillary}; /// use std::io::IoSlice; @@ -591,15 +576,7 @@ impl UnixStream { /// Ok(()) /// } /// ``` - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(doc, target_os = "android", target_os = "linux"))] #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")] pub fn send_vectored_with_ancillary( &self, diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index c1f11c56b8f..e4499f9b6a6 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -1,24 +1,7 @@ use super::*; use crate::io::prelude::*; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(target_os = "android", target_os = "linux"))] use crate::os::unix::io::AsRawFd; use crate::sys_common::io::test::tmpdir; use crate::thread; @@ -618,15 +601,7 @@ fn test_unix_datagram_peek_from() { assert_eq!(msg, &buf[..]); } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] fn test_send_vectored_fds_unix_stream() { let (s1, s2) = or_panic!(UnixStream::pair()); @@ -664,7 +639,7 @@ fn test_send_vectored_fds_unix_stream() { } } -#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))] +#[cfg(any(target_os = "android", target_os = "linux",))] #[test] fn test_send_vectored_with_ancillary_to_unix_datagram() { fn getpid() -> libc::pid_t { @@ -731,15 +706,7 @@ fn test_send_vectored_with_ancillary_to_unix_datagram() { } } -#[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", -))] +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] fn test_send_vectored_with_ancillary_unix_datagram() { let dir = tmpdir(); diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 9bf9607a63e..a1bbc2d87b6 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -289,15 +289,7 @@ impl Socket { self.recv_from_with_flags(buf, 0) } - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(target_os = "android", target_os = "linux"))] pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> { let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) @@ -320,15 +312,7 @@ impl Socket { self.0.is_write_vectored() } - #[cfg(any( - target_os = "android", - target_os = "dragonfly", - target_os = "emscripten", - target_os = "freebsd", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - ))] + #[cfg(any(target_os = "android", target_os = "linux"))] pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> { let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?; Ok(n as usize) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 761bd66b505..b804cefd3fc 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -227,7 +227,7 @@ impl StepDescription { fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { if builder.config.exclude.iter().any(|e| pathset.has(&e.path, e.kind)) { - eprintln!("Skipping {:?} because it is excluded", pathset); + println!("Skipping {:?} because it is excluded", pathset); return true; } @@ -1232,7 +1232,12 @@ impl<'a> Builder<'a> { // HACK: because anyhow does feature detection in build.rs, we need to allow the backtrace feature too. rustflags.arg("-Zallow-features=binary-dep-depinfo,backtrace"); } - Mode::Std | Mode::Rustc | Mode::ToolStd | Mode::Codegen | Mode::ToolRustc => {} + Mode::ToolStd => { + // Right now this is just compiletest and a few other tools that build on stable. + // Allow them to use `feature(test)`, but nothing else. + rustflags.arg("-Zallow-features=binary-dep-depinfo,test,backtrace"); + } + Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {} } cargo.arg("-j").arg(self.jobs().to_string()); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0b430f64e1e..b35eba21e6b 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1164,14 +1164,11 @@ impl Step for Assemble { // for `-Z gcc-ld=lld` let gcc_ld_dir = libdir_bin.join("gcc-ld"); t!(fs::create_dir(&gcc_ld_dir)); - for flavor in ["ld", "ld64"] { - let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { - compiler: build_compiler, - target: target_compiler.host, - flavor_feature: flavor, - }); - builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(flavor, target_compiler.host))); - } + let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { + compiler: build_compiler, + target: target_compiler.host, + }); + builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host))); } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 843d276cd7a..b82c1505b24 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -765,7 +765,7 @@ impl Config { { Ok(table) => table, Err(err) => { - println!("failed to parse TOML configuration '{}': {}", file.display(), err); + eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err); process::exit(2); } } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0be11e3fb46..cc10d67c551 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -407,11 +407,8 @@ impl Step for Rustc { let gcc_lld_src_dir = src_dir.join("gcc-ld"); let gcc_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&gcc_lld_dst_dir)); - for flavor in ["ld", "ld64"] { - let exe_name = exe(flavor, compiler.host); - builder - .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); - } + let exe_name = exe("ld", compiler.host); + builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); } // Man pages diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 4cd835ade64..9827a6c590b 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -367,8 +367,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", } } if !pass_sanity_check { - println!("{}\n", subcommand_help); - println!( + eprintln!("{}\n", subcommand_help); + eprintln!( "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ You may need to move some options to after the subcommand.\n" ); @@ -532,7 +532,7 @@ Arguments: Kind::Build => Subcommand::Build { paths }, Kind::Check => { if matches.opt_present("all-targets") { - eprintln!( + println!( "Warning: --all-targets is now on by default and does not need to be passed explicitly." ); } @@ -606,7 +606,7 @@ Arguments: if matches.opt_str("keep-stage").is_some() || matches.opt_str("keep-stage-std").is_some() { - println!("--keep-stage not yet supported for x.py check"); + eprintln!("--keep-stage not yet supported for x.py check"); process::exit(1); } } diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 10b846e6db2..d1a450f1bff 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -96,7 +96,7 @@ pub fn format(build: &Build, check: bool, paths: &[PathBuf]) { entry.split(' ').nth(1).expect("every git status entry should list a path") }); for untracked_path in untracked_paths { - eprintln!("skip untracked path {} during rustfmt invocations", untracked_path); + println!("skip untracked path {} during rustfmt invocations", untracked_path); // The leading `/` makes it an exact match against the // repository root, rather than a glob. Without that, if you // have `foo.rs` in the repository root it will also match @@ -105,10 +105,10 @@ pub fn format(build: &Build, check: bool, paths: &[PathBuf]) { ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path); } } else { - eprintln!("Not in git tree. Skipping git-aware format checks"); + println!("Not in git tree. Skipping git-aware format checks"); } } else { - eprintln!("Could not find usable git. Skipping git-aware format checks"); + println!("Could not find usable git. Skipping git-aware format checks"); } let ignore_fmt = ignore_fmt.build().unwrap(); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 591f9a1ca50..0f0cf0762ab 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -689,9 +689,9 @@ impl Build { // Check for postponed failures from `test --no-fail-fast`. let failures = self.delayed_failures.borrow(); if failures.len() > 0 { - println!("\n{} command(s) did not execute successfully:\n", failures.len()); + eprintln!("\n{} command(s) did not execute successfully:\n", failures.len()); for failure in failures.iter() { - println!(" - {}\n", failure); + eprintln!(" - {}\n", failure); } process::exit(1); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 09b8cbe9014..7bfcfcdef2c 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -138,10 +138,10 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) { let llvm_sha = llvm_sha.trim(); if llvm_sha == "" { - println!("error: could not find commit hash for downloading LLVM"); - println!("help: maybe your repository history is too shallow?"); - println!("help: consider disabling `download-ci-llvm`"); - println!("help: or fetch enough history to include one upstream commit"); + eprintln!("error: could not find commit hash for downloading LLVM"); + eprintln!("help: maybe your repository history is too shallow?"); + eprintln!("help: consider disabling `download-ci-llvm`"); + eprintln!("help: or fetch enough history to include one upstream commit"); panic!(); } diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index b730730854f..82f55440ce5 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -85,12 +85,12 @@ pub fn setup(config: &Config, profile: Profile) { let path = &config.config; if path.exists() { - println!( + eprintln!( "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", path.display() ); - println!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display()); - println!( + eprintln!("help: try adding `profile = \"{}\"` at the top of {}", profile, path.display()); + eprintln!( "note: this will use the configuration in {}", profile.include_path(&config.src).display() ); @@ -115,7 +115,7 @@ pub fn setup(config: &Config, profile: Profile) { println!(); if !rustup_installed() && profile != Profile::User { - println!("`rustup` is not installed; cannot link `stage1` toolchain"); + eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); } else if stage_dir_exists(&stage_path[..]) { attempt_toolchain_link(&stage_path[..]); } @@ -173,7 +173,7 @@ fn attempt_toolchain_link(stage_path: &str) { } if !ensure_stage1_toolchain_placeholder_exists(stage_path) { - println!( + eprintln!( "Failed to create a template for stage 1 toolchain or confirm that it already exists" ); return; @@ -184,8 +184,8 @@ fn attempt_toolchain_link(stage_path: &str) { "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); } else { - println!("`rustup` failed to link stage 1 build to `stage1` toolchain"); - println!( + eprintln!("`rustup` failed to link stage 1 build to `stage1` toolchain"); + eprintln!( "To manually link stage 1 build to `stage1` toolchain, run:\n `rustup toolchain link stage1 {}`", &stage_path @@ -292,8 +292,8 @@ pub fn interactive_path() -> io::Result<Profile> { break match parse_with_abbrev(&input) { Ok(profile) => profile, Err(err) => { - println!("error: {}", err); - println!("note: press Ctrl+C to exit"); + eprintln!("error: {}", err); + eprintln!("note: press Ctrl+C to exit"); continue; } }; @@ -320,8 +320,8 @@ undesirable, simply delete the `pre-push` file from .git/hooks." "y" | "yes" => true, "n" | "no" | "" => false, _ => { - println!("error: unrecognized option '{}'", input.trim()); - println!("note: press Ctrl+C to exit"); + eprintln!("error: unrecognized option '{}'", input.trim()); + eprintln!("note: press Ctrl+C to exit"); continue; } }; @@ -337,7 +337,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." )); let dst = git.join("hooks").join("pre-push"); match fs::hard_link(src, &dst) { - Err(e) => println!( + Err(e) => eprintln!( "error: could not create hook {}: do you already have the git hook installed?\n{}", dst.display(), e diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 3b30e6de12a..f39cbb57b82 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -152,43 +152,43 @@ impl Step for ToolBuild { }); if is_expected && !duplicates.is_empty() { - println!( + eprintln!( "duplicate artifacts found when compiling a tool, this \ typically means that something was recompiled because \ a transitive dependency has different features activated \ than in a previous build:\n" ); - println!( + eprintln!( "the following dependencies are duplicated although they \ have the same features enabled:" ); let (same, different): (Vec<_>, Vec<_>) = duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2); for (id, cur, prev) in same { - println!(" {}", id); + eprintln!(" {}", id); // same features - println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); + eprintln!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); } - println!("the following dependencies have different features:"); + eprintln!("the following dependencies have different features:"); for (id, cur, prev) in different { - println!(" {}", id); + eprintln!(" {}", id); let cur_features: HashSet<_> = cur.2.into_iter().collect(); let prev_features: HashSet<_> = prev.2.into_iter().collect(); - println!( + eprintln!( " `{}` additionally enabled features {:?} at {:?}", cur.0, &cur_features - &prev_features, cur.1 ); - println!( + eprintln!( " `{}` additionally enabled features {:?} at {:?}", prev.0, &prev_features - &cur_features, prev.1 ); } - println!(); - println!( + eprintln!(); + eprintln!( "to fix this you will probably want to edit the local \ src/tools/rustc-workspace-hack/Cargo.toml crate, as \ that will update the dependency graph to ensure that \ @@ -656,7 +656,6 @@ impl Step for Cargo { pub struct LldWrapper { pub compiler: Compiler, pub target: TargetSelection, - pub flavor_feature: &'static str, } impl Step for LldWrapper { @@ -676,7 +675,7 @@ impl Step for LldWrapper { path: "src/tools/lld-wrapper", is_optional_tool: false, source_type: SourceType::InTree, - extra_features: vec![self.flavor_feature.to_owned()], + extra_features: Vec::new(), }) .expect("expected to build -- essential tool"); diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 710b3588b84..848d9a7dc92 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -455,7 +455,7 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { } fn fail(s: &str) -> ! { - println!("\n\n{}\n\n", s); + eprintln!("\n\n{}\n\n", s); std::process::exit(1); } diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index b3ec1638fda..03834411d15 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.9.3 \ No newline at end of file +0.9.5 \ No newline at end of file diff --git a/src/doc/book b/src/doc/book -Subproject d9415b7cbfcb4b24062683f429bd0ff53539636 +Subproject b4dd5f00b87190ad5ef42cbc2a88a783c6ae57e diff --git a/src/doc/reference b/src/doc/reference -Subproject 8e36971959ff238b5aa2575fbc7a2e09e1313e8 +Subproject b74825d8f88b685e239ade00f00de68ba4cd63d diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject e9f93cfcf410bc092c9107b8a41a82f144c761f +Subproject 2ed26865e8c29ef939dc913a97bd321cadd72a9 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 0c02acdb6f48f03907a02ea8e537c3272b4fde9 +Subproject 554c00e4805df7f7bffac7db408437d62d6dfb9 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e10c61901d0..99b4eacedc2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -525,7 +525,7 @@ impl Item { if let Ok((mut href, ..)) = href(*did, cx) { debug!(?href); if let Some(ref fragment) = *fragment { - fragment.render(&mut href, cx.tcx()).unwrap() + fragment.render(&mut href, cx.tcx()) } Some(RenderedLink { original_text: s.clone(), diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a4ec4052e05..86c58cd79dc 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -795,7 +795,9 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) { // If not, then we append the new line into the pending attribute to check // if this time it's complete... mod_attr_pending.push_str(line); - if !trimline.is_empty() && check_if_attr_is_complete(line, edition) { + if !trimline.is_empty() + && check_if_attr_is_complete(&mod_attr_pending, edition) + { // If it's complete, then we can clear the pending content. mod_attr_pending.clear(); } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index da4273345cb..c5dbf8aa754 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -55,9 +55,9 @@ pub(crate) struct Context<'tcx> { pub(super) render_redirect_pages: bool, /// Tracks section IDs for `Deref` targets so they match in both the main /// body and the sidebar. - pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>, + pub(super) deref_id_map: FxHashMap<DefId, String>, /// The map used to ensure all generated 'id=' attributes are unique. - pub(super) id_map: RefCell<IdMap>, + pub(super) id_map: IdMap, /// Shared mutable state. /// /// Issue for improving the situation: [#82381][] @@ -72,7 +72,7 @@ pub(crate) struct Context<'tcx> { // `Context` is cloned a lot, so we don't want the size to grow unexpectedly. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Context<'_>, 144); +rustc_data_structures::static_assert_size!(Context<'_>, 128); /// Shared mutable state used in [`Context`] and elsewhere. pub(crate) struct SharedContext<'tcx> { @@ -155,9 +155,8 @@ impl<'tcx> Context<'tcx> { self.shared.tcx.sess } - pub(super) fn derive_id(&self, id: String) -> String { - let mut map = self.id_map.borrow_mut(); - map.derive(id) + pub(super) fn derive_id(&mut self, id: String) -> String { + self.id_map.derive(id) } /// String representation of how to get back to the root path of the 'doc/' @@ -166,7 +165,7 @@ impl<'tcx> Context<'tcx> { "../".repeat(self.current.len()) } - fn render_item(&self, it: &clean::Item, is_module: bool) -> String { + fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String { let mut title = String::new(); if !is_module { title.push_str(it.name.unwrap().as_str()); @@ -203,23 +202,26 @@ impl<'tcx> Context<'tcx> { }; if !self.render_redirect_pages { + let clone_shared = Rc::clone(&self.shared); let page = layout::Page { css_class: tyname_s, root_path: &self.root_path(), - static_root_path: self.shared.static_root_path.as_deref(), + static_root_path: clone_shared.static_root_path.as_deref(), title: &title, description: &desc, keywords: &keywords, - resource_suffix: &self.shared.resource_suffix, + resource_suffix: &clone_shared.resource_suffix, extra_scripts: &[], static_extra_scripts: &[], }; + let mut page_buffer = Buffer::html(); + print_item(self, it, &mut page_buffer, &page); layout::render( - &self.shared.layout, + &clone_shared.layout, &page, |buf: &mut _| print_sidebar(self, it, buf), - |buf: &mut _| print_item(self, it, buf, &page), - &self.shared.style_files, + move |buf: &mut Buffer| buf.push_buffer(page_buffer), + &clone_shared.style_files, ) } else { if let Some(&(ref names, ty)) = self.cache().paths.get(&it.item_id.expect_def_id()) { @@ -512,8 +514,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { current: Vec::new(), dst, render_redirect_pages: false, - id_map: RefCell::new(id_map), - deref_id_map: RefCell::new(FxHashMap::default()), + id_map, + deref_id_map: FxHashMap::default(), shared: Rc::new(scx), include_sources, }; @@ -528,7 +530,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // Write shared runs within a flock; disable thread dispatching of IO temporarily. Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); - write_shared(&cx, &krate, index, &md_opts)?; + write_shared(&mut cx, &krate, index, &md_opts)?; Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); } @@ -540,8 +542,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { current: self.current.clone(), dst: self.dst.clone(), render_redirect_pages: self.render_redirect_pages, - deref_id_map: RefCell::new(FxHashMap::default()), - id_map: RefCell::new(IdMap::new()), + deref_id_map: FxHashMap::default(), + id_map: IdMap::new(), shared: Rc::clone(&self.shared), include_sources: self.include_sources, } @@ -557,31 +559,32 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if !root_path.ends_with('/') { root_path.push('/'); } + let shared = Rc::clone(&self.shared); let mut page = layout::Page { title: "List of all items in this crate", css_class: "mod", root_path: "../", - static_root_path: self.shared.static_root_path.as_deref(), + static_root_path: shared.static_root_path.as_deref(), description: "List of all items in this crate", keywords: BASIC_KEYWORDS, - resource_suffix: &self.shared.resource_suffix, + resource_suffix: &shared.resource_suffix, extra_scripts: &[], static_extra_scripts: &[], }; - let sidebar = if self.shared.cache.crate_version.is_some() { + let sidebar = if shared.cache.crate_version.is_some() { format!("<h2 class=\"location\">Crate {}</h2>", crate_name) } else { String::new() }; - let all = self.shared.all.replace(AllTypes::new()); + let all = shared.all.replace(AllTypes::new()); let v = layout::render( - &self.shared.layout, + &shared.layout, &page, sidebar, |buf: &mut Buffer| all.print(buf), - &self.shared.style_files, + &shared.style_files, ); - self.shared.fs.write(final_file, v)?; + shared.fs.write(final_file, v)?; // Generating settings page. page.title = "Rustdoc settings"; @@ -590,7 +593,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>"; let v = layout::render( - &self.shared.layout, + &shared.layout, &page, sidebar, |buf: &mut Buffer| { @@ -613,33 +616,36 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { suffix = page.resource_suffix, ) }, - &self.shared.style_files, + &shared.style_files, ); - self.shared.fs.write(settings_file, v)?; + shared.fs.write(settings_file, v)?; - if self.shared.layout.scrape_examples_extension { + if shared.layout.scrape_examples_extension { page.title = "About scraped examples"; page.description = "How the scraped examples feature works in Rustdoc"; let v = layout::render( - &self.shared.layout, + &shared.layout, &page, "", - scrape_examples_help(&*self.shared), - &self.shared.style_files, + scrape_examples_help(&*shared), + &shared.style_files, ); - self.shared.fs.write(scrape_examples_help_file, v)?; + shared.fs.write(scrape_examples_help_file, v)?; } - if let Some(ref redirections) = self.shared.redirections { + if let Some(ref redirections) = shared.redirections { if !redirections.borrow().is_empty() { let redirect_map_path = self.dst.join(crate_name.as_str()).join("redirect-map.json"); let paths = serde_json::to_string(&*redirections.borrow()).unwrap(); - self.shared.ensure_dir(&self.dst.join(crate_name.as_str()))?; - self.shared.fs.write(redirect_map_path, paths)?; + shared.ensure_dir(&self.dst.join(crate_name.as_str()))?; + shared.fs.write(redirect_map_path, paths)?; } } + // No need for it anymore. + drop(shared); + // Flush pending errors. Rc::get_mut(&mut self.shared).unwrap().fs.close(); let nb_errors = @@ -662,7 +668,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if !self.render_redirect_pages { self.render_redirect_pages = item.is_stripped(); } - let scx = &self.shared; let item_name = item.name.unwrap(); self.dst.push(&*item_name.as_str()); self.current.push(item_name); @@ -674,7 +679,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if !buf.is_empty() { self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join("index.html"); - scx.fs.write(joint_dst, buf)?; + self.shared.fs.write(joint_dst, buf)?; } // Render sidebar-items.js used throughout this module. @@ -684,7 +689,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let items = self.build_sidebar_items(module); let js_dst = self.dst.join(&format!("sidebar-items{}.js", self.shared.resource_suffix)); let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap()); - scx.fs.write(js_dst, v)?; + self.shared.fs.write(js_dst, v)?; } Ok(()) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3809738cc33..eefb2c2358f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -42,6 +42,7 @@ use std::fmt; use std::fs; use std::iter::Peekable; use std::path::PathBuf; +use std::rc::Rc; use std::str; use std::string::ToString; @@ -364,7 +365,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { fn document( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, item: &clean::Item, parent: Option<&clean::Item>, heading_offset: HeadingOffset, @@ -383,19 +384,18 @@ fn document( /// Render md_text as markdown. fn render_markdown( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, md_text: &str, links: Vec<RenderedLink>, heading_offset: HeadingOffset, ) { - let mut ids = cx.id_map.borrow_mut(); write!( w, "<div class=\"docblock\">{}</div>", Markdown { content: md_text, links: &links, - ids: &mut ids, + ids: &mut cx.id_map, error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, @@ -410,7 +410,7 @@ fn render_markdown( fn document_short( w: &mut Buffer, item: &clean::Item, - cx: &Context<'_>, + cx: &mut Context<'_>, link: AssocItemLink<'_>, parent: &clean::Item, show_def_docs: bool, @@ -439,7 +439,7 @@ fn document_short( fn document_full_collapsible( w: &mut Buffer, item: &clean::Item, - cx: &Context<'_>, + cx: &mut Context<'_>, heading_offset: HeadingOffset, ) { document_full_inner(w, item, cx, true, heading_offset); @@ -448,7 +448,7 @@ fn document_full_collapsible( fn document_full( w: &mut Buffer, item: &clean::Item, - cx: &Context<'_>, + cx: &mut Context<'_>, heading_offset: HeadingOffset, ) { document_full_inner(w, item, cx, false, heading_offset); @@ -457,7 +457,7 @@ fn document_full( fn document_full_inner( w: &mut Buffer, item: &clean::Item, - cx: &Context<'_>, + cx: &mut Context<'_>, is_collapsible: bool, heading_offset: HeadingOffset, ) { @@ -493,7 +493,7 @@ fn document_full_inner( /// * Required features (through the `doc_cfg` feature) fn document_item_info( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, item: &clean::Item, parent: Option<&clean::Item>, ) { @@ -522,7 +522,7 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin /// the item's documentation. fn short_item_info( item: &clean::Item, - cx: &Context<'_>, + cx: &mut Context<'_>, parent: Option<&clean::Item>, ) -> Vec<String> { let mut extra_info = vec![]; @@ -550,10 +550,9 @@ fn short_item_info( if let Some(note) = note { let note = note.as_str(); - let mut ids = cx.id_map.borrow_mut(); let html = MarkdownHtml( note, - &mut ids, + &mut cx.id_map, error_codes, cx.shared.edition(), &cx.shared.playground, @@ -601,7 +600,7 @@ fn short_item_info( // Render the list of items inside one of the sections "Trait Implementations", // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages). fn render_impls( - cx: &Context<'_>, + cx: &mut Context<'_>, w: &mut Buffer, impls: &[&&Impl], containing_item: &clean::Item, @@ -994,7 +993,7 @@ impl<'a> AssocItemLink<'a> { fn render_assoc_items( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, containing_item: &clean::Item, it: DefId, what: AssocItemRender<'_>, @@ -1006,14 +1005,15 @@ fn render_assoc_items( fn render_assoc_items_inner( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, containing_item: &clean::Item, it: DefId, what: AssocItemRender<'_>, derefs: &mut FxHashSet<DefId>, ) { info!("Documenting associated items of {:?}", containing_item.name); - let cache = cx.cache(); + let shared = Rc::clone(&cx.shared); + let cache = &shared.cache; let Some(v) = cache.impls.get(&it) else { return }; let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); if !non_trait.is_empty() { @@ -1032,7 +1032,7 @@ fn render_assoc_items_inner( let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); if let Some(def_id) = type_.def_id(cx.cache()) { - cx.deref_id_map.borrow_mut().insert(def_id, id.clone()); + cx.deref_id_map.insert(def_id, id.clone()); } write!( tmp_buf, @@ -1138,7 +1138,7 @@ fn render_assoc_items_inner( fn render_deref_methods( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, impl_: &Impl, container_item: &clean::Item, deref_mut: bool, @@ -1285,7 +1285,7 @@ struct ImplRenderingParameters { fn render_impl( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, i: &Impl, parent: &clean::Item, link: AssocItemLink<'_>, @@ -1294,7 +1294,8 @@ fn render_impl( aliases: &[String], rendering_params: ImplRenderingParameters, ) { - let cache = cx.cache(); + let shared = Rc::clone(&cx.shared); + let cache = &shared.cache; let traits = &cache.traits; let trait_ = i.trait_did().map(|did| &traits[&did]); let mut close_tags = String::new(); @@ -1307,7 +1308,7 @@ fn render_impl( fn doc_impl_item( boring: &mut Buffer, interesting: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, item: &clean::Item, parent: &clean::Item, containing_item: &clean::Item, @@ -1520,7 +1521,7 @@ fn render_impl( fn render_default_items( boring: &mut Buffer, interesting: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, t: &clean::Trait, i: &clean::Impl, parent: &clean::Item, @@ -1599,14 +1600,13 @@ fn render_impl( } if let Some(ref dox) = i.impl_item.collapsed_doc_value() { - let mut ids = cx.id_map.borrow_mut(); write!( w, "<div class=\"docblock\">{}</div>", Markdown { content: &*dox, links: &i.impl_item.links(cx), - ids: &mut ids, + ids: &mut cx.id_map, error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, @@ -1664,7 +1664,7 @@ fn render_rightside( pub(crate) fn render_impl_summary( w: &mut Buffer, - cx: &Context<'_>, + cx: &mut Context<'_>, i: &Impl, parent: &clean::Item, containing_item: &clean::Item, @@ -2092,10 +2092,8 @@ fn sidebar_deref_methods( }) .collect::<Vec<_>>(); if !ret.is_empty() { - let map; let id = if let Some(target_def_id) = real_target.def_id(c) { - map = cx.deref_id_map.borrow(); - map.get(&target_def_id).expect("Deref section without derived id") + cx.deref_id_map.get(&target_def_id).expect("Deref section without derived id") } else { "deref-methods" }; @@ -2641,14 +2639,14 @@ const MAX_FULL_EXAMPLES: usize = 5; const NUM_VISIBLE_LINES: usize = 10; /// Generates the HTML for example call locations generated via the --scrape-examples flag. -fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) { +fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item) { let tcx = cx.tcx(); let def_id = item.item_id.expect_def_id(); let key = tcx.def_path_hash(def_id); let Some(call_locations) = cx.shared.call_locations.get(&key) else { return }; // Generate a unique ID so users can link to this section for a given method - let id = cx.id_map.borrow_mut().derive("scraped-examples"); + let id = cx.id_map.derive("scraped-examples"); write!( w, "<div class=\"docblock scraped-example-list\">\ diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index ed41b95e73f..dcf36b5e865 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2,6 +2,7 @@ use clean::AttributesExt; use std::cmp::Ordering; use std::fmt; +use std::rc::Rc; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -60,7 +61,12 @@ struct ItemVars<'a> { src_href: Option<&'a str>, } -pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>) { +pub(super) fn print_item( + cx: &mut Context<'_>, + item: &clean::Item, + buf: &mut Buffer, + page: &Page<'_>, +) { debug_assert!(!item.is_stripped()); let typ = match *item.kind { clean::ModuleItem(_) => { @@ -187,7 +193,7 @@ fn toggle_close(w: &mut Buffer) { w.write_str("</details>"); } -fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { +fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) { document(w, cx, item, None, HeadingOffset::H2); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>(); @@ -344,6 +350,12 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let add = if stab.is_some() { " " } else { "" }; w.write_str(ITEM_TABLE_ROW_OPEN); + let id = match import.kind { + clean::ImportKind::Simple(s) => { + format!(" id=\"{}\"", cx.derive_id(format!("reexport.{}", s))) + } + clean::ImportKind::Glob => String::new(), + }; write!( w, "<div class=\"item-left {stab}{add}import-item\"{id}>\ @@ -351,15 +363,9 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl </div>\ <div class=\"item-right docblock-short\">{stab_tags}</div>", stab = stab.unwrap_or_default(), - add = add, vis = myitem.visibility.print_with_space(myitem.item_id, cx), imp = import.print(cx), stab_tags = stab_tags.unwrap_or_default(), - id = match import.kind { - clean::ImportKind::Simple(s) => - format!(" id=\"{}\"", cx.derive_id(format!("reexport.{}", s))), - clean::ImportKind::Glob => String::new(), - }, ); w.write_str(ITEM_TABLE_ROW_CLOSE); } @@ -464,7 +470,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> tags } -fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { +fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { let header = it.fn_header(cx.tcx()).expect("printing a function which isn't a function"); let constness = print_constness_with_space(&header.constness, it.const_stability(cx.tcx())); let unsafety = header.unsafety.print_with_space(); @@ -507,7 +513,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: document(w, cx, it, None, HeadingOffset::H2) } -fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { +fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) { let bounds = bounds(&t.bounds, false, cx); let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>(); let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); @@ -674,7 +680,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ) } - fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) { + fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::Item) { let name = m.name.unwrap(); info!("Documenting {} on {:?}", name, t.name); let item_type = m.type_(); @@ -791,14 +797,15 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra // If there are methods directly on this trait object, render them here. render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All); - let cache = cx.cache(); + let cloned_shared = Rc::clone(&cx.shared); + let cache = &cloned_shared.cache; let mut extern_crates = FxHashSet::default(); if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default(); for implementor in implementors { - if let Some(did) = implementor.inner_impl().for_.without_borrowed_ref().def_id(cx.cache()) && + if let Some(did) = implementor.inner_impl().for_.without_borrowed_ref().def_id(cache) && !did.is_local() { extern_crates.insert(did.krate); } @@ -996,7 +1003,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ); } -fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias) { +fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) { wrap_into_docblock(w, |w| { wrap_item(w, "trait-alias", |w| { render_attributes_in_pre(w, it, ""); @@ -1020,7 +1027,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) } -fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) { +fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) { wrap_into_docblock(w, |w| { wrap_item(w, "opaque", |w| { render_attributes_in_pre(w, it, ""); @@ -1044,7 +1051,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean: render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) } -fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { +fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) { fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { wrap_item(w, "typedef", |w| { render_attributes_in_pre(w, it, ""); @@ -1073,7 +1080,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T document_type_layout(w, cx, def_id); } -fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) { +fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { wrap_into_docblock(w, |w| { wrap_item(w, "union", |w| { render_attributes_in_pre(w, it, ""); @@ -1135,7 +1142,7 @@ fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item] } } -fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) { +fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let count_variants = e.variants().count(); wrap_into_docblock(w, |w| { wrap_item(w, "enum", |w| { @@ -1283,7 +1290,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum document_type_layout(w, cx, def_id); } -fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) { +fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { highlight::render_with_highlighting( &t.source, @@ -1300,7 +1307,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac document(w, cx, it, None, HeadingOffset::H2) } -fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { +fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { wrap_into_docblock(w, |w| { let name = it.name.expect("proc-macros always have names"); match m.kind { @@ -1332,12 +1339,12 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean document(w, cx, it, None, HeadingOffset::H2) } -fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { +fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) } -fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) { +fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_into_docblock(w, |w| { wrap_item(w, "const", |w| { render_attributes_in_code(w, it); @@ -1377,7 +1384,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: document(w, cx, it, None, HeadingOffset::H2) } -fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { +fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_into_docblock(w, |w| { wrap_item(w, "struct", |w| { render_attributes_in_code(w, it); @@ -1430,7 +1437,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St document_type_layout(w, cx, def_id); } -fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) { +fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_into_docblock(w, |w| { wrap_item(w, "static", |w| { render_attributes_in_code(w, it); @@ -1447,7 +1454,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St document(w, cx, it, None, HeadingOffset::H2) } -fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { +fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { wrap_into_docblock(w, |w| { wrap_item(w, "foreigntype", |w| { w.write_str("extern {\n"); @@ -1466,7 +1473,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All) } -fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { +fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { document(w, cx, it, None, HeadingOffset::H2) } @@ -1579,7 +1586,7 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> O } fn render_implementor( - cx: &Context<'_>, + cx: &mut Context<'_>, implementor: &Impl, trait_: &clean::Item, w: &mut Buffer, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index ece659284d1..325d3a31434 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -5,6 +5,7 @@ use std::io::prelude::*; use std::io::{self, BufReader}; use std::lazy::SyncLazy as Lazy; use std::path::{Component, Path, PathBuf}; +use std::rc::Rc; use itertools::Itertools; use rustc_data_structures::flock; @@ -135,7 +136,7 @@ impl Context<'_> { } pub(super) fn write_shared( - cx: &Context<'_>, + cx: &mut Context<'_>, krate: &Crate, search_index: String, options: &RenderOptions, @@ -462,15 +463,16 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; crate::markdown::render(&index_page, md_opts, cx.shared.edition()) .map_err(|e| Error::new(e, &index_page))?; } else { + let shared = Rc::clone(&cx.shared); let dst = cx.dst.join("index.html"); let page = layout::Page { title: "Index of crates", css_class: "mod", root_path: "./", - static_root_path: cx.shared.static_root_path.as_deref(), + static_root_path: shared.static_root_path.as_deref(), description: "List of crates", keywords: BASIC_KEYWORDS, - resource_suffix: &cx.shared.resource_suffix, + resource_suffix: &shared.resource_suffix, extra_scripts: &[], static_extra_scripts: &[], }; @@ -490,8 +492,8 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; }) .collect::<String>() ); - let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.style_files); - cx.shared.fs.write(dst, v)?; + let v = layout::render(&shared.layout, &page, "", content, &shared.style_files); + shared.fs.write(dst, v)?; } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 0bbdc37ea89..524c90e1f4d 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -6,15 +6,18 @@ use crate::html::highlight; use crate::html::layout; use crate::html::render::{Context, BASIC_KEYWORDS}; use crate::visit::DocVisitor; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; + use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; +use std::rc::Rc; pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> { info!("emitting source files"); @@ -174,15 +177,16 @@ impl SourceCollector<'_, '_> { // Remove the utf-8 BOM if any let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents); + let shared = Rc::clone(&self.cx.shared); // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = String::from("../../"); - clean_path(&self.cx.shared.src_root, &p, false, |component| { + clean_path(&shared.src_root, &p, false, |component| { cur.push(component); root_path.push_str("../"); }); - self.cx.shared.ensure_dir(&cur)?; + shared.ensure_dir(&cur)?; let src_fname = p.file_name().expect("source has no filename").to_os_string(); let mut fname = src_fname.clone(); @@ -195,32 +199,33 @@ impl SourceCollector<'_, '_> { title: &title, css_class: "source", root_path: &root_path, - static_root_path: self.cx.shared.static_root_path.as_deref(), + static_root_path: shared.static_root_path.as_deref(), description: &desc, keywords: BASIC_KEYWORDS, - resource_suffix: &self.cx.shared.resource_suffix, - extra_scripts: &[&format!("source-files{}", self.cx.shared.resource_suffix)], - static_extra_scripts: &[&format!("source-script{}", self.cx.shared.resource_suffix)], + resource_suffix: &shared.resource_suffix, + extra_scripts: &[&format!("source-files{}", shared.resource_suffix)], + static_extra_scripts: &[&format!("source-script{}", shared.resource_suffix)], }; let v = layout::render( - &self.cx.shared.layout, + &shared.layout, &page, "", |buf: &mut _| { + let cx = &mut self.cx; print_src( buf, contents, - self.cx.shared.edition(), + cx.shared.edition(), file_span, - self.cx, + cx, &root_path, None, SourceContext::Standalone, ) }, - &self.cx.shared.style_files, + &shared.style_files, ); - self.cx.shared.fs.write(cur, v)?; + shared.fs.write(cur, v)?; self.emitted_local_sources.insert(p); Ok(()) } diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index bf962303b3a..997def1657f 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -47,5 +47,21 @@ module.exports = { { "beforeColon": false, "afterColon": true, "mode": "strict" } ], "func-call-spacing": ["error", "never"], + "space-infix-ops": "error", + "space-before-function-paren": ["error", "never"], + "space-before-blocks": "error", + "comma-dangle": ["error", "always-multiline"], + "comma-style": ["error", "last"], + "max-len": ["error", { "code": 100, "tabWidth": 4 }], + "eol-last": ["error", "always"], + "arrow-parens": ["error", "as-needed"], + "no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "eqeqeq": "error", } }; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4eb8029ee2d..d0229bdb5f2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1415,30 +1415,6 @@ pre.rust { #settings-menu.rotate > a img { animation: rotating 2s linear infinite; } -#settings-menu #settings { - position: absolute; - right: 0; - z-index: 1; - display: block; - margin-top: 7px; - border-radius: 3px; - border: 1px solid; -} -#settings-menu #settings .setting-line { - margin: 0.6em; -} -/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ -#settings-menu #settings::before { - content: ''; - position: absolute; - right: 11px; - border: solid; - border-width: 1px 1px 0 0; - display: inline-block; - padding: 4px; - transform: rotate(-45deg); - top: -5px; -} #help-button { font-family: "Fira Sans", Arial, sans-serif; diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css index 07588748ad6..c69ff04236d 100644 --- a/src/librustdoc/html/static/css/settings.css +++ b/src/librustdoc/html/static/css/settings.css @@ -46,9 +46,12 @@ .toggle { position: relative; display: inline-block; - width: 45px; + width: 100%; height: 27px; margin-right: 20px; + display: flex; + align-items: center; + cursor: pointer; } .toggle input { @@ -57,12 +60,12 @@ } .slider { - position: absolute; + position: relative; + width: 45px; + display: block; + height: 28px; + margin-right: 20px; cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; background-color: #ccc; transition: .3s; } @@ -95,3 +98,28 @@ input:checked + .slider:before { width: 100%; display: block; } + +div#settings { + position: absolute; + right: 0; + z-index: 1; + display: block; + margin-top: 7px; + border-radius: 3px; + border: 1px solid; +} +#settings .setting-line { + margin: 1.2em 0.6em; +} +/* This rule is to draw the little arrow connecting the settings menu to the gear icon. */ +div#settings::before { + content: ''; + position: absolute; + right: 11px; + border: solid; + border-width: 1px 1px 0 0; + display: inline-block; + padding: 4px; + transform: rotate(-45deg); + top: -5px; +} diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 454c7f557b9..548aeedd033 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -63,7 +63,7 @@ function showMain() { removeClass(document.getElementById(MAIN_ID), "hidden"); } -(function () { +(function() { window.rootPath = getVar("root-path"); window.currentCrate = getVar("current-crate"); window.searchJS = resourcePath("search", ".js"); @@ -97,12 +97,12 @@ function showMain() { // // So I guess you could say things are getting pretty interoperable. function getVirtualKey(ev) { - if ("key" in ev && typeof ev.key != "undefined") { + if ("key" in ev && typeof ev.key !== "undefined") { return ev.key; } const c = ev.charCode || ev.keyCode; - if (c == 27) { + if (c === 27) { return "Escape"; } return String.fromCharCode(c); @@ -929,7 +929,7 @@ function loadCss(cssFileName) { searchState.setup(); }()); -(function () { +(function() { let reset_button_timeout = null; window.copy_path = but => { diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index 7b9d86a851b..fd7a1449763 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -2,7 +2,7 @@ "use strict"; -(function () { +(function() { // Number of lines shown when code viewer is not expanded const MAX_LINES = 10; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index c784d69dcd6..c726aeeff47 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -70,7 +70,7 @@ function printTab(nb) { }); if (foundCurrentTab && foundCurrentResultSet) { searchState.currentTab = nb; - } else if (nb != 0) { + } else if (nb !== 0) { printTab(0); } } @@ -200,7 +200,7 @@ function initSearch(rawSearchIndex) { * @return {boolean} */ function isPathStart(parserState) { - return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "::"; + return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) === "::"; } /** @@ -211,7 +211,7 @@ function initSearch(rawSearchIndex) { * @return {boolean} */ function isReturnArrow(parserState) { - return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "->"; + return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) === "->"; } /** @@ -1726,7 +1726,7 @@ function initSearch(rawSearchIndex) { crates = " in <select id=\"crate-search\"><option value=\"All crates\">" + "All crates</option>"; for (const c of window.ALL_CRATES) { - crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`; + crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`; } crates += "</select>"; } diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 8770cc3f3b1..3d1d942eaa9 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -5,7 +5,7 @@ "use strict"; -(function () { +(function() { const isSettingsPage = window.location.pathname.endsWith("/settings.html"); function changeSetting(settingName, value) { @@ -130,12 +130,11 @@ } else { // This is a toggle. const checked = setting["default"] === true ? " checked" : ""; - output += ` - <label class="toggle"> - <input type="checkbox" id="${js_data_name}"${checked}> - <span class="slider"></span> - </label> - <div>${setting_name}</div>`; + output += `<label class="toggle">\ + <input type="checkbox" id="${js_data_name}"${checked}>\ + <span class="slider"></span>\ + <span class="label">${setting_name}</span>\ + </label>`; } output += "</div>"; } diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index 15e3bdf47b2..aaac878d3a3 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -187,7 +187,7 @@ function highlightSourceLines(match) { } } -const handleSourceHighlight = (function () { +const handleSourceHighlight = (function() { let prev_line_id = 0; const set_fragment = name => { diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 3fcf66a817e..4fcf0499234 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -4,7 +4,7 @@ const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); window.mainTheme = document.getElementById("mainThemeStyle"); -const settingsDataset = (function () { +const settingsDataset = (function() { const settingsElement = document.getElementById("default-settings"); if (settingsElement === null) { return null; @@ -163,7 +163,7 @@ function useSystemTheme(value) { } } -const updateSystemTheme = (function () { +const updateSystemTheme = (function() { if (!window.matchMedia) { // fallback to the CSS computed value return () => { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 61acf2de90d..8b3edfd2135 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -70,9 +70,7 @@ extern crate test; // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs // about jemalloc. #[cfg(feature = "jemalloc")] -extern crate tikv_jemalloc_sys; -#[cfg(feature = "jemalloc")] -use tikv_jemalloc_sys as jemalloc_sys; +extern crate jemalloc_sys; use std::default::Default; use std::env::{self, VarError}; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ab57005abc4..83d8fe9ef11 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -20,7 +20,6 @@ use rustc_span::BytePos; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; -use std::fmt::Write; use std::mem; use std::ops::Range; @@ -220,80 +219,43 @@ enum MalformedGenerics { #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub(crate) enum UrlFragment { - Item(ItemFragment), + Item(DefId), UserWritten(String), } impl UrlFragment { /// Render the fragment, including the leading `#`. - pub(crate) fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result { + pub(crate) fn render(&self, s: &mut String, tcx: TyCtxt<'_>) { + s.push('#'); match self { - UrlFragment::Item(frag) => frag.render(s, tcx), - UrlFragment::UserWritten(raw) => write!(s, "#{}", raw), - } - } -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub(crate) struct ItemFragment(FragmentKind, DefId); - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub(crate) enum FragmentKind { - Method, - TyMethod, - AssociatedConstant, - AssociatedType, - - StructField, - Variant, - VariantField, -} - -impl FragmentKind { - fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> FragmentKind { - match tcx.def_kind(def_id) { - DefKind::AssocFn => { - if tcx.associated_item(def_id).defaultness.has_value() { - FragmentKind::Method - } else { - FragmentKind::TyMethod - } - } - DefKind::AssocConst => FragmentKind::AssociatedConstant, - DefKind::AssocTy => FragmentKind::AssociatedType, - DefKind::Variant => FragmentKind::Variant, - DefKind::Field => { - if tcx.def_kind(tcx.parent(def_id)) == DefKind::Variant { - FragmentKind::VariantField - } else { - FragmentKind::StructField - } - } - kind => bug!("unexpected associated item kind: {:?}", kind), - } - } -} - -impl ItemFragment { - /// Render the fragment, including the leading `#`. - pub(crate) fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result { - write!(s, "#")?; - match *self { - ItemFragment(kind, def_id) => { - let name = tcx.item_name(def_id); - match kind { - FragmentKind::Method => write!(s, "method.{}", name), - FragmentKind::TyMethod => write!(s, "tymethod.{}", name), - FragmentKind::AssociatedConstant => write!(s, "associatedconstant.{}", name), - FragmentKind::AssociatedType => write!(s, "associatedtype.{}", name), - FragmentKind::StructField => write!(s, "structfield.{}", name), - FragmentKind::Variant => write!(s, "variant.{}", name), - FragmentKind::VariantField => { - let variant = tcx.item_name(tcx.parent(def_id)); - write!(s, "variant.{}.field.{}", variant, name) + &UrlFragment::Item(def_id) => { + let kind = match tcx.def_kind(def_id) { + DefKind::AssocFn => { + if tcx.associated_item(def_id).defaultness.has_value() { + "method." + } else { + "tymethod." + } } - } + DefKind::AssocConst => "associatedconstant.", + DefKind::AssocTy => "associatedtype.", + DefKind::Variant => "variant.", + DefKind::Field => { + let parent_id = tcx.parent(def_id); + if tcx.def_kind(parent_id) == DefKind::Variant { + s.push_str("variant."); + s.push_str(tcx.item_name(parent_id).as_str()); + ".field." + } else { + "structfield." + } + } + kind => bug!("unexpected associated item kind: {:?}", kind), + }; + s.push_str(kind); + s.push_str(tcx.item_name(def_id).as_str()); } + UrlFragment::UserWritten(raw) => s.push_str(&raw), } } } @@ -315,11 +277,6 @@ struct DiagnosticInfo<'a> { link_range: Range<usize>, } -#[derive(Clone, Debug, Hash)] -struct CachedLink { - res: (Res, Option<UrlFragment>), -} - struct LinkCollector<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, /// A stack of modules used to decide what scope to resolve in. @@ -329,7 +286,7 @@ struct LinkCollector<'a, 'tcx> { mod_ids: Vec<DefId>, /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link. /// The link will be `None` if it could not be resolved (i.e. the error was cached). - visited_links: FxHashMap<ResolutionInfo, Option<CachedLink>>, + visited_links: FxHashMap<ResolutionInfo, Option<(Res, Option<UrlFragment>)>>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -1097,6 +1054,9 @@ impl LinkCollector<'_, '_> { extra_fragment: extra_fragment.clone(), }, diag_info.clone(), // this struct should really be Copy, but Range is not :( + // For reference-style links we want to report only one error so unsuccessful + // resolutions are cached, for other links we want to report an error every + // time so they are not cached. matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut), )?; @@ -1123,7 +1083,7 @@ impl LinkCollector<'_, '_> { match res { Res::Primitive(prim) => { - if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { + if let Some(UrlFragment::Item(id)) = fragment { // We're actually resolving an associated item of a primitive, so we need to // verify the disambiguator (if any) matches the type of the associated item. // This case should really follow the same flow as the `Res::Def` branch below, @@ -1171,12 +1131,11 @@ impl LinkCollector<'_, '_> { }) } Res::Def(kind, id) => { - let (kind_for_dis, id_for_dis) = - if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment { - (self.cx.tcx.def_kind(id), id) - } else { - (kind, id) - }; + let (kind_for_dis, id_for_dis) = if let Some(UrlFragment::Item(id)) = fragment { + (self.cx.tcx.def_kind(id), id) + } else { + (kind, id) + }; self.verify_disambiguator( path_str, ori_link, @@ -1294,53 +1253,33 @@ impl LinkCollector<'_, '_> { &mut self, key: ResolutionInfo, diag: DiagnosticInfo<'_>, - cache_resolution_failure: bool, + // If errors are cached then they are only reported on first ocurrence + // which we want in some cases but not in others. + cache_errors: bool, ) -> Option<(Res, Option<UrlFragment>)> { - if let Some(ref cached) = self.visited_links.get(&key) { - match cached { - Some(cached) => { - return Some(cached.res.clone()); - } - None if cache_resolution_failure => return None, - None => { - // Although we hit the cache and found a resolution error, this link isn't - // supposed to cache those. Run link resolution again to emit the expected - // resolution error. - } + if let Some(res) = self.visited_links.get(&key) { + if res.is_some() || cache_errors { + return res.clone(); } } let res = self.resolve_with_disambiguator(&key, diag.clone()).and_then(|(res, def_id)| { let fragment = match (&key.extra_fragment, def_id) { (Some(_), Some(def_id)) => { - report_anchor_conflict(self.cx, diag, Res::from_def_id(self.cx.tcx, def_id)); + report_anchor_conflict(self.cx, diag, def_id); return None; } (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())), - (None, Some(def_id)) => Some(UrlFragment::Item(ItemFragment( - FragmentKind::from_def_id(self.cx.tcx, def_id), - def_id, - ))), + (None, Some(def_id)) => Some(UrlFragment::Item(def_id)), (None, None) => None, }; Some((res, fragment)) }); - // Cache only if resolved successfully - don't silence duplicate errors - if let Some(res) = res { - // Store result for the actual namespace - self.visited_links.insert(key, Some(CachedLink { res: res.clone() })); - - Some(res) - } else { - if cache_resolution_failure { - // For reference-style links we only want to report one resolution error - // so let's cache them as well. - self.visited_links.insert(key, None); - } - - None + if res.is_some() || cache_errors { + self.visited_links.insert(key, res.clone()); } + res } /// After parsing the disambiguator, resolve the main part of the link. @@ -1916,8 +1855,8 @@ fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { anchor_failure(cx, diag_info, &msg, 1) } -fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, res: Res) { - let (link, kind) = (diag_info.ori_link, res.descr()); +fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, def_id: DefId) { + let (link, kind) = (diag_info.ori_link, Res::from_def_id(cx.tcx, def_id).descr()); let msg = format!("`{link}` contains an anchor, but links to {kind}s are already anchored"); anchor_failure(cx, diag_info, &msg, 0) } diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index 9a9c45a9b7f..1b2d1e31f52 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -34,7 +34,7 @@ wait-for: "#settings" // We check that the "Use system theme" is disabled. assert-property: ("#use-system-theme", {"checked": "false"}) -assert: "//*[@class='setting-line']/*[text()='Use system theme']" +assert: "//*[@class='setting-line']//span[text()='Use system theme']" // Meaning that only the "theme" menu is showing up. assert: ".setting-line:not(.hidden) #theme" assert: ".setting-line.hidden #preferred-dark-theme" @@ -55,7 +55,13 @@ assert: ".setting-line.hidden #theme" assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme") assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme") +// We now check that clicking on the "sliders"' text is like clicking on the slider. +// To test it, we use the "Disable keyboard shortcuts". +local-storage: {"rustdoc-disable-shortcuts": "false"} +click: ".setting-line:last-child .toggle .label" +assert-local-storage: {"rustdoc-disable-shortcuts": "true"} + // Now we go to the settings page to check that the CSS is loaded as expected. goto: file://|DOC_PATH|/settings.html wait-for: "#settings" -assert-css: (".setting-line .toggle", {"width": "45px", "margin-right": "20px"}) +assert-css: (".setting-line .toggle .slider", {"width": "45px", "margin-right": "20px"}) diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs new file mode 100644 index 00000000000..97259f782bd --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.rs @@ -0,0 +1,11 @@ +// Regression test for #97440: Multiline inner attribute triggers ICE during doctest +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +// check-pass + +//! ```rust +//! #![deny( +//! unused_parens, +//! )] +//! ``` diff --git a/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout new file mode 100644 index 00000000000..e47edbd2a81 --- /dev/null +++ b/src/test/rustdoc-ui/doc-comment-multi-line-attr.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-comment-multi-line-attr.rs - (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs index 1a314101916..2b6a9b71cd5 100644 --- a/src/test/ui/asm/aarch64/bad-reg.rs +++ b/src/test/ui/asm/aarch64/bad-reg.rs @@ -36,9 +36,11 @@ fn main() { asm!("", in("p0") foo); //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class asm!("", out("p0") _); asm!("{}", in(preg) foo); //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + //~| ERROR type `i32` cannot be used with this register class asm!("{}", out(preg) _); //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output diff --git a/src/test/ui/asm/aarch64/bad-reg.stderr b/src/test/ui/asm/aarch64/bad-reg.stderr index e3316b85193..0ba627dac30 100644 --- a/src/test/ui/asm/aarch64/bad-reg.stderr +++ b/src/test/ui/asm/aarch64/bad-reg.stderr @@ -87,19 +87,19 @@ LL | asm!("", in("p0") foo); | ^^^^^^^^^^^^ error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:40:20 + --> $DIR/bad-reg.rs:41:20 | LL | asm!("{}", in(preg) foo); | ^^^^^^^^^^^^ error: register class `preg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:42:20 + --> $DIR/bad-reg.rs:44:20 | LL | asm!("{}", out(preg) _); | ^^^^^^^^^^^ error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:48:32 + --> $DIR/bad-reg.rs:50:32 | LL | asm!("", in("x0") foo, in("w0") bar); | ------------ ^^^^^^^^^^^^ register `x0` @@ -107,7 +107,7 @@ LL | asm!("", in("x0") foo, in("w0") bar); | register `x0` error: register `x0` conflicts with register `x0` - --> $DIR/bad-reg.rs:50:32 + --> $DIR/bad-reg.rs:52:32 | LL | asm!("", in("x0") foo, out("x0") bar); | ------------ ^^^^^^^^^^^^^ register `x0` @@ -115,13 +115,13 @@ LL | asm!("", in("x0") foo, out("x0") bar); | register `x0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:50:18 + --> $DIR/bad-reg.rs:52:18 | LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ error: register `v0` conflicts with register `v0` - --> $DIR/bad-reg.rs:53:32 + --> $DIR/bad-reg.rs:55:32 | LL | asm!("", in("v0") foo, in("q0") bar); | ------------ ^^^^^^^^^^^^ register `v0` @@ -129,7 +129,7 @@ LL | asm!("", in("v0") foo, in("q0") bar); | register `v0` error: register `v0` conflicts with register `v0` - --> $DIR/bad-reg.rs:55:32 + --> $DIR/bad-reg.rs:57:32 | LL | asm!("", in("v0") foo, out("q0") bar); | ------------ ^^^^^^^^^^^^^ register `v0` @@ -137,10 +137,26 @@ LL | asm!("", in("v0") foo, out("q0") bar); | register `v0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:55:18 + --> $DIR/bad-reg.rs:57:18 | LL | asm!("", in("v0") foo, out("q0") bar); | ^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:37:27 + | +LL | asm!("", in("p0") foo); + | ^^^ + | + = note: register class `preg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:41:29 + | +LL | asm!("{}", in(preg) foo); + | ^^^ + | + = note: register class `preg` supports these types: + +error: aborting due to 20 previous errors diff --git a/src/test/ui/asm/aarch64/type-check-2-2.rs b/src/test/ui/asm/aarch64/type-check-2-2.rs new file mode 100644 index 00000000000..e4d29754556 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2-2.rs @@ -0,0 +1,37 @@ +// only-aarch64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Clone, Copy)] +struct SimdType(f32, f32, f32, f32); + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec<u64> = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + } +} diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr new file mode 100644 index 00000000000..37bbe394994 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr @@ -0,0 +1,34 @@ +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-2-2.rs:19:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-2-2.rs:22:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2-2.rs:30:29 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2-2.rs:32:31 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs index 9e53a2e0c52..fdafe63c7b0 100644 --- a/src/test/ui/asm/aarch64/type-check-2.rs +++ b/src/test/ui/asm/aarch64/type-check-2.rs @@ -15,23 +15,6 @@ fn main() { unsafe { // Inputs must be initialized - let x: u64; - asm!("{}", in(reg) x); - //~^ ERROR use of possibly-uninitialized variable: `x` - let mut y: u64; - asm!("{}", inout(reg) y); - //~^ ERROR use of possibly-uninitialized variable: `y` - let _ = y; - - // Outputs require mutable places - - let v: Vec<u64> = vec![0, 1, 2]; - asm!("{}", in(reg) v[0]); - asm!("{}", out(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable - asm!("{}", inout(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable - // Sym operands must point to a function or static const C: i32 = 0; diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr index 6047bed6e78..4b99652cd20 100644 --- a/src/test/ui/asm/aarch64/type-check-2.stderr +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -1,13 +1,29 @@ +error: invalid `sym` operand + --> $DIR/type-check-2.rs:75:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:24:20 + | +LL | asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:46:31 + --> $DIR/type-check-2.rs:29:31 | LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly - --> $DIR/type-check-2.rs:58:28 +error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:38]` for inline assembly + --> $DIR/type-check-2.rs:41:28 | LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ @@ -15,7 +31,7 @@ LL | asm!("{}", in(reg) |x: i32| x); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec<i32>` for inline assembly - --> $DIR/type-check-2.rs:60:28 + --> $DIR/type-check-2.rs:43:28 | LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ @@ -24,7 +40,7 @@ LL | asm!("{}", in(reg) vec![0]); = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:62:28 + --> $DIR/type-check-2.rs:45:28 | LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ @@ -32,7 +48,7 @@ LL | asm!("{}", in(reg) (1, 2, 3)); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:64:28 + --> $DIR/type-check-2.rs:47:28 | LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ @@ -40,7 +56,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:72:31 + --> $DIR/type-check-2.rs:55:31 | LL | asm!("{}", inout(reg) f); | ^ @@ -48,60 +64,12 @@ LL | asm!("{}", inout(reg) f); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:75:31 + --> $DIR/type-check-2.rs:58:31 | LL | asm!("{}", inout(reg) r); | ^ | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly -error: invalid `sym` operand - --> $DIR/type-check-2.rs:41:20 - | -LL | asm!("{}", sym C); - | ^^^^^ is an `i32` - | - = help: `sym` operands must refer to either a function or a static - -error: invalid `sym` operand - --> $DIR/type-check-2.rs:92:19 - | -LL | global_asm!("{}", sym C); - | ^^^^^ is an `i32` - | - = help: `sym` operands must refer to either a function or a static - -error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/type-check-2.rs:19:28 - | -LL | asm!("{}", in(reg) x); - | ^ use of possibly-uninitialized `x` - -error[E0381]: use of possibly-uninitialized variable: `y` - --> $DIR/type-check-2.rs:22:9 - | -LL | asm!("{}", inout(reg) y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:30:29 - | -LL | let v: Vec<u64> = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -LL | asm!("{}", in(reg) v[0]); -LL | asm!("{}", out(reg) v[0]); - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:32:31 - | -LL | let v: Vec<u64> = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -... -LL | asm!("{}", inout(reg) v[0]); - | ^ cannot borrow as mutable - -error: aborting due to 13 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0381, E0596. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/aarch64/type-check-3.rs b/src/test/ui/asm/aarch64/type-check-3.rs index 8cac18b8052..623f6593d79 100644 --- a/src/test/ui/asm/aarch64/type-check-3.rs +++ b/src/test/ui/asm/aarch64/type-check-3.rs @@ -95,21 +95,3 @@ fn main() { asm!("{:x}", inout(reg) main => val_u64); } } - -// Constants must be... constant - -static S: i32 = 1; -const fn const_foo(x: i32) -> i32 { - x -} -const fn const_bar<T>(x: T) -> T { - x -} -global_asm!("{}", const S); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(S)); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(S)); -//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr index c31a62ae791..b320abdc01b 100644 --- a/src/test/ui/asm/aarch64/type-check-3.stderr +++ b/src/test/ui/asm/aarch64/type-check-3.stderr @@ -143,30 +143,5 @@ LL | asm!("{:x}", inout(reg) main => val_u32); | = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:108:25 - | -LL | global_asm!("{}", const S); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:111:35 - | -LL | global_asm!("{}", const const_foo(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:114:35 - | -LL | global_asm!("{}", const const_bar(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error: aborting due to 9 previous errors; 10 warnings emitted +error: aborting due to 6 previous errors; 10 warnings emitted -For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/aarch64/type-check-4.rs b/src/test/ui/asm/aarch64/type-check-4.rs new file mode 100644 index 00000000000..bd23755c023 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-4.rs @@ -0,0 +1,32 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(repr_simd, stdsimd, asm_const)] + +use std::arch::aarch64::float64x2_t; +use std::arch::{asm, global_asm}; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct Simd256bit(f64, f64, f64, f64); + +fn main() { +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar<T>(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/aarch64/type-check-4.stderr b/src/test/ui/asm/aarch64/type-check-4.stderr new file mode 100644 index 00000000000..4837e647bea --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-4.stderr @@ -0,0 +1,27 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:25:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:28:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:31:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr index 11c4e01f418..7ef93e15f5b 100644 --- a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -89,7 +89,7 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:52:18 + --> $DIR/bad-template.rs:53:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:58:14 + --> $DIR/bad-template.rs:59:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:60:14 + --> $DIR/bad-template.rs:61:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:60:20 + --> $DIR/bad-template.rs:61:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:15 + --> $DIR/bad-template.rs:64:15 | LL | global_asm!("{a}"); | ^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:65:14 + --> $DIR/bad-template.rs:66:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:68:14 + --> $DIR/bad-template.rs:69:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:68:20 + --> $DIR/bad-template.rs:69:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:71:16 + --> $DIR/bad-template.rs:72:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:73:17 + --> $DIR/bad-template.rs:74:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -183,5 +183,15 @@ LL | global_asm!("", const FOO, const FOO); | = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` -error: aborting due to 21 previous errors +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr index 11c4e01f418..7ef93e15f5b 100644 --- a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -89,7 +89,7 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:52:18 + --> $DIR/bad-template.rs:53:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:58:14 + --> $DIR/bad-template.rs:59:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:60:14 + --> $DIR/bad-template.rs:61:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:60:20 + --> $DIR/bad-template.rs:61:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:15 + --> $DIR/bad-template.rs:64:15 | LL | global_asm!("{a}"); | ^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:65:14 + --> $DIR/bad-template.rs:66:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:68:14 + --> $DIR/bad-template.rs:69:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:68:20 + --> $DIR/bad-template.rs:69:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:71:16 + --> $DIR/bad-template.rs:72:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:73:17 + --> $DIR/bad-template.rs:74:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -183,5 +183,15 @@ LL | global_asm!("", const FOO, const FOO); | = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` -error: aborting due to 21 previous errors +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs index b062c45e6ea..55637174792 100644 --- a/src/test/ui/asm/bad-template.rs +++ b/src/test/ui/asm/bad-template.rs @@ -49,6 +49,7 @@ fn main() { //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 asm!("{:foo}", in(reg) foo); //~^ ERROR asm template modifier must be a single character + //~| WARN formatting may not be suitable for sub-register argument [asm_sub_register] asm!("", in(reg) 0, in(reg) 1); //~^ ERROR multiple unused asm arguments } diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr index c198e0a69dd..250bc3be42e 100644 --- a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -89,7 +89,7 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:52:18 + --> $DIR/bad-template.rs:53:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:58:14 + --> $DIR/bad-template.rs:59:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:60:14 + --> $DIR/bad-template.rs:61:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:60:20 + --> $DIR/bad-template.rs:61:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:15 + --> $DIR/bad-template.rs:64:15 | LL | global_asm!("{a}"); | ^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:65:14 + --> $DIR/bad-template.rs:66:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:68:14 + --> $DIR/bad-template.rs:69:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:68:20 + --> $DIR/bad-template.rs:69:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:71:16 + --> $DIR/bad-template.rs:72:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:73:17 + --> $DIR/bad-template.rs:74:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -183,5 +183,15 @@ LL | global_asm!("", const FOO, const FOO); | = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` -error: aborting due to 21 previous errors +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr index c198e0a69dd..250bc3be42e 100644 --- a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -89,7 +89,7 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:52:18 + --> $DIR/bad-template.rs:53:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:58:14 + --> $DIR/bad-template.rs:59:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:60:14 + --> $DIR/bad-template.rs:61:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:60:20 + --> $DIR/bad-template.rs:61:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:15 + --> $DIR/bad-template.rs:64:15 | LL | global_asm!("{a}"); | ^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:65:14 + --> $DIR/bad-template.rs:66:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:65:19 + --> $DIR/bad-template.rs:66:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:68:14 + --> $DIR/bad-template.rs:69:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:68:20 + --> $DIR/bad-template.rs:69:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:71:16 + --> $DIR/bad-template.rs:72:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:73:17 + --> $DIR/bad-template.rs:74:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -183,5 +183,15 @@ LL | global_asm!("", const FOO, const FOO); | = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` -error: aborting due to 21 previous errors +warning: formatting may not be suitable for sub-register argument + --> $DIR/bad-template.rs:50:15 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs index 2a57afa1a6a..9e626f5711d 100644 --- a/src/test/ui/asm/naked-functions.rs +++ b/src/test/ui/asm/naked-functions.rs @@ -37,6 +37,7 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 { } #[naked] +#[allow(asm_sub_register)] pub unsafe extern "C" fn inc_asm(a: u32) -> u32 { asm!("/* {0} */", in(reg) a, options(noreturn)); //~^ ERROR referencing function parameters is not allowed in naked functions diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr index 8a610b25f00..1828066b692 100644 --- a/src/test/ui/asm/naked-functions.stderr +++ b/src/test/ui/asm/naked-functions.stderr @@ -1,23 +1,23 @@ error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:110:14 + --> $DIR/naked-functions.rs:111:14 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:202:5 + --> $DIR/naked-functions.rs:203:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:208:5 + --> $DIR/naked-functions.rs:209:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:215:10 + --> $DIR/naked-functions.rs:216:10 | LL | asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | | } | |_^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:41:31 + --> $DIR/naked-functions.rs:42:31 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^ @@ -74,13 +74,13 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn)); = help: follow the calling convention in asm block to use parameters error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:41:23 + --> $DIR/naked-functions.rs:42:23 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^^^^^^^^^ error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:47:1 + --> $DIR/naked-functions.rs:48:1 | LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | | @@ -90,7 +90,7 @@ LL | | } | |_^ error[E0787]: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:64:10 + --> $DIR/naked-functions.rs:65:10 | LL | in(reg) a, | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | out(reg) e, | ^^^^^^^^^^ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:62:5 + --> $DIR/naked-functions.rs:63:5 | LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", LL | | @@ -122,7 +122,7 @@ LL | sym G, options(noreturn), | +++++++++++++++++++ error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:53:1 + --> $DIR/naked-functions.rs:54:1 | LL | / pub unsafe extern "C" fn unsupported_operands() { LL | | @@ -142,7 +142,7 @@ LL | | } | |_^ error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:76:1 + --> $DIR/naked-functions.rs:77:1 | LL | / pub extern "C" fn missing_assembly() { LL | | @@ -150,7 +150,7 @@ LL | | } | |_^ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:83:5 + --> $DIR/naked-functions.rs:84:5 | LL | asm!(""); | ^^^^^^^^ @@ -161,7 +161,7 @@ LL | asm!("", options(noreturn)); | +++++++++++++++++++ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:85:5 + --> $DIR/naked-functions.rs:86:5 | LL | asm!(""); | ^^^^^^^^ @@ -172,7 +172,7 @@ LL | asm!("", options(noreturn)); | +++++++++++++++++++ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:87:5 + --> $DIR/naked-functions.rs:88:5 | LL | asm!(""); | ^^^^^^^^ @@ -183,7 +183,7 @@ LL | asm!("", options(noreturn)); | +++++++++++++++++++ error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:81:1 + --> $DIR/naked-functions.rs:82:1 | LL | / pub extern "C" fn too_many_asm_blocks() { LL | | @@ -201,7 +201,7 @@ LL | | } | |_^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:96:11 + --> $DIR/naked-functions.rs:97:11 | LL | *&y | ^ @@ -209,7 +209,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters error[E0787]: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:94:5 + --> $DIR/naked-functions.rs:95:5 | LL | / pub extern "C" fn inner(y: usize) -> usize { LL | | @@ -220,19 +220,19 @@ LL | | } | |_____^ error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:104:5 + --> $DIR/naked-functions.rs:105:5 | LL | asm!("", options(nomem, preserves_flags, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` - --> $DIR/naked-functions.rs:110:5 + --> $DIR/naked-functions.rs:111:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:110:5 + --> $DIR/naked-functions.rs:111:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -243,13 +243,13 @@ LL | asm!("", options(noreturn), options(readonly, nostack), options(pure)); | +++++++++++++++++++ error[E0787]: asm options unsupported in naked functions: `may_unwind` - --> $DIR/naked-functions.rs:118:5 + --> $DIR/naked-functions.rs:119:5 | LL | asm!("", options(noreturn, may_unwind)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:123:15 + --> $DIR/naked-functions.rs:124:15 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^ @@ -257,43 +257,43 @@ LL | pub unsafe fn default_abi() { = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:129:15 + --> $DIR/naked-functions.rs:130:15 | LL | pub unsafe fn rust_abi() { | ^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:169:1 + --> $DIR/naked-functions.rs:170:1 | LL | #[inline] | ^^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:176:1 + --> $DIR/naked-functions.rs:177:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:183:1 + --> $DIR/naked-functions.rs:184:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:190:1 + --> $DIR/naked-functions.rs:191:1 | LL | #[inline] | ^^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:192:1 + --> $DIR/naked-functions.rs:193:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:194:1 + --> $DIR/naked-functions.rs:195:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs index 367a035387b..50b369ae045 100644 --- a/src/test/ui/asm/type-check-1.rs +++ b/src/test/ui/asm/type-check-1.rs @@ -22,10 +22,13 @@ fn main() { let v: [u64; 3] = [0, 1, 2]; asm!("{}", in(reg) v[..]); //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly asm!("{}", out(reg) v[..]); //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly asm!("{}", inout(reg) v[..]); //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + //~| ERROR cannot use value of type `[u64]` for inline assembly // Constants must be... constant diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index bf5ea1befb6..52d814ce682 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:39:26 + --> $DIR/type-check-1.rs:42:26 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -8,7 +8,7 @@ LL | asm!("{}", const x); | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:42:36 + --> $DIR/type-check-1.rs:45:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -17,7 +17,7 @@ LL | asm!("{}", const const_foo(x)); | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:45:36 + --> $DIR/type-check-1.rs:48:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -26,7 +26,7 @@ LL | asm!("{}", const const_bar(x)); | ^ non-constant value error: invalid `sym` operand - --> $DIR/type-check-1.rs:47:24 + --> $DIR/type-check-1.rs:50:24 | LL | asm!("{}", sym x); | ^ is a local variable @@ -34,13 +34,13 @@ LL | asm!("{}", sym x); = help: `sym` operands must refer to either a function or a static error[E0308]: mismatched types - --> $DIR/type-check-1.rs:55:26 + --> $DIR/type-check-1.rs:58:26 | LL | asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:57:26 + --> $DIR/type-check-1.rs:60:26 | LL | asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -49,7 +49,7 @@ LL | asm!("{}", const 0 as *mut u8); found raw pointer `*mut u8` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:59:26 + --> $DIR/type-check-1.rs:62:26 | LL | asm!("{}", const &0); | ^^ expected integer, found `&{integer}` @@ -82,7 +82,7 @@ LL | asm!("{}", in(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:25:29 + --> $DIR/type-check-1.rs:26:29 | LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -91,7 +91,7 @@ LL | asm!("{}", out(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:27:31 + --> $DIR/type-check-1.rs:29:31 | LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -99,14 +99,38 @@ LL | asm!("{}", inout(reg) v[..]); = help: the trait `Sized` is not implemented for `[u64]` = note: all inline asm arguments must have a statically known size +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:23:28 + | +LL | asm!("{}", in(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:26:29 + | +LL | asm!("{}", out(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[u64]` for inline assembly + --> $DIR/type-check-1.rs:29:31 + | +LL | asm!("{}", inout(reg) v[..]); + | ^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + error[E0308]: mismatched types - --> $DIR/type-check-1.rs:73:25 + --> $DIR/type-check-1.rs:76:25 | LL | global_asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:75:25 + --> $DIR/type-check-1.rs:78:25 | LL | global_asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -114,7 +138,7 @@ LL | global_asm!("{}", const 0 as *mut u8); = note: expected type `{integer}` found raw pointer `*mut u8` -error: aborting due to 14 previous errors +error: aborting due to 17 previous errors Some errors have detailed explanations: E0277, E0308, E0435. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/asm/x86_64/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs index 272372ebedc..a4f50a534a1 100644 --- a/src/test/ui/asm/x86_64/bad-reg.rs +++ b/src/test/ui/asm/x86_64/bad-reg.rs @@ -32,16 +32,21 @@ fn main() { asm!("", in("st(2)") foo); //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class asm!("", in("mm0") foo); //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class asm!("", in("k0") foo); //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class asm!("", out("st(2)") _); asm!("", out("mm0") _); asm!("{}", in(x87_reg) foo); //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class asm!("{}", in(mmx_reg) foo); //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output + //~| ERROR `i32` cannot be used with this register class asm!("{}", out(x87_reg) _); //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output asm!("{}", out(mmx_reg) _); @@ -52,9 +57,12 @@ fn main() { asm!("", in("eax") foo, in("al") bar); //~^ ERROR register `al` conflicts with register `ax` + //~| ERROR `i32` cannot be used with this register class asm!("", in("rax") foo, out("rax") bar); //~^ ERROR register `ax` conflicts with register `ax` asm!("", in("al") foo, lateout("al") bar); + //~^ ERROR `i32` cannot be used with this register class + //~| ERROR `i32` cannot be used with this register class asm!("", in("xmm0") foo, in("ymm0") bar); //~^ ERROR register `ymm0` conflicts with register `xmm0` asm!("", in("xmm0") foo, out("ymm0") bar); diff --git a/src/test/ui/asm/x86_64/bad-reg.stderr b/src/test/ui/asm/x86_64/bad-reg.stderr index 84b8b5ec285..82b7ebd0fb0 100644 --- a/src/test/ui/asm/x86_64/bad-reg.stderr +++ b/src/test/ui/asm/x86_64/bad-reg.stderr @@ -71,43 +71,43 @@ LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: register class `kreg0` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:37:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:41:20 + --> $DIR/bad-reg.rs:44:20 | LL | asm!("{}", in(x87_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:43:20 + --> $DIR/bad-reg.rs:47:20 | LL | asm!("{}", in(mmx_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:45:20 + --> $DIR/bad-reg.rs:50:20 | LL | asm!("{}", out(x87_reg) _); | ^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:47:20 + --> $DIR/bad-reg.rs:52:20 | LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ error: register `al` conflicts with register `ax` - --> $DIR/bad-reg.rs:53:33 + --> $DIR/bad-reg.rs:58:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` @@ -115,7 +115,7 @@ LL | asm!("", in("eax") foo, in("al") bar); | register `ax` error: register `ax` conflicts with register `ax` - --> $DIR/bad-reg.rs:55:33 + --> $DIR/bad-reg.rs:61:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `ax` @@ -123,13 +123,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `ax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:55:18 + --> $DIR/bad-reg.rs:61:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:58:34 + --> $DIR/bad-reg.rs:66:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -137,7 +137,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:60:34 + --> $DIR/bad-reg.rs:68:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -145,10 +145,74 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:60:18 + --> $DIR/bad-reg.rs:68:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ -error: aborting due to 20 previous errors +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:33:30 + | +LL | asm!("", in("st(2)") foo); + | ^^^ + | + = note: register class `x87_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:36:28 + | +LL | asm!("", in("mm0") foo); + | ^^^ + | + = note: register class `mmx_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:39:27 + | +LL | asm!("", in("k0") foo); + | ^^^ + | + = note: register class `kreg0` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:44:32 + | +LL | asm!("{}", in(x87_reg) foo); + | ^^^ + | + = note: register class `x87_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:47:32 + | +LL | asm!("{}", in(mmx_reg) foo); + | ^^^ + | + = note: register class `mmx_reg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:58:42 + | +LL | asm!("", in("eax") foo, in("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:63:27 + | +LL | asm!("", in("al") foo, lateout("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:63:46 + | +LL | asm!("", in("al") foo, lateout("al") bar); + | ^^^ + | + = note: register class `reg_byte` supports these types: i8 + +error: aborting due to 28 previous errors diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs index eb87ea91085..59d8cde3fb6 100644 --- a/src/test/ui/asm/x86_64/type-check-2.rs +++ b/src/test/ui/asm/x86_64/type-check-2.rs @@ -13,10 +13,8 @@ fn main() { let x: u64; asm!("{}", in(reg) x); - //~^ ERROR use of possibly-uninitialized variable: `x` let mut y: u64; asm!("{}", inout(reg) y); - //~^ ERROR use of possibly-uninitialized variable: `y` let _ = y; // Outputs require mutable places @@ -24,9 +22,7 @@ fn main() { let v: Vec<u64> = vec![0, 1, 2]; asm!("{}", in(reg) v[0]); asm!("{}", out(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable asm!("{}", inout(reg) v[0]); - //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable // Sym operands must point to a function or static @@ -36,6 +32,8 @@ fn main() { asm!("{}", sym main); asm!("{}", sym C); //~^ ERROR invalid `sym` operand + asm!("{}", sym x); + //~^ ERROR invalid `sym` operand // Register operands must be Copy diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr index cb3960acdf9..46baeb511ca 100644 --- a/src/test/ui/asm/x86_64/type-check-2.stderr +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -1,13 +1,37 @@ +error: invalid `sym` operand + --> $DIR/type-check-2.rs:35:24 + | +LL | asm!("{}", sym x); + | ^ is a local variable + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:86:19 + | +LL | global_asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + +error: invalid `sym` operand + --> $DIR/type-check-2.rs:33:20 + | +LL | asm!("{}", sym C); + | ^^^^^ is an `i32` + | + = help: `sym` operands must refer to either a function or a static + error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:42:32 + --> $DIR/type-check-2.rs:40:32 | LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly - --> $DIR/type-check-2.rs:54:28 +error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:38]` for inline assembly + --> $DIR/type-check-2.rs:52:28 | LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ @@ -15,7 +39,7 @@ LL | asm!("{}", in(reg) |x: i32| x); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec<i32>` for inline assembly - --> $DIR/type-check-2.rs:56:28 + --> $DIR/type-check-2.rs:54:28 | LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ @@ -24,7 +48,7 @@ LL | asm!("{}", in(reg) vec![0]); = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:58:28 + --> $DIR/type-check-2.rs:56:28 | LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ @@ -32,7 +56,7 @@ LL | asm!("{}", in(reg) (1, 2, 3)); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:60:28 + --> $DIR/type-check-2.rs:58:28 | LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ @@ -40,7 +64,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:68:31 + --> $DIR/type-check-2.rs:66:31 | LL | asm!("{}", inout(reg) f); | ^ @@ -48,60 +72,12 @@ LL | asm!("{}", inout(reg) f); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:71:31 + --> $DIR/type-check-2.rs:69:31 | LL | asm!("{}", inout(reg) r); | ^ | = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly -error: invalid `sym` operand - --> $DIR/type-check-2.rs:37:20 - | -LL | asm!("{}", sym C); - | ^^^^^ is an `i32` - | - = help: `sym` operands must refer to either a function or a static - -error: invalid `sym` operand - --> $DIR/type-check-2.rs:88:19 - | -LL | global_asm!("{}", sym C); - | ^^^^^ is an `i32` - | - = help: `sym` operands must refer to either a function or a static - -error[E0381]: use of possibly-uninitialized variable: `x` - --> $DIR/type-check-2.rs:15:28 - | -LL | asm!("{}", in(reg) x); - | ^ use of possibly-uninitialized `x` - -error[E0381]: use of possibly-uninitialized variable: `y` - --> $DIR/type-check-2.rs:18:9 - | -LL | asm!("{}", inout(reg) y); - | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:26:29 - | -LL | let v: Vec<u64> = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -LL | asm!("{}", in(reg) v[0]); -LL | asm!("{}", out(reg) v[0]); - | ^ cannot borrow as mutable - -error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable - --> $DIR/type-check-2.rs:28:31 - | -LL | let v: Vec<u64> = vec![0, 1, 2]; - | - help: consider changing this to be mutable: `mut v` -... -LL | asm!("{}", inout(reg) v[0]); - | ^ cannot borrow as mutable - -error: aborting due to 13 previous errors +error: aborting due to 10 previous errors -Some errors have detailed explanations: E0381, E0596. -For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/x86_64/type-check-3.rs b/src/test/ui/asm/x86_64/type-check-3.rs index 595de55fd8b..89c849c7523 100644 --- a/src/test/ui/asm/x86_64/type-check-3.rs +++ b/src/test/ui/asm/x86_64/type-check-3.rs @@ -71,21 +71,3 @@ fn main() { asm!("{:r}", inout(reg) main => val_u64); } } - -// Constants must be... constant - -static S: i32 = 1; -const fn const_foo(x: i32) -> i32 { - x -} -const fn const_bar<T>(x: T) -> T { - x -} -global_asm!("{}", const S); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_foo(0)); -global_asm!("{}", const const_foo(S)); -//~^ ERROR constants cannot refer to statics -global_asm!("{}", const const_bar(0)); -global_asm!("{}", const const_bar(S)); -//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr index aeb638d6949..b38ea8cc4d8 100644 --- a/src/test/ui/asm/x86_64/type-check-3.stderr +++ b/src/test/ui/asm/x86_64/type-check-3.stderr @@ -114,30 +114,5 @@ LL | asm!("{:r}", inout(reg) main => val_u32); | = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:84:25 - | -LL | global_asm!("{}", const S); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:87:35 - | -LL | global_asm!("{}", const const_foo(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0013]: constants cannot refer to statics - --> $DIR/type-check-3.rs:90:35 - | -LL | global_asm!("{}", const const_bar(S)); - | ^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error: aborting due to 12 previous errors; 4 warnings emitted +error: aborting due to 9 previous errors; 4 warnings emitted -For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/x86_64/type-check-4.rs b/src/test/ui/asm/x86_64/type-check-4.rs new file mode 100644 index 00000000000..da3b76c3d23 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-4.rs @@ -0,0 +1,29 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx512f + +#![feature(asm_const, asm_sym)] + +use std::arch::{asm, global_asm}; + +use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; + +fn main() { +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar<T>(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/x86_64/type-check-4.stderr b/src/test/ui/asm/x86_64/type-check-4.stderr new file mode 100644 index 00000000000..33f4638fb4b --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-4.stderr @@ -0,0 +1,27 @@ +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:22:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:25:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-4.rs:28:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/x86_64/type-check-5.rs b/src/test/ui/asm/x86_64/type-check-5.rs new file mode 100644 index 00000000000..474478f6a88 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-5.rs @@ -0,0 +1,63 @@ +// only-x86_64 + +#![feature(repr_simd, never_type, asm_sym)] + +use std::arch::asm; + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec<u64> = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + + // Register operands must be Copy + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", in(reg) r); + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr new file mode 100644 index 00000000000..181ecaf5855 --- /dev/null +++ b/src/test/ui/asm/x86_64/type-check-5.stderr @@ -0,0 +1,34 @@ +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-5.rs:15:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-5.rs:18:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-5.rs:26:29 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-5.rs:28:31 + | +LL | let v: Vec<u64> = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 36b7f2e4558..28d94b14ac9 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -43,13 +43,13 @@ LL | require_send(send_fut); = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>` = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>` = note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>` = note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>` = note: required because it appears within the type `impl Future<Output = Arc<RefCell<i32>>>` = note: required because it appears within the type `{ResumeTy, impl Future<Output = Arc<RefCell<i32>>>, (), i32, Ready<i32>}` = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>` = note: required because it appears within the type `impl Future<Output = ()>` note: required by a bound in `require_send` --> $DIR/issue-68112.rs:11:25 diff --git a/src/test/ui/async-await/partial-drop-partial-reinit.stderr b/src/test/ui/async-await/partial-drop-partial-reinit.stderr index 7c074b07c3d..a1c4957e984 100644 --- a/src/test/ui/async-await/partial-drop-partial-reinit.stderr +++ b/src/test/ui/async-await/partial-drop-partial-reinit.stderr @@ -13,7 +13,7 @@ LL | async fn foo() { = note: required because it appears within the type `(NotSend,)` = note: required because it appears within the type `{ResumeTy, (NotSend,), impl Future<Output = ()>, ()}` = note: required because it appears within the type `[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]` - = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>` + = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/partial-drop-partial-reinit.rs:22:16: 27:2]>` = note: required because it appears within the type `impl Future<Output = ()>` = note: required because it appears within the type `impl Future<Output = ()>` note: required by a bound in `gimme_send` diff --git a/src/test/ui/borrowck/issue-81899.rs b/src/test/ui/borrowck/issue-81899.rs new file mode 100644 index 00000000000..356517745ff --- /dev/null +++ b/src/test/ui/borrowck/issue-81899.rs @@ -0,0 +1,13 @@ +// Regression test for #81899. +// The `panic!()` below is important to trigger the fixed ICE. + +const _CONST: &[u8] = &f(&[], |_| {}); + +const fn f<F>(_: &[u8], _: F) -> &[u8] +where + F: FnMut(&u8), +{ + panic!() //~ ERROR: evaluation of constant value failed +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-81899.stderr b/src/test/ui/borrowck/issue-81899.stderr new file mode 100644 index 00000000000..59bf00d0012 --- /dev/null +++ b/src/test/ui/borrowck/issue-81899.stderr @@ -0,0 +1,17 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-81899.rs:10:5 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | -------------- inside `_CONST` at $DIR/issue-81899.rs:4:24 +... +LL | panic!() + | ^^^^^^^^ + | | + | the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:10:5 + | inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/cast/casts-issue-46365.rs b/src/test/ui/cast/casts-issue-46365.rs index 3d0fea245c0..a2205b718c1 100644 --- a/src/test/ui/cast/casts-issue-46365.rs +++ b/src/test/ui/cast/casts-issue-46365.rs @@ -3,5 +3,5 @@ struct Lorem { } fn main() { - let _foo: *mut Lorem = core::ptr::null_mut(); // no error here + let _foo: *mut Lorem = core::ptr::NonNull::dangling().as_ptr(); // no error here } diff --git a/src/test/ui/cfg/cfg-target-compact-errors.rs b/src/test/ui/cfg/cfg-target-compact-errors.rs new file mode 100644 index 00000000000..bca2275b1a9 --- /dev/null +++ b/src/test/ui/cfg/cfg-target-compact-errors.rs @@ -0,0 +1,17 @@ +// check-fail + +#![feature(cfg_target_compact)] + +#[cfg(target(o::o))] +//~^ ERROR `cfg` predicate key must be an identifier +fn one() {} + +#[cfg(target(os = 8))] +//~^ ERROR literal in `cfg` predicate value must be a string +fn two() {} + +#[cfg(target(os = "linux", pointer(width = "64")))] +//~^ ERROR invalid predicate `target_pointer` +fn three() {} + +fn main() {} diff --git a/src/test/ui/cfg/cfg-target-compact-errors.stderr b/src/test/ui/cfg/cfg-target-compact-errors.stderr new file mode 100644 index 00000000000..bb858301eb5 --- /dev/null +++ b/src/test/ui/cfg/cfg-target-compact-errors.stderr @@ -0,0 +1,22 @@ +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-target-compact-errors.rs:5:14 + | +LL | #[cfg(target(o::o))] + | ^^^^ + +error[E0565]: literal in `cfg` predicate value must be a string + --> $DIR/cfg-target-compact-errors.rs:9:19 + | +LL | #[cfg(target(os = 8))] + | ^ + +error[E0537]: invalid predicate `target_pointer` + --> $DIR/cfg-target-compact-errors.rs:13:28 + | +LL | #[cfg(target(os = "linux", pointer(width = "64")))] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0537, E0565. +For more information about an error, try `rustc --explain E0537`. diff --git a/src/test/ui/cfg/cfg-target-compact.rs b/src/test/ui/cfg/cfg-target-compact.rs new file mode 100644 index 00000000000..dc95a80915c --- /dev/null +++ b/src/test/ui/cfg/cfg-target-compact.rs @@ -0,0 +1,10 @@ +// run-pass +#![feature(cfg_target_compact)] + +#[cfg(target(os = "linux", pointer_width = "64"))] +pub fn main() { +} + +#[cfg(not(target(os = "linux", pointer_width = "64")))] +pub fn main() { +} diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr index e6a72c72dd3..5b7ca8d46cf 100644 --- a/src/test/ui/chalkify/bugs/async.stderr +++ b/src/test/ui/chalkify/bugs/async.stderr @@ -7,11 +7,11 @@ LL | | x LL | | } | |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]` | -note: required by a bound in `from_generator` +note: required by a bound in `std::future::from_generator` --> $SRC_DIR/core/src/future/mod.rs:LL:COL | LL | T: Generator<ResumeTy, Yield = ()>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `from_generator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `std::future::from_generator` error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator<ResumeTy>>::Yield == ()` is not satisfied --> $DIR/async.rs:7:29 @@ -22,11 +22,11 @@ LL | | x LL | | } | |_^ | -note: required by a bound in `from_generator` +note: required by a bound in `std::future::from_generator` --> $SRC_DIR/core/src/future/mod.rs:LL:COL | LL | T: Generator<ResumeTy, Yield = ()>, - | ^^^^^^^^^^ required by this bound in `from_generator` + | ^^^^^^^^^^ required by this bound in `std::future::from_generator` error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied --> $DIR/async.rs:7:29 diff --git a/src/test/ui/check-cfg/compact-names.rs b/src/test/ui/check-cfg/compact-names.rs new file mode 100644 index 00000000000..bff80740039 --- /dev/null +++ b/src/test/ui/check-cfg/compact-names.rs @@ -0,0 +1,15 @@ +// This test check that we correctly emit an warning for compact cfg +// +// check-pass +// compile-flags:--check-cfg=names() -Z unstable-options + +#![feature(cfg_target_compact)] + +#[cfg(target(os = "linux", arch = "arm"))] +pub fn expected() {} + +#[cfg(target(os = "linux", architecture = "arm"))] +//~^ WARNING unexpected `cfg` condition name +pub fn unexpected() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/compact-names.stderr b/src/test/ui/check-cfg/compact-names.stderr new file mode 100644 index 00000000000..f1fc4285a71 --- /dev/null +++ b/src/test/ui/check-cfg/compact-names.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name + --> $DIR/compact-names.rs:11:28 + | +LL | #[cfg(target(os = "linux", architecture = "arm"))] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/check-cfg/compact-values.rs b/src/test/ui/check-cfg/compact-values.rs new file mode 100644 index 00000000000..1f17057840c --- /dev/null +++ b/src/test/ui/check-cfg/compact-values.rs @@ -0,0 +1,15 @@ +// This test check that we correctly emit an warning for compact cfg +// +// check-pass +// compile-flags:--check-cfg=values() -Z unstable-options + +#![feature(cfg_target_compact)] + +#[cfg(target(os = "linux", arch = "arm"))] +pub fn expected() {} + +#[cfg(target(os = "linux", arch = "X"))] +//~^ WARNING unexpected `cfg` condition value +pub fn unexpected() {} + +fn main() {} diff --git a/src/test/ui/check-cfg/compact-values.stderr b/src/test/ui/check-cfg/compact-values.stderr new file mode 100644 index 00000000000..a196e1537df --- /dev/null +++ b/src/test/ui/check-cfg/compact-values.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value + --> $DIR/compact-values.rs:11:28 + | +LL | #[cfg(target(os = "linux", arch = "X"))] + | ^^^^^^^^^^ + | + = note: `#[warn(unexpected_cfgs)]` on by default + = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64 + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr index e1c20e6ae78..16fabd1e88f 100644 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -1,8 +1,8 @@ -error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter +error[E0741]: `(dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter --> $DIR/issue-63322-forbid-dyn.rs:9:18 | LL | fn test<const T: &'static dyn A>() { - | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-97278.rs b/src/test/ui/const-generics/issues/issue-97278.rs new file mode 100644 index 00000000000..da0a9776fd4 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-97278.rs @@ -0,0 +1,14 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::sync::Arc; + +#[derive(PartialEq, Eq)] +enum Bar { + Bar(Arc<i32>) +} + +fn test<const BAR: Bar>() {} +//~^ ERROR `Arc<i32>` must be annotated with `#[derive(PartialEq, Eq)]` + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-97278.stderr b/src/test/ui/const-generics/issues/issue-97278.stderr new file mode 100644 index 00000000000..ff13cb505ab --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-97278.stderr @@ -0,0 +1,9 @@ +error[E0741]: `Arc<i32>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-97278.rs:11:20 + | +LL | fn test<const BAR: Bar>() {} + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/consts/issue-91434.rs b/src/test/ui/consts/issue-91434.rs index fc7731291b3..001dc708f89 100644 --- a/src/test/ui/consts/issue-91434.rs +++ b/src/test/ui/consts/issue-91434.rs @@ -2,5 +2,4 @@ fn main() { [9; [[9E; h]]]; //~^ ERROR: expected at least one digit in exponent //~| ERROR: cannot find value `h` in this scope [E0425] - //~| ERROR: constant expression depends on a generic parameter } diff --git a/src/test/ui/consts/issue-91434.stderr b/src/test/ui/consts/issue-91434.stderr index 9d3fe5f2016..08d3ad77053 100644 --- a/src/test/ui/consts/issue-91434.stderr +++ b/src/test/ui/consts/issue-91434.stderr @@ -10,14 +10,6 @@ error[E0425]: cannot find value `h` in this scope LL | [9; [[9E; h]]]; | ^ not found in this scope -error: constant expression depends on a generic parameter - --> $DIR/issue-91434.rs:2:9 - | -LL | [9; [[9E; h]]]; - | ^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/consts/nested_erroneous_ctfe.rs b/src/test/ui/consts/nested_erroneous_ctfe.rs new file mode 100644 index 00000000000..1ec271401fb --- /dev/null +++ b/src/test/ui/consts/nested_erroneous_ctfe.rs @@ -0,0 +1,4 @@ +fn main() { + [9; || [9; []]]; + //~^ ERROR: mismatched types +} diff --git a/src/test/ui/consts/nested_erroneous_ctfe.stderr b/src/test/ui/consts/nested_erroneous_ctfe.stderr new file mode 100644 index 00000000000..d579a54e983 --- /dev/null +++ b/src/test/ui/consts/nested_erroneous_ctfe.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/nested_erroneous_ctfe.rs:2:16 + | +LL | [9; || [9; []]]; + | ^^ expected `usize`, found array of 0 elements + | + = note: expected type `usize` + found array `[_; 0]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs index 2e1d5d26b5c..852a5b3b46a 100644 --- a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -5,15 +5,9 @@ fn main() { match &b""[..] { - ZST => {} //~ ERROR could not evaluate constant pattern - //~| ERROR could not evaluate constant pattern + ZST => {} } } const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; -//~^ ERROR any use of this value will cause an error -//~| ERROR cannot transmute between types of different sizes -//~| WARN this was previously accepted by the compiler but is being phased out - -// Once the `any use of this value will cause an error` disappears in this test, make sure to -// remove the `TransmuteSizeDiff` error variant and make its emitter site an assertion again. +//~^ ERROR cannot transmute between types of different sizes diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr index 27cc2f5e66a..4e8470173a1 100644 --- a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -1,23 +1,5 @@ -error: any use of this value will cause an error - --> $DIR/transmute-size-mismatch-before-typeck.rs:13:29 - | -LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; - | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^--- - | | - | transmuting `usize` to `&[u8]` is not possible, because these types do not have the same size - | - = note: `#[deny(const_err)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> - -error: could not evaluate constant pattern - --> $DIR/transmute-size-mismatch-before-typeck.rs:8:9 - | -LL | ZST => {} - | ^^^ - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-size-mismatch-before-typeck.rs:13:29 + --> $DIR/transmute-size-mismatch-before-typeck.rs:12:29 | LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^ @@ -25,12 +7,6 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; = note: source type: `usize` (word size) = note: target type: `&[u8]` (2 * word size) -error: could not evaluate constant pattern - --> $DIR/transmute-size-mismatch-before-typeck.rs:8:9 - | -LL | ZST => {} - | ^^^ - -error: aborting due to 4 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/ui/derives/issue-97343.rs b/src/test/ui/derives/issue-97343.rs new file mode 100644 index 00000000000..adec6c7a5c5 --- /dev/null +++ b/src/test/ui/derives/issue-97343.rs @@ -0,0 +1,8 @@ +use std::fmt::Debug; + +#[derive(Debug)] +pub struct Irrelevant<Irrelevant> { //~ ERROR type arguments are not allowed for this type + irrelevant: Irrelevant, +} + +fn main() {} diff --git a/src/test/ui/derives/issue-97343.stderr b/src/test/ui/derives/issue-97343.stderr new file mode 100644 index 00000000000..eedd54f1e9f --- /dev/null +++ b/src/test/ui/derives/issue-97343.stderr @@ -0,0 +1,13 @@ +error[E0109]: type arguments are not allowed for this type + --> $DIR/issue-97343.rs:4:23 + | +LL | #[derive(Debug)] + | ----- in this derive macro expansion +LL | pub struct Irrelevant<Irrelevant> { + | ^^^^^^^^^^ type argument not allowed + | + = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/drop/repeat-drop-2.rs b/src/test/ui/drop/repeat-drop-2.rs new file mode 100644 index 00000000000..2e7855328ec --- /dev/null +++ b/src/test/ui/drop/repeat-drop-2.rs @@ -0,0 +1,15 @@ +fn borrowck_catch() { + let foo = String::new(); + let _bar = foo; + let _baz = [foo; 0]; //~ ERROR use of moved value: `foo` [E0382] +} + +const _: [String; 0] = [String::new(); 0]; +//~^ ERROR destructors cannot be evaluated at compile-time [E0493] + +fn must_be_init() { + let x: u8; + let _ = [x; 0]; //~ ERROR: use of possibly-uninitialized variable: `x` +} + +fn main() {} diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr new file mode 100644 index 00000000000..cdc58180c37 --- /dev/null +++ b/src/test/ui/drop/repeat-drop-2.stderr @@ -0,0 +1,29 @@ +error[E0382]: use of moved value: `foo` + --> $DIR/repeat-drop-2.rs:4:17 + | +LL | let foo = String::new(); + | --- move occurs because `foo` has type `String`, which does not implement the `Copy` trait +LL | let _bar = foo; + | --- value moved here +LL | let _baz = [foo; 0]; + | ^^^ value used here after move + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/repeat-drop-2.rs:7:25 + | +LL | const _: [String; 0] = [String::new(); 0]; + | -^^^^^^^^^^^^^---- + | || + | |constants cannot evaluate destructors + | value is dropped here + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/repeat-drop-2.rs:12:14 + | +LL | let _ = [x; 0]; + | ^ use of possibly-uninitialized `x` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0381, E0382, E0493. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/drop/repeat-drop.rs b/src/test/ui/drop/repeat-drop.rs new file mode 100644 index 00000000000..03e832adb3b --- /dev/null +++ b/src/test/ui/drop/repeat-drop.rs @@ -0,0 +1,120 @@ +// run-pass +// ignore-wasm32-bare no unwinding panic +// ignore-avr no unwinding panic +// ignore-nvptx64 no unwinding panic + +static mut CHECK: usize = 0; + +struct DropChecker(usize); + +impl Drop for DropChecker { + fn drop(&mut self) { + unsafe { + if CHECK != self.0 - 1 { + panic!("Found {}, should have found {}", CHECK, self.0 - 1); + } + CHECK = self.0; + } + } +} + +macro_rules! check_drops { + ($l:literal) => { + unsafe { assert_eq!(CHECK, $l) } + }; +} + +struct DropPanic; + +impl Drop for DropPanic { + fn drop(&mut self) { + panic!() + } +} + +fn value_zero() { + unsafe { CHECK = 0 }; + let foo = DropChecker(1); + let v: [DropChecker; 0] = [foo; 0]; + check_drops!(1); + std::mem::drop(v); + check_drops!(1); +} + +fn value_one() { + unsafe { CHECK = 0 }; + let foo = DropChecker(1); + let v: [DropChecker; 1] = [foo; 1]; + check_drops!(0); + std::mem::drop(v); + check_drops!(1); +} + +const DROP_CHECKER: DropChecker = DropChecker(1); + +fn const_zero() { + unsafe { CHECK = 0 }; + let v: [DropChecker; 0] = [DROP_CHECKER; 0]; + check_drops!(0); + std::mem::drop(v); + check_drops!(0); +} + +fn const_one() { + unsafe { CHECK = 0 }; + let v: [DropChecker; 1] = [DROP_CHECKER; 1]; + check_drops!(0); + std::mem::drop(v); + check_drops!(1); +} + +fn const_generic_zero<const N: usize>() { + unsafe { CHECK = 0 }; + let v: [DropChecker; N] = [DROP_CHECKER; N]; + check_drops!(0); + std::mem::drop(v); + check_drops!(0); +} + +fn const_generic_one<const N: usize>() { + unsafe { CHECK = 0 }; + let v: [DropChecker; N] = [DROP_CHECKER; N]; + check_drops!(0); + std::mem::drop(v); + check_drops!(1); +} + +// Make sure that things are allowed to promote as expected + +fn allow_promote() { + unsafe { CHECK = 0 }; + let foo = DropChecker(1); + let v: &'static [DropChecker; 0] = &[foo; 0]; + check_drops!(1); + std::mem::drop(v); + check_drops!(1); +} + +// Verify that unwinding in the drop causes the right things to drop in the right order +fn on_unwind() { + unsafe { CHECK = 0 }; + std::panic::catch_unwind(|| { + let panic = DropPanic; + let _local = DropChecker(2); + let _v = (DropChecker(1), [panic; 0]); + std::process::abort(); + }) + .unwrap_err(); + check_drops!(2); +} + +fn main() { + value_zero(); + value_one(); + const_zero(); + const_one(); + const_generic_zero::<0>(); + const_generic_one::<1>(); + allow_promote(); + on_unwind(); +} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-compact.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-compact.rs new file mode 100644 index 00000000000..df81b7d2297 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-compact.rs @@ -0,0 +1,13 @@ +#[cfg(target(os = "x"))] //~ ERROR compact `cfg(target(..))` is experimental +struct Foo(u64, u64); + +#[cfg_attr(target(os = "x"), x)] //~ ERROR compact `cfg(target(..))` is experimental +struct Bar(u64, u64); + +#[cfg(not(any(all(target(os = "x")))))] //~ ERROR compact `cfg(target(..))` is experimental +fn foo() {} + +fn main() { + cfg!(target(os = "x")); + //~^ ERROR compact `cfg(target(..))` is experimental and subject to change +} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-compact.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-compact.stderr new file mode 100644 index 00000000000..be6fe23ded1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-compact.stderr @@ -0,0 +1,39 @@ +error[E0658]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-compact.rs:1:7 + | +LL | #[cfg(target(os = "x"))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information + = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable + +error[E0658]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-compact.rs:4:12 + | +LL | #[cfg_attr(target(os = "x"), x)] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information + = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable + +error[E0658]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-compact.rs:7:19 + | +LL | #[cfg(not(any(all(target(os = "x")))))] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information + = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable + +error[E0658]: compact `cfg(target(..))` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-compact.rs:11:10 + | +LL | cfg!(target(os = "x")); + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #96901 <https://github.com/rust-lang/rust/issues/96901> for more information + = help: add `#![feature(cfg_target_compact)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/native-library-link-flags/modifiers-override-3.rs b/src/test/ui/native-library-link-flags/modifiers-override-3.rs new file mode 100644 index 00000000000..b28c53c6b0a --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-3.rs @@ -0,0 +1,7 @@ +// Regression test for issue #97299, one command line library with modifiers +// overrides another command line library with modifiers. + +// compile-flags:-lstatic:+whole-archive=foo -lstatic:+whole-archive=foo +// error-pattern: overriding linking modifiers from command line is not supported + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/modifiers-override-3.stderr b/src/test/ui/native-library-link-flags/modifiers-override-3.stderr new file mode 100644 index 00000000000..365e5618100 --- /dev/null +++ b/src/test/ui/native-library-link-flags/modifiers-override-3.stderr @@ -0,0 +1,4 @@ +error: overriding linking modifiers from command line is not supported + +error: aborting due to previous error + diff --git a/src/test/ui/parser/else-no-if.stderr b/src/test/ui/parser/else-no-if.stderr index 27abbadd7ad..b9c1a75276c 100644 --- a/src/test/ui/parser/else-no-if.stderr +++ b/src/test/ui/parser/else-no-if.stderr @@ -6,14 +6,10 @@ LL | } else false { | | | expected an `if` or a block after this `else` | -help: add an `if` if this is the condition to an chained `if` statement after the `else` +help: add an `if` if this is the condition of a chained `else if` statement | LL | } else if false { | ++ -help: ... otherwise, place this expression inside of a block if it is not an `if` condition - | -LL | } else { false } { - | + + error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:10:12 @@ -23,14 +19,10 @@ LL | } else falsy() { | | | expected an `if` or a block after this `else` | -help: add an `if` if this is the condition to an chained `if` statement after the `else` +help: add an `if` if this is the condition of a chained `else if` statement | LL | } else if falsy() { | ++ -help: ... otherwise, place this expression inside of a block if it is not an `if` condition - | -LL | } else { falsy() } { - | + + error: expected `{`, found `falsy` --> $DIR/else-no-if.rs:17:12 diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index 0045d608133..43e33cbb120 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -4,6 +4,7 @@ use std::arch::asm; #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` +//~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn f() { asm!("", options(noreturn)); @@ -13,6 +14,7 @@ struct S; impl S { #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` + //~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn g() { asm!("", options(noreturn)); diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr index d33aecc0f97..3f7d0df42a0 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -5,11 +5,24 @@ LL | #[track_caller] | ^^^^^^^^^^^^^^^ error[E0736]: cannot use `#[track_caller]` with `#[naked]` - --> $DIR/error-with-naked.rs:15:5 + --> $DIR/error-with-naked.rs:16:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:6:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/error-with-naked.rs:16:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0736`. +Some errors have detailed explanations: E0736, E0737. +For more information about an error, try `rustc --explain E0736`. diff --git a/src/test/ui/traits/issue-82830.rs b/src/test/ui/traits/issue-82830.rs new file mode 100644 index 00000000000..c8289b2e30b --- /dev/null +++ b/src/test/ui/traits/issue-82830.rs @@ -0,0 +1,16 @@ +trait A<Y, N> { + type B; +} + +type MaybeBox<T> = <T as A<T, Box<T>>>::B; +struct P { + t: MaybeBox<P>, //~ ERROR: overflow evaluating the requirement `P: Sized` +} + +impl<Y, N> A<Y, N> for P { + type B = N; +} + +fn main() { + let t: MaybeBox<P>; +} diff --git a/src/test/ui/traits/issue-82830.stderr b/src/test/ui/traits/issue-82830.stderr new file mode 100644 index 00000000000..f863143c738 --- /dev/null +++ b/src/test/ui/traits/issue-82830.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `P: Sized` + --> $DIR/issue-82830.rs:7:8 + | +LL | t: MaybeBox<P>, + | ^^^^^^^^^^^ + | +note: required because of the requirements on the impl of `A<P, Box<P>>` for `P` + --> $DIR/issue-82830.rs:10:12 + | +LL | impl<Y, N> A<Y, N> for P { + | ^^^^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/type-alias-impl-trait/issue-53092-2.rs b/src/test/ui/type-alias-impl-trait/issue-53092-2.rs new file mode 100644 index 00000000000..438ac35fdea --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092-2.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +type Bug<T, U> = impl Fn(T) -> U + Copy; //~ ERROR cycle detected + +const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; +//~^ ERROR: cannot transmute + +fn make_bug<T, U: From<T>>() -> Bug<T, U> { + |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied +} + +fn main() { + CONST_BUG(0); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr new file mode 100644 index 00000000000..f4a0cdb1625 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -0,0 +1,55 @@ +error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` + --> $DIR/issue-53092-2.rs:4:18 + | +LL | type Bug<T, U> = impl Fn(T) -> U + Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `CONST_BUG`... + --> $DIR/issue-53092-2.rs:6:1 + | +LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `Bug<u8, ()>`... + = note: ...which requires normalizing `Bug<u8, ()>`... + = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/issue-53092-2.rs:1:1 + | +LL | / #![feature(type_alias_impl_trait)] +LL | | #![allow(dead_code)] +LL | | +LL | | type Bug<T, U> = impl Fn(T) -> U + Copy; +... | +LL | | CONST_BUG(0); +LL | | } + | |_^ + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/issue-53092-2.rs:6:41 + | +LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:71]` (0 bits) + = note: target type: `Bug<u8, ()>` (size can vary because of [type error]) + +error[E0277]: the trait bound `U: From<T>` is not satisfied + --> $DIR/issue-53092-2.rs:10:5 + | +LL | |x| x.into() + | ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U` + | +note: required by a bound in `make_bug` + --> $DIR/issue-53092-2.rs:9:19 + | +LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> { + | ^^^^^^^ required by this bound in `make_bug` +help: consider restricting type parameter `U` + | +LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy; + | +++++++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0391, E0512. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.rs b/src/test/ui/type-alias-impl-trait/issue-53092.rs index 45792ba97a7..1be5b46d6df 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53092.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53092.rs @@ -3,7 +3,12 @@ type Bug<T, U> = impl Fn(T) -> U + Copy; -const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; +union Moo { + x: Bug<u8, ()>, + y: (), +} + +const CONST_BUG: Bug<u8, ()> = unsafe { Moo { y: () }.x }; fn make_bug<T, U: From<T>>() -> Bug<T, U> { |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.stderr b/src/test/ui/type-alias-impl-trait/issue-53092.stderr index 2d423a0c0df..2109cf8a784 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53092.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-53092.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `U: From<T>` is not satisfied - --> $DIR/issue-53092.rs:9:5 + --> $DIR/issue-53092.rs:14:5 | LL | |x| x.into() | ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U` | note: required by a bound in `make_bug` - --> $DIR/issue-53092.rs:8:19 + --> $DIR/issue-53092.rs:13:19 | LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> { | ^^^^^^^ required by this bound in `make_bug` diff --git a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs index fa578eced5f..46621362e4f 100644 --- a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs +++ b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs @@ -3,13 +3,17 @@ #![feature(type_alias_impl_trait)] -type Foo = impl Copy; //~ unconstrained opaque type +mod foo { + pub type Foo = impl Copy; + //~^ ERROR unconstrained opaque type -// make compiler happy about using 'Foo' -fn bar(x: Foo) -> Foo { - x + // make compiler happy about using 'Foo' + pub fn bar(x: Foo) -> Foo { + x + } } fn main() { - let _: Foo = std::mem::transmute(0u8); + let _: foo::Foo = std::mem::transmute(0u8); + //~^ ERROR cannot transmute between types of different sizes, or dependently-sized types } diff --git a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr index 009935347e6..337708b8765 100644 --- a/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr @@ -1,10 +1,20 @@ error: unconstrained opaque type - --> $DIR/no_inferrable_concrete_type.rs:6:12 + --> $DIR/no_inferrable_concrete_type.rs:7:20 | -LL | type Foo = impl Copy; - | ^^^^^^^^^ +LL | pub type Foo = impl Copy; + | ^^^^^^^^^ | = note: `Foo` must be used in combination with a concrete type within the same module -error: aborting due to previous error +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/no_inferrable_concrete_type.rs:17:23 + | +LL | let _: foo::Foo = std::mem::transmute(0u8); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `Foo` (size can vary because of [type error]) + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.rs b/src/test/ui/type/type-check/unknown_type_for_closure.rs index 0dbf82453a2..0089d86e340 100644 --- a/src/test/ui/type/type-check/unknown_type_for_closure.rs +++ b/src/test/ui/type/type-check/unknown_type_for_closure.rs @@ -1,3 +1,17 @@ -fn main() { - let x = |_| { }; //~ ERROR type annotations needed +fn infer_in_arg() { + let x = |b: Vec<_>| {}; //~ ERROR E0282 } + +fn empty_pattern() { + let x = |_| {}; //~ ERROR type annotations needed +} + +fn infer_ty() { + let x = |k: _| {}; //~ ERROR type annotations needed +} + +fn ambig_return() { + let x = || -> Vec<_> { Vec::new() }; //~ ERROR type annotations needed for the closure `fn() -> Vec<_>` +} + +fn main() {} diff --git a/src/test/ui/type/type-check/unknown_type_for_closure.stderr b/src/test/ui/type/type-check/unknown_type_for_closure.stderr index 5971f56c97f..c3accad5f25 100644 --- a/src/test/ui/type/type-check/unknown_type_for_closure.stderr +++ b/src/test/ui/type/type-check/unknown_type_for_closure.stderr @@ -1,9 +1,32 @@ -error[E0282]: type annotations needed +error[E0282]: type annotations needed for `Vec<_>` --> $DIR/unknown_type_for_closure.rs:2:14 | -LL | let x = |_| { }; +LL | let x = |b: Vec<_>| {}; | ^ consider giving this closure parameter a type -error: aborting due to previous error +error[E0282]: type annotations needed + --> $DIR/unknown_type_for_closure.rs:6:14 + | +LL | let x = |_| {}; + | ^ consider giving this closure parameter a type + +error[E0282]: type annotations needed + --> $DIR/unknown_type_for_closure.rs:10:14 + | +LL | let x = |k: _| {}; + | ^ consider giving this closure parameter a type + +error[E0282]: type annotations needed for the closure `fn() -> Vec<_>` + --> $DIR/unknown_type_for_closure.rs:14:28 + | +LL | let x = || -> Vec<_> { Vec::new() }; + | ^^^^^^^^ cannot infer type for type parameter `T` + | +help: give this closure an explicit return type without `_` placeholders + | +LL | let x = || -> Vec<_> { Vec::new() }; + | ~~~~~~ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0282`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a4c1cd0eb6b18082a7e693f5a665548fe1534be +Subproject 39ad1039d9e3e1746177bf5d134af4c164f9552 diff --git a/src/tools/lld-wrapper/Cargo.toml b/src/tools/lld-wrapper/Cargo.toml index 66a586fd6c3..bf5138b16d5 100644 --- a/src/tools/lld-wrapper/Cargo.toml +++ b/src/tools/lld-wrapper/Cargo.toml @@ -3,9 +3,3 @@ name = "lld-wrapper" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" - -[dependencies] - -[features] -ld = [] -ld64 = [] \ No newline at end of file diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 8d19a054a1d..90bd24a75e0 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -1,5 +1,4 @@ -//! Script to invoke the bundled rust-lld with the correct flavor. The flavor is selected by -//! feature. +//! Script to invoke the bundled rust-lld with the correct flavor. //! //! lld supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first //! two arguments the `<flavor>` command line interface is used to process the remaining arguments. @@ -8,59 +7,33 @@ //! In Rust with `-Z gcc-ld=lld` we have gcc or clang invoke rust-lld. Since there is no way to //! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation //! and since Windows does not support symbolic links for files this wrapper is used in place of a -//! symbolic link. It execs `../rust-lld -flavor ld` if the feature `ld` is enabled and -//! `../rust-lld -flavor ld64` if `ld64` is enabled. On Windows it spawns a `..\rust-lld.exe` +//! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument +//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe` //! child process. -#[cfg(not(any(feature = "ld", feature = "ld64")))] -compile_error!("One of the features ld and ld64 must be enabled."); - -#[cfg(all(feature = "ld", feature = "ld64"))] -compile_error!("Only one of the feature ld or ld64 can be enabled."); - -#[cfg(feature = "ld")] -const FLAVOR: &str = "ld"; - -#[cfg(feature = "ld64")] -const FLAVOR: &str = "ld64"; - -use std::env; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process; +use std::{env, process}; -trait ResultExt<T, E> { +trait UnwrapOrExitWith<T> { fn unwrap_or_exit_with(self, context: &str) -> T; } -impl<T, E> ResultExt<T, E> for Result<T, E> -where - E: Display, -{ +impl<T> UnwrapOrExitWith<T> for Option<T> { fn unwrap_or_exit_with(self, context: &str) -> T { - match self { - Ok(t) => t, - Err(e) => { - eprintln!("lld-wrapper: {}: {}", context, e); - process::exit(1); - } - } + self.unwrap_or_else(|| { + eprintln!("lld-wrapper: {}", context); + process::exit(1); + }) } } -trait OptionExt<T> { - fn unwrap_or_exit_with(self, context: &str) -> T; -} - -impl<T> OptionExt<T> for Option<T> { +impl<T, E: Display> UnwrapOrExitWith<T> for Result<T, E> { fn unwrap_or_exit_with(self, context: &str) -> T { - match self { - Some(t) => t, - None => { - eprintln!("lld-wrapper: {}", context); - process::exit(1); - } - } + self.unwrap_or_else(|err| { + eprintln!("lld-wrapper: {}: {}", context, err); + process::exit(1); + }) } } @@ -81,14 +54,28 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { } /// Returns the command for invoking rust-lld with the correct flavor. +/// LLD only accepts the flavor argument at the first two arguments, so move it there. /// /// Exits on error. fn get_rust_lld_command(current_exe_path: &Path) -> process::Command { let rust_lld_path = get_rust_lld_path(current_exe_path); let mut command = process::Command::new(rust_lld_path); + + let mut flavor = None; + let args = env::args_os() + .skip(1) + .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) { + Some(suffix) => { + flavor = Some(suffix.to_string()); + false + } + None => true, + }) + .collect::<Vec<_>>(); + command.arg("-flavor"); - command.arg(FLAVOR); - command.args(env::args_os().skip(1)); + command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor=<flavor> is not passed")); + command.args(args); command } @@ -101,20 +88,14 @@ fn exec_lld(mut command: process::Command) { #[cfg(not(unix))] fn exec_lld(mut command: process::Command) { - // Windows has no exec(), spawn a child process and wait for it + // Windows has no exec(), spawn a child process and wait for it. let exit_status = command.status().unwrap_or_exit_with("error running rust-lld child process"); - if !exit_status.success() { - match exit_status.code() { - Some(code) => { - // return the original lld exit code - process::exit(code) - } - None => { - eprintln!("lld-wrapper: rust-lld child process exited with error: {}", exit_status,); - process::exit(1); - } - } - } + let code = exit_status + .code() + .ok_or(exit_status) + .unwrap_or_exit_with("rust-lld child process exited with error"); + // Return the original lld exit code. + process::exit(code); } fn main() { diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 8532410a1bf..4599e12de5f 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -19,6 +19,7 @@ function showHelp() { console.log(" --help : show this message then quit"); console.log(" --tests-folder [PATH] : location of the .GOML tests folder"); console.log(" --jobs [NUMBER] : number of threads to run tests on"); + console.log(" --executable-path [PATH] : path of the browser's executable to be used"); } function isNumeric(s) { @@ -34,6 +35,8 @@ function parseOptions(args) { "show_text": false, "no_headless": false, "jobs": -1, + "executable_path": null, + "no_sandbox": false, }; var correspondances = { "--doc-folder": "doc_folder", @@ -41,13 +44,16 @@ function parseOptions(args) { "--debug": "debug", "--show-text": "show_text", "--no-headless": "no_headless", + "--executable-path": "executable_path", + "--no-sandbox": "no_sandbox", }; for (var i = 0; i < args.length; ++i) { if (args[i] === "--doc-folder" || args[i] === "--tests-folder" || args[i] === "--file" - || args[i] === "--jobs") { + || args[i] === "--jobs" + || args[i] === "--executable-path") { i += 1; if (i >= args.length) { console.log("Missing argument after `" + args[i - 1] + "` option."); @@ -68,6 +74,9 @@ function parseOptions(args) { } else if (args[i] === "--help") { showHelp(); process.exit(0); + } else if (args[i] === "--no-sandbox") { + console.log("`--no-sandbox` is being used. Be very careful!"); + opts[correspondances[args[i]]] = true; } else if (correspondances[args[i]]) { opts[correspondances[args[i]]] = true; } else { @@ -147,10 +156,17 @@ async function main(argv) { if (opts["show_text"]) { args.push("--show-text"); } + if (opts["no_sandbox"]) { + args.push("--no-sandbox"); + } if (opts["no_headless"]) { args.push("--no-headless"); headless = false; } + if (opts["executable_path"] !== null) { + args.push("--executable-path"); + args.push(opts["executable_path"]); + } options.parseArguments(args); } catch (error) { console.error(`invalid argument: ${error}`); diff --git a/triagebot.toml b/triagebot.toml index a5724ddfb88..e161adcd6e0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -80,6 +80,13 @@ resolved/implemented on Fuchsia. Could one of you weigh in? """ label = "O-fuchsia" +[ping.macos] +message = """\ +Hey MacOS Group! This issue or PR could use some MacOS-specific guidance. Could one +of you weigh in? Thanks <3 +""" +label = "O-macos" + [prioritize] label = "I-prioritize" |
