checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
dependencies = [
"compiler_builtins",
- "gimli",
+ "gimli 0.25.0",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
[[package]]
name = "anyhow"
-version = "1.0.34"
+version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
[[package]]
name = "array_tool"
dependencies = [
"directories",
"rustc-workspace-hack",
- "rustc_version 0.3.3",
+ "rustc_version",
"serde",
"serde_json",
"vergen",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
[[package]]
name = "filetime"
version = "0.2.14"
"rustc-std-workspace-core",
]
+[[package]]
+name = "gimli"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+dependencies = [
+ "fallible-iterator",
+ "indexmap",
+ "stable_deref_trait",
+]
+
[[package]]
name = "git2"
version = "0.13.23"
[[package]]
name = "gsgdt"
-version = "0.1.3"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60"
+checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825"
dependencies = [
"serde",
]
"measureme 9.1.2",
"rand 0.8.4",
"rustc-workspace-hack",
- "rustc_version 0.4.0",
+ "rustc_version",
"shell-escape",
"smallvec",
]
"rustc-std-workspace-core",
]
+[[package]]
+name = "object"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "indexmap",
+ "memchr",
+]
+
[[package]]
name = "odht"
version = "0.3.1"
"itertools 0.9.0",
"jobserver",
"libc",
- "object",
+ "object 0.26.2",
"pathdiff",
"regex",
"rustc_apfloat",
+ "rustc_arena",
"rustc_ast",
"rustc_attr",
"rustc_data_structures",
"smallvec",
"snap",
"tempfile",
+ "thorin-dwp",
"tracing",
]
name = "rustc_driver"
version = "0.0.0"
dependencies = [
- "atty",
"libc",
"rustc_ast",
"rustc_ast_pretty",
"rustc_hir_pretty",
"rustc_interface",
"rustc_lint",
+ "rustc_log",
"rustc_metadata",
"rustc_middle",
"rustc_parse",
"rustc_target",
"rustc_typeck",
"tracing",
- "tracing-subscriber",
- "tracing-tree",
"winapi",
]
"libc",
]
+[[package]]
+name = "rustc_log"
+version = "0.0.0"
+dependencies = [
+ "atty",
+ "rustc_span",
+ "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
+]
+
[[package]]
name = "rustc_macros"
version = "0.1.0"
"tracing",
]
-[[package]]
-name = "rustc_version"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
-dependencies = [
- "semver 0.11.0",
-]
-
[[package]]
name = "rustc_version"
version = "0.4.0"
"hermit-abi",
"libc",
"miniz_oxide",
- "object",
+ "object 0.26.2",
"panic_abort",
"panic_unwind",
"profiler_builtins",
[[package]]
name = "structopt"
-version = "0.3.16"
+version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de5472fb24d7e80ae84a7801b7978f95a19ec32cb1876faea59ab711eb901976"
+checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [
"clap",
"lazy_static",
[[package]]
name = "structopt-derive"
-version = "0.4.9"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0eb37335aeeebe51be42e2dc07f031163fbabfa6ac67d7ea68b5c2f68d5f99"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
[[package]]
name = "thiserror"
-version = "1.0.20"
+version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.20"
+version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
+[[package]]
+name = "thorin-dwp"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039d1fc0bfdb73910c2702893515580e38c192f47a987bc98ddd38a36f2d953a"
+dependencies = [
+ "gimli 0.26.1",
+ "indexmap",
+ "object 0.27.1",
+ "tracing",
+]
+
[[package]]
name = "thread_local"
version = "1.0.1"
[[package]]
name = "tracing"
-version = "0.1.28"
+version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [
"cfg-if 1.0.0",
"pin-project-lite",
[[package]]
name = "tracing-attributes"
-version = "0.1.17"
+version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650"
+checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
dependencies = [
"proc-macro2",
"quote",
pub attrs: Vec<Attribute>,
pub items: Vec<P<Item>>,
pub span: Span,
- // Placeholder ID if the crate node is a macro placeholder.
- pub is_placeholder: Option<NodeId>,
+ /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
+ /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that.
+ pub id: NodeId,
+ pub is_placeholder: bool,
}
/// Possible values inside of compile-time attribute lists.
}
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
- let Crate { attrs, items, span, is_placeholder: _ } = krate;
+ let Crate { attrs, items, span, id, is_placeholder: _ } = krate;
+ vis.visit_id(id);
visit_attrs(attrs, vis);
items.flat_map_in_place(|item| vis.flat_map_item(item));
vis.visit_span(span);
attrs: Default::default(),
items: Default::default(),
span: Default::default(),
+ id: DUMMY_NODE_ID,
is_placeholder: Default::default(),
}
}
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = self.lower_expr(expr);
- let count = self.lower_anon_const(count);
+ let count = self.lower_array_length(count);
hir::ExprKind::Repeat(expr, count)
}
ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
use rustc_span::hygiene::ExpnId;
))
}
TyKind::Array(ref ty, ref length) => {
- hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+ hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
}
TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
TyKind::TraitObject(ref bounds, kind) => {
self.expr_block(block, AttrVec::new())
}
+ fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+ match c.value.kind {
+ ExprKind::Underscore => {
+ if self.sess.features_untracked().generic_arg_infer {
+ hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+ } else {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::generic_arg_infer,
+ c.value.span,
+ "using `_` for array lengths is unstable",
+ )
+ .emit();
+ hir::ArrayLen::Body(self.lower_anon_const(c))
+ }
+ }
+ _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+ }
+ }
+
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
self.with_new_scopes(|this| hir::AnonConst {
hir_id: this.lower_node_id(c.id),
self.print_visibility(&item.vis);
self.print_defaultness(defaultness);
self.print_unsafety(unsafety);
- self.word_nbsp("impl");
- self.print_constness(constness);
+ self.word("impl");
- if !generics.params.is_empty() {
+ if generics.params.is_empty() {
+ self.nbsp();
+ } else {
self.print_generic_params(&generics.params);
self.space();
}
+ self.print_constness(constness);
+
if let ast::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
use rustc_fs_util::{link_or_copy, path_to_c_string};
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::InnerSpan;
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
- tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name))
+ tcx.output_filenames(()).split_dwarf_path(
+ tcx.sess.split_debuginfo(),
+ tcx.sess.opts.debugging_opts.split_dwarf_kind,
+ Some(mod_name),
+ )
} else {
None
};
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
- let dwo_out = match cgcx.split_debuginfo {
- // Don't change how DWARF is emitted in single mode (or when disabled).
- SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
- // Emit (a subset of the) DWARF into a separate file in split mode.
- SplitDebuginfo::Unpacked => {
- if cgcx.target_can_use_split_dwarf {
- Some(dwo_out.as_path())
- } else {
- None
- }
- }
+ let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) {
+ // Don't change how DWARF is emitted when disabled.
+ (SplitDebuginfo::Off, _) => None,
+ // Don't provide a DWARF object path if split debuginfo is enabled but this is
+ // a platform that doesn't support Split DWARF.
+ _ if !cgcx.target_can_use_split_dwarf => None,
+ // Don't provide a DWARF object path in single mode, sections will be written
+ // into the object as normal but ignored by linker.
+ (_, SplitDwarfKind::Single) => None,
+ // Emit (a subset of the) DWARF into a separate dwarf object file in split
+ // mode.
+ (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
};
with_codegen(tm, llmod, config.no_builtins, |cpm| {
Ok(module.into_compiled_module(
config.emit_obj != EmitObj::None,
- cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+ cgcx.target_can_use_split_dwarf
+ && cgcx.split_debuginfo != SplitDebuginfo::Off
+ && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
config.emit_bc,
&cgcx.output_filenames,
))
let output_filenames = tcx.output_filenames(());
let split_name = if tcx.sess.target_can_use_split_dwarf() {
output_filenames
- .split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+ .split_dwarf_path(
+ tcx.sess.split_debuginfo(),
+ tcx.sess.opts.debugging_opts.split_dwarf_kind,
+ Some(codegen_unit_name),
+ )
// We get a path relative to the working directory from split_dwarf_path
.map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
} else {
// the values should match the ones in the DWARF standard anyway.
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
- let mut addr_ops = SmallVec::<[_; 8]>::new();
+ let mut addr_ops = SmallVec::<[u64; 8]>::new();
if direct_offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
- addr_ops.push(direct_offset.bytes() as i64);
+ addr_ops.push(direct_offset.bytes() as u64);
}
for &offset in indirect_offsets {
addr_ops.push(op_deref());
if offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
- addr_ops.push(offset.bytes() as i64);
+ addr_ops.push(offset.bytes() as u64);
}
}
Builder: &DIBuilder<'a>,
Val: &'a Value,
VarInfo: &'a DIVariable,
- AddrOps: *const i64,
+ AddrOps: *const u64,
AddrOpsCount: c_uint,
DL: &'a DILocation,
InsertAtEnd: &'a BasicBlock,
Scope: &'a DIScope,
InlinedAt: Option<&'a DILocation>,
) -> &'a DILocation;
- pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
- pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
+ pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
+ pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
+thorin-dwp = "0.1.1"
pathdiff = "0.2.0"
snap = "1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
regex = "1.4"
rustc_serialize = { path = "../rustc_serialize" }
+rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
+use rustc_arena::TypedArena;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{ErrorReported, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
use rustc_session::search_paths::PathKind;
use regex::Regex;
use tempfile::Builder as TempFileBuilder;
-use std::ffi::{OsStr, OsString};
+use std::borrow::Borrow;
+use std::ffi::OsString;
+use std::fs::{File, OpenOptions};
+use std::io::{BufWriter, Write};
use std::lazy::OnceCell;
use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
}
}
- // Remove the temporary object file and metadata if we aren't saving temps
+ // Remove the temporary object file and metadata if we aren't saving temps.
sess.time("link_binary_remove_temps", || {
- if !sess.opts.cg.save_temps {
- let remove_temps_from_module = |module: &CompiledModule| {
- if let Some(ref obj) = module.object {
- ensure_removed(sess.diagnostic(), obj);
- }
-
- if let Some(ref obj) = module.dwarf_object {
- ensure_removed(sess.diagnostic(), obj);
- }
- };
+ // If the user requests that temporaries are saved, don't delete any.
+ if sess.opts.cg.save_temps {
+ return;
+ }
- if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
- for module in &codegen_results.modules {
- remove_temps_from_module(module);
- }
+ let remove_temps_from_module = |module: &CompiledModule| {
+ if let Some(ref obj) = module.object {
+ ensure_removed(sess.diagnostic(), obj);
}
+ };
+
+ // Otherwise, always remove the metadata and allocator module temporaries.
+ if let Some(ref metadata_module) = codegen_results.metadata_module {
+ remove_temps_from_module(metadata_module);
+ }
+
+ if let Some(ref allocator_module) = codegen_results.allocator_module {
+ remove_temps_from_module(allocator_module);
+ }
- if let Some(ref metadata_module) = codegen_results.metadata_module {
- remove_temps_from_module(metadata_module);
+ // If no requested outputs require linking, then the object temporaries should
+ // be kept.
+ if !sess.opts.output_types.should_link() {
+ return;
+ }
+
+ // Potentially keep objects for their debuginfo.
+ let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess);
+ debug!(?preserve_objects, ?preserve_dwarf_objects);
+
+ for module in &codegen_results.modules {
+ if !preserve_objects {
+ remove_temps_from_module(module);
}
- if let Some(ref allocator_module) = codegen_results.allocator_module {
- remove_temps_from_module(allocator_module);
+ if !preserve_dwarf_objects {
+ if let Some(ref obj) = module.dwarf_object {
+ ensure_removed(sess.diagnostic(), obj);
+ }
}
}
});
let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
- for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
- ab.add_file(obj);
+ for m in &codegen_results.modules {
+ if let Some(obj) = m.object.as_ref() {
+ ab.add_file(obj);
+ }
+
+ if let Some(dwarf_obj) = m.dwarf_object.as_ref() {
+ ab.add_file(dwarf_obj);
+ }
}
// Note that in this loop we are ignoring the value of `lib.cfg`. That is,
})
}
-const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
-
-/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp`
-/// file.
-fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I)
-where
- I: IntoIterator<Item: AsRef<OsStr>>,
-{
- info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
-
+/// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
+/// DWARF package.
+fn link_dwarf_object<'a>(
+ sess: &'a Session,
+ cg_results: &CodegenResults,
+ executable_out_filename: &Path,
+) {
let dwp_out_filename = executable_out_filename.with_extension("dwp");
- let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
- cmd.arg("-o");
- cmd.arg(&dwp_out_filename);
- cmd.args(object_files);
+ debug!(?dwp_out_filename, ?executable_out_filename);
- let mut new_path = sess.get_tools_search_paths(false);
- if let Some(path) = env::var_os("PATH") {
- new_path.extend(env::split_paths(&path));
+ #[derive(Default)]
+ struct ThorinSession<Relocations> {
+ arena_data: TypedArena<Vec<u8>>,
+ arena_mmap: TypedArena<Mmap>,
+ arena_relocations: TypedArena<Relocations>,
}
- let new_path = env::join_paths(new_path).unwrap();
- cmd.env("PATH", new_path);
- info!("{:?}", &cmd);
- match sess.time("run_dwp", || cmd.output()) {
- Ok(prog) if !prog.status.success() => {
- sess.struct_err(&format!(
- "linking dwarf objects with `{}` failed: {}",
- LLVM_DWP_EXECUTABLE, prog.status
- ))
- .note(&format!("{:?}", &cmd))
- .note(&escape_stdout_stderr_string(&prog.stdout))
- .note(&escape_stdout_stderr_string(&prog.stderr))
- .emit();
- info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
- info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
+ impl<Relocations> ThorinSession<Relocations> {
+ fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+ (*self.arena_mmap.alloc(data)).borrow()
}
- Ok(_) => {}
- Err(e) => {
- let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
- let mut err = if dwp_not_found {
- sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
- } else {
- sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
- };
+ }
- err.note(&e.to_string());
+ impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
+ fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+ (*self.arena_data.alloc(data)).borrow()
+ }
- if !dwp_not_found {
- err.note(&format!("{:?}", &cmd));
+ fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+ (*self.arena_relocations.alloc(data)).borrow()
+ }
+
+ fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+ let file = File::open(&path)?;
+ let mmap = (unsafe { Mmap::map(file) })?;
+ Ok(self.alloc_mmap(mmap))
+ }
+ }
+
+ match sess.time("run_thorin", || -> Result<(), thorin::Error> {
+ let thorin_sess = ThorinSession::default();
+ let mut package = thorin::DwarfPackage::new(&thorin_sess);
+
+ // Input objs contain .o/.dwo files from the current crate.
+ match sess.opts.debugging_opts.split_dwarf_kind {
+ SplitDwarfKind::Single => {
+ for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+ package.add_input_object(input_obj)?;
+ }
}
+ SplitDwarfKind::Split => {
+ for input_obj in cg_results.modules.iter().filter_map(|m| m.dwarf_object.as_ref()) {
+ package.add_input_object(input_obj)?;
+ }
+ }
+ }
- err.emit();
+ // Input rlibs contain .o/.dwo files from dependencies.
+ let input_rlibs = cg_results
+ .crate_info
+ .used_crate_source
+ .values()
+ .filter_map(|csource| csource.rlib.as_ref())
+ .map(|(path, _)| path);
+ for input_rlib in input_rlibs {
+ debug!(?input_rlib);
+ package.add_input_object(input_rlib)?;
+ }
+
+ // Failing to read the referenced objects is expected for dependencies where the path in the
+ // executable will have been cleaned by Cargo, but the referenced objects will be contained
+ // within rlibs provided as inputs.
+ //
+ // If paths have been remapped, then .o/.dwo files from the current crate also won't be
+ // found, but are provided explicitly above.
+ //
+ // Adding an executable is primarily done to make `thorin` check that all the referenced
+ // dwarf objects are found in the end.
+ package.add_executable(
+ &executable_out_filename,
+ thorin::MissingReferencedObjectBehaviour::Skip,
+ )?;
+
+ let output = package.finish()?.write()?;
+ let mut output_stream = BufWriter::new(
+ OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(dwp_out_filename)?,
+ );
+ output_stream.write_all(&output)?;
+ output_stream.flush()?;
+
+ Ok(())
+ }) {
+ Ok(()) => {}
+ Err(e) => {
+ sess.struct_err("linking dwarf objects with thorin failed")
+ .note(&format!("{:?}", e))
+ .emit();
}
}
}
SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
+ //
// We cannot rely on the .o paths in the exectuable because they may have been
- // remapped by --remap-path-prefix and therefore invalid. So we need to provide
- // the .o paths explicitly
- SplitDebuginfo::Packed => link_dwarf_object(
- sess,
- &out_filename,
- codegen_results.modules.iter().filter_map(|m| m.object.as_ref()),
- ),
+ // remapped by --remap-path-prefix and therefore invalid, so we need to provide
+ // the .o/.dwo paths explicitly.
+ SplitDebuginfo::Packed => link_dwarf_object(sess, codegen_results, out_filename),
}
let strip = strip_value(sess);
bug!("Not enough information provided to determine how to invoke the linker");
}
-/// Returns a boolean indicating whether we should preserve the object files on
-/// the filesystem for their debug information. This is often useful with
-/// split-dwarf like schemes.
-fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
+/// Returns a pair of boolean indicating whether we should preserve the object and
+/// dwarf object files on the filesystem for their debug information. This is often
+/// useful with split-dwarf like schemes.
+fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
// If the objects don't have debuginfo there's nothing to preserve.
if sess.opts.debuginfo == config::DebugInfo::None {
- return false;
+ return (false, false);
}
// If we're only producing artifacts that are archives, no need to preserve
// the objects as they're losslessly contained inside the archives.
- let output_linked =
- sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
- if !output_linked {
- return false;
+ if sess.crate_types().iter().all(|&x| x.is_archive()) {
+ return (false, false);
+ }
+
+ match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) {
+ // If there is no split debuginfo then do not preserve objects.
+ (SplitDebuginfo::Off, _) => (false, false),
+ // If there is packed split debuginfo, then the debuginfo in the objects
+ // has been packaged and the objects can be deleted.
+ (SplitDebuginfo::Packed, _) => (false, false),
+ // If there is unpacked split debuginfo and the current target can not use
+ // split dwarf, then keep objects.
+ (SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false),
+ // If there is unpacked split debuginfo and the target can use split dwarf, then
+ // keep the object containing that debuginfo (whether that is an object file or
+ // dwarf object file depends on the split dwarf kind).
+ (SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false),
+ (SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true),
}
-
- // "unpacked" split debuginfo means that we leave object files as the
- // debuginfo is found in the original object files themselves
- sess.split_debuginfo() == SplitDebuginfo::Unpacked
}
fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
use object::write::{self, StandardSegment, Symbol, SymbolSection};
use object::{
- elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags,
- SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+ elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
+ SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
};
use snap::write::FrameEncoder;
);
match file.format() {
BinaryFormat::Coff => {
- const IMAGE_SCN_LNK_REMOVE: u32 = 0;
file.section_mut(section).flags =
- SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+ SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE };
}
BinaryFormat::Elf => {
- const SHF_EXCLUDE: u64 = 0x80000000;
- file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+ file.section_mut(section).flags =
+ SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
}
_ => {}
};
module_name: &str,
) -> TargetMachineFactoryConfig {
let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
- cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name))
+ cgcx.output_filenames.split_dwarf_path(
+ cgcx.split_debuginfo,
+ cgcx.split_dwarf_kind,
+ Some(module_name),
+ )
} else {
None
};
pub target_arch: String,
pub debuginfo: config::DebugInfo,
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
+ pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
// Number of cgus excluding the allocator/metadata modules
pub total_cgus: usize,
target_arch: tcx.sess.target.arch.clone(),
debuginfo: tcx.sess.opts.debuginfo,
split_debuginfo: tcx.sess.split_debuginfo(),
+ split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind,
};
// This is the "main loop" of parallel work happening for parallel codegen.
cid.instance,
body,
Some(&ret.into()),
- StackPopCleanup::None { cleanup: false },
+ StackPopCleanup::Root { cleanup: false },
)?;
// The main interpreter loop.
/// `ret` stores the block we jump to on a normal return, while `unwind`
/// stores the block used for cleanup during unwinding.
Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
- /// Just do nothing: Used by Main and for TLS hooks in miri.
+ /// The root frame of the stack: nowhere else to jump to.
/// `cleanup` says whether locals are deallocated. Static computation
/// wants them leaked to intern what they need (and just throw away
/// the entire `ecx` when it is done).
- None { cleanup: bool },
+ Root { cleanup: bool },
}
/// State of a local variable including a memoized layout
// because this is CTFE and the final value will be thoroughly validated anyway.
let cleanup = match return_to_block {
StackPopCleanup::Goto { .. } => true,
- StackPopCleanup::None { cleanup, .. } => cleanup,
+ StackPopCleanup::Root { cleanup, .. } => cleanup,
};
if !cleanup {
// Follow the unwind edge.
let unwind = match return_to_block {
StackPopCleanup::Goto { unwind, .. } => unwind,
- StackPopCleanup::None { .. } => {
- panic!("Encountered StackPopCleanup::None when unwinding!")
+ StackPopCleanup::Root { .. } => {
+ panic!("encountered StackPopCleanup::Root when unwinding!")
}
};
self.unwind_to_block(unwind)
// Follow the normal return edge.
match return_to_block {
StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
- StackPopCleanup::None { .. } => Ok(()),
+ StackPopCleanup::Root { .. } => {
+ assert!(
+ self.stack().is_empty(),
+ "only the topmost frame can have StackPopCleanup::Root"
+ );
+ Ok(())
+ }
}
}
}
}
}
+macro_rules! dispatch_value {
+ ($target: expr, $value:expr) => {
+ let value = $value;
+ #[allow(unreachable_patterns)]
+ #[allow(overflowing_literals)]
+ match value {
+ 0..=0xFF => $target.short_write(value as u8),
+ 0x100..=0xFFFF => $target.short_write(value as u16),
+ 0x10000..=0xFFFFFFFF => $target.short_write(value as u32),
+ _ => $target.short_write(value as u64),
+ }
+ };
+}
+
impl Hasher for SipHasher128 {
#[inline]
fn write_u8(&mut self, i: u8) {
#[inline]
fn write_u32(&mut self, i: u32) {
- self.short_write(i);
+ dispatch_value!(self, i);
}
#[inline]
#[inline]
fn write_i64(&mut self, i: i64) {
- self.short_write(i as u64);
+ dispatch_value!(self, i as u64);
}
#[inline]
[dependencies]
libc = "0.2"
-atty = "0.2"
tracing = { version = "0.1.28" }
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+rustc_log = { path = "../rustc_log" }
rustc_middle = { path = "../rustc_middle" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_target = { path = "../rustc_target" }
[features]
llvm = ['rustc_interface/llvm']
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['rustc_log/max_level_info']
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
+use rustc_log::stdout_isatty;
use rustc_metadata::locator;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
#[derive(Copy, Clone)]
pub struct RustcDefaultCalls;
-fn stdout_isatty() -> bool {
- atty::is(atty::Stream::Stdout)
-}
-
-fn stderr_isatty() -> bool {
- atty::is(atty::Stream::Stderr)
-}
-
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
let upper_cased_code = code.to_ascii_uppercase();
let normalised = if upper_cased_code.starts_with('E') {
let wall = matches.opt_strs("W");
if wall.iter().any(|x| *x == "all") {
print_wall_help();
- return None;
+ rustc_errors::FatalError.raise();
}
// Don't handle -W help here, because we might first load plugins.
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
- init_env_logger("RUSTC_LOG")
+ if let Err(error) = rustc_log::init_rustc_env_logger() {
+ early_error(ErrorOutputType::default(), &error.to_string());
+ }
}
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
- use tracing_subscriber::{
- filter::{self, EnvFilter, LevelFilter},
- layer::SubscriberExt,
- };
-
- let filter = match std::env::var(env) {
- Ok(env) => EnvFilter::new(env),
- _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
- };
-
- let color_logs = match std::env::var(String::from(env) + "_COLOR") {
- Ok(value) => match value.as_ref() {
- "always" => true,
- "never" => false,
- "auto" => stderr_isatty(),
- _ => early_error(
- ErrorOutputType::default(),
- &format!(
- "invalid log color value '{}': expected one of always, never, or auto",
- value
- ),
- ),
- },
- Err(std::env::VarError::NotPresent) => stderr_isatty(),
- Err(std::env::VarError::NotUnicode(_value)) => early_error(
- ErrorOutputType::default(),
- "non-Unicode log color value: expected one of always, never, or auto",
- ),
- };
-
- let layer = tracing_tree::HierarchicalLayer::default()
- .with_writer(io::stderr)
- .with_indent_lines(true)
- .with_ansi(color_logs)
- .with_targets(true)
- .with_indent_amount(2);
- #[cfg(parallel_compiler)]
- let layer = layer.with_thread_ids(true).with_thread_names(true);
-
- let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
- tracing::subscriber::set_global_default(subscriber).unwrap();
+ if let Err(error) = rustc_log::init_env_logger(env) {
+ early_error(ErrorOutputType::default(), &error.to_string());
+ }
}
#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
dir_path,
});
let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
+ assert_eq!(krate.id, ast::CRATE_NODE_ID);
self.cx.trace_macros_diag();
krate
}
attrs: Vec::new(),
items: Vec::new(),
span,
- is_placeholder: None,
+ id: self.cx.resolver.next_node_id(),
+ is_placeholder: false,
};
}
};
.make_crate();
}
- noop_visit_crate(&mut krate, self);
+ assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self));
krate
})
}
attrs: Default::default(),
items: Default::default(),
span,
- is_placeholder: Some(id),
+ id,
+ is_placeholder: true,
}),
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
}
fn visit_crate(&mut self, krate: &mut ast::Crate) {
- if let Some(id) = krate.is_placeholder {
- *krate = self.remove(id).make_crate();
+ if krate.is_placeholder {
+ *krate = self.remove(krate.id).make_crate();
} else {
noop_visit_crate(krate, self)
}
/// A literal.
pub type Lit = Spanned<LitKind>;
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+ Infer(HirId, Span),
+ Body(AnonConst),
+}
+
+impl ArrayLen {
+ pub fn hir_id(&self) -> HirId {
+ match self {
+ &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+ }
+ }
+}
+
/// A constant (expression) that's not an item or associated item,
/// but needs its own `DefId` for type-checking, const-eval, etc.
/// These are usually found nested inside types (e.g., array lengths)
///
/// E.g., `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- Repeat(&'hir Expr<'hir>, AnonConst),
+ Repeat(&'hir Expr<'hir>, ArrayLen),
/// A suspension point for generators (i.e., `yield <expr>`).
Yield(&'hir Expr<'hir>, YieldSource),
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
- Array(&'hir Ty<'hir>, AnonConst),
+ Array(&'hir Ty<'hir>, ArrayLen),
/// A raw pointer (i.e., `*const T` or `*mut T`).
Ptr(MutTy<'hir>),
/// A reference (i.e., `&'a T` or `&'a mut T`).
fn visit_pat(&mut self, p: &'v Pat<'v>) {
walk_pat(self, p)
}
+ fn visit_array_length(&mut self, len: &'v ArrayLen) {
+ walk_array_len(self, len)
+ }
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
}
TyKind::Array(ref ty, ref length) => {
visitor.visit_ty(ty);
- visitor.visit_anon_const(length)
+ visitor.visit_array_length(length)
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
for bound in bounds {
}
}
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+ match len {
+ &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+ ArrayLen::Body(c) => visitor.visit_anon_const(c),
+ }
+}
+
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
visitor.visit_id(constant.hir_id);
visitor.visit_nested_body(constant.body);
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
ExprKind::Repeat(ref element, ref count) => {
visitor.visit_expr(element);
- visitor.visit_anon_const(count)
+ visitor.visit_array_length(count)
}
ExprKind::Struct(ref qpath, fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.hir_id, expression.span);
self.word("[");
self.print_type(&ty);
self.word("; ");
- self.print_anon_const(length);
+ self.print_array_length(length);
self.word("]");
}
hir::TyKind::Typeof(ref e) => {
self.print_else(elseopt)
}
+ pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+ match len {
+ hir::ArrayLen::Infer(_, _) => self.word("_"),
+ hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
+ }
+ }
+
pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
self.ann.nested(self, Nested::Body(constant.body))
}
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+ fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
self.ibox(INDENT_UNIT);
self.word("[");
self.print_expr(element);
self.word_space(";");
- self.print_anon_const(count);
+ self.print_array_length(count);
self.word("]");
self.end()
}
if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
trace.values
{
- // If a tuple of length one was expected and the found expression has
- // parentheses around it, perhaps the user meant to write `(expr,)` to
- // build a tuple (issue #86100)
match (expected.kind(), found.kind()) {
(ty::Tuple(_), ty::Tuple(_)) => {}
+ // If a tuple of length one was expected and the found expression has
+ // parentheses around it, perhaps the user meant to write `(expr,)` to
+ // build a tuple (issue #86100)
(ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
if let Some(code) =
}
}
}
+ // If a character was expected and the found expression is a string literal
+ // containing a single character, perhaps the user meant to write `'c'` to
+ // specify a character literal (issue #92479)
+ (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+ if let Some(code) =
+ code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
+ {
+ if code.chars().nth(1).is_none() {
+ err.span_suggestion(
+ span,
+ "if you meant to write a `char` literal, use single quotes",
+ format!("'{}'", code),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+ // If a string was expected and the found expression is a character literal,
+ // perhaps the user meant to write `"s"` to specify a string literal.
+ (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+ if let Some(code) =
+ code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ {
+ err.span_suggestion(
+ span,
+ "if you meant to write a `str` literal, use double quotes",
+ format!("\"{}\"", code),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
_ => {}
}
}
use crate::util;
use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit};
+use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_ssa::traits::CodegenBackend;
let crate_attrs = krate.attrs.clone();
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
- let krate = ast::Crate { attrs, items, span, is_placeholder: None };
+ let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
(krate.attrs, krate.items)
};
extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
- int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
+ uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
LLVMBasicBlockRef InsertAtEnd) {
return wrap(Builder->insertDeclare(
unwrap(V), unwrap<DILocalVariable>(VarInfo),
- Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+ Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
DebugLoc(cast<MDNode>(unwrap(DL))),
unwrap(InsertAtEnd)));
}
return wrap(Loc);
}
-extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
return dwarf::DW_OP_deref;
}
-extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
return dwarf::DW_OP_plus_uconst;
}
--- /dev/null
+[package]
+name = "rustc_log"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+atty = "0.2"
+tracing = "0.1.28"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.2.0"
+
+[dev-dependencies]
+rustc_span = { path = "../rustc_span" }
+
+[features]
+max_level_info = ['tracing/max_level_info']
--- /dev/null
+//! This crate allows tools to enable rust logging without having to magically
+//! match rustc's tracing crate version.
+//!
+//! For example if someone is working on rustc_ast and wants to write some
+//! minimal code against it to run in a debugger, with access to the `debug!`
+//! logs emitted by rustc_ast, that can be done by writing:
+//!
+//! ```toml
+//! [dependencies]
+//! rustc_ast = { path = "../rust/compiler/rustc_ast" }
+//! rustc_log = { path = "../rust/compiler/rustc_log" }
+//! rustc_span = { path = "../rust/compiler/rustc_span" }
+//! ```
+//!
+//! ```
+//! fn main() {
+//! rustc_log::init_rustc_env_logger().unwrap();
+//!
+//! let edition = rustc_span::edition::Edition::Edition2021;
+//! rustc_span::create_session_globals_then(edition, || {
+//! /* ... */
+//! });
+//! }
+//! ```
+//!
+//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! rustc's debug logging. In a workflow like this, one might also add
+//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! run` by itself is sufficient to get logs.
+//!
+//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
+//! same things in rustc_driver only, is to enable the above workflow. If you
+//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
+//! an enormously bigger dependency tree; every change you make to rustc_ast (or
+//! whichever piece of the compiler you are interested in) would involve
+//! rebuilding all the rest of rustc up to rustc_driver in order to run your
+//! main.rs. Whereas by depending only on rustc_log and the few crates you are
+//! debugging, you can make changes inside those crates and quickly run main.rs
+//! to read the debug logs.
+
+use std::env::{self, VarError};
+use std::fmt::{self, Display};
+use std::io;
+use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::layer::SubscriberExt;
+
+pub fn init_rustc_env_logger() -> Result<(), Error> {
+ init_env_logger("RUSTC_LOG")
+}
+
+/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) -> Result<(), Error> {
+ let filter = match env::var(env) {
+ Ok(env) => EnvFilter::new(env),
+ _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
+ };
+
+ let color_logs = match env::var(String::from(env) + "_COLOR") {
+ Ok(value) => match value.as_ref() {
+ "always" => true,
+ "never" => false,
+ "auto" => stderr_isatty(),
+ _ => return Err(Error::InvalidColorValue(value)),
+ },
+ Err(VarError::NotPresent) => stderr_isatty(),
+ Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
+ };
+
+ let layer = tracing_tree::HierarchicalLayer::default()
+ .with_writer(io::stderr)
+ .with_indent_lines(true)
+ .with_ansi(color_logs)
+ .with_targets(true)
+ .with_indent_amount(2);
+ #[cfg(parallel_compiler)]
+ let layer = layer.with_thread_ids(true).with_thread_names(true);
+
+ let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+
+ Ok(())
+}
+
+pub fn stdout_isatty() -> bool {
+ atty::is(atty::Stream::Stdout)
+}
+
+pub fn stderr_isatty() -> bool {
+ atty::is(atty::Stream::Stderr)
+}
+
+#[derive(Debug)]
+pub enum Error {
+ InvalidColorValue(String),
+ NonUnicodeColorValue,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::InvalidColorValue(value) => write!(
+ formatter,
+ "invalid log color value '{}': expected one of always, never, or auto",
+ value,
+ ),
+ Error::NonUnicodeColorValue => write!(
+ formatter,
+ "non-Unicode log color value: expected one of always, never, or auto",
+ ),
+ }
+ }
+}
rustc_arena = { path = "../rustc_arena" }
bitflags = "1.2.1"
either = "1.5.0"
-gsgdt = "0.1.3"
+gsgdt = "0.1.2"
tracing = "0.1"
rustc-rayon = "0.3.1"
rustc-rayon-core = "0.3.1"
data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
stmts.push(terminator_head);
- Node::from_list(stmts, label, title, style)
+ Node::new(stmts, label, title, style)
}
// Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
ExprKind::ConstBlock { value }
}
// Now comes the rote stuff:
- hir::ExprKind::Repeat(ref v, ref count) => {
- let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
- let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+ hir::ExprKind::Repeat(ref v, _) => {
+ let ty = self.typeck_results().expr_ty(expr);
+ let count = match ty.kind() {
+ ty::Array(_, ct) => ct,
+ _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+ };
ExprKind::Repeat { value: self.mirror_expr(v), count }
}
Instance::new(def_id, substs),
dummy_body,
ret.as_ref(),
- StackPopCleanup::None { cleanup: false },
+ StackPopCleanup::Root { cleanup: false },
)
.expect("failed to push initial stack frame");
LookupResult::Parent(Some(parent)) => {
let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
if maybe_dead {
- span_bug!(
+ self.tcx.sess.delay_span_bug(
terminator.source_info.span,
- "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
- bb,
- place,
- path
+ &format!(
+ "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
+ bb, place, path,
+ ),
);
}
continue;
bb,
),
LookupResult::Parent(..) => {
- span_bug!(
+ self.tcx.sess.delay_span_bug(
terminator.source_info.span,
- "drop of untracked value {:?}",
- bb
+ &format!("drop of untracked value {:?}", bb),
);
}
}
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
let (attrs, items, span) = self.parse_mod(&token::Eof)?;
- Ok(ast::Crate { attrs, items, span, is_placeholder: None })
+ Ok(ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
}
fn visit_crate(&mut self, krate: &'b ast::Crate) {
- if let Some(id) = krate.is_placeholder {
- self.visit_invoc_in_module(id);
+ if krate.is_placeholder {
+ self.visit_invoc_in_module(krate.id);
} else {
visit::walk_crate(self, krate);
self.contains_macro_use(&krate.attrs);
}
fn visit_crate(&mut self, krate: &'a Crate) {
- if let Some(id) = krate.is_placeholder {
- self.visit_macro_invoc(id)
+ if krate.is_placeholder {
+ self.visit_macro_invoc(krate.id)
} else {
visit::walk_crate(self, krate)
}
use std::cell::{Cell, RefCell};
use std::collections::{BTreeMap, BTreeSet};
use std::ops::ControlFlow;
-use std::{cmp, fmt, iter, ptr};
+use std::{cmp, fmt, iter, mem, ptr};
use tracing::debug;
use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
.chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
.collect(),
lint_buffer: LintBuffer::default(),
- next_node_id: NodeId::from_u32(1),
+ next_node_id: CRATE_NODE_ID,
node_id_to_def_id,
def_id_to_node_id,
placeholder_field_indices: Default::default(),
pub fn next_node_id(&mut self) -> NodeId {
let next =
self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
- self.next_node_id = ast::NodeId::from_u32(next);
- self.next_node_id
+ mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
}
pub fn lint_buffer(&mut self) -> &mut LintBuffer {
}
intravisit::walk_qpath(self, path, t.hir_id, t.span);
}
- hir::TyKind::Array(ref ty, ref anon_const) => {
+ hir::TyKind::Array(ref ty, ref length) => {
self.visit_ty(ty);
let map = self.tcx.hir();
- self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
- v.visit_expr(&map.body(anon_const.body).value)
- });
+ match length {
+ // FIXME(generic_arg_infer): We probably want to
+ // output the inferred type here? :shrug:
+ hir::ArrayLen::Infer(..) => {}
+ hir::ArrayLen::Body(anon_const) => self
+ .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+ v.visit_expr(&map.body(anon_const.body).value)
+ }),
+ }
}
hir::TyKind::OpaqueDef(item_id, _) => {
let item = self.tcx.hir().item(item_id);
v.visit_expr(&body.value)
});
}
- hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+ hir::ExprKind::Repeat(ref expr, ref length) => {
self.visit_expr(expr);
let map = self.tcx.hir();
- self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
- v.visit_expr(&map.body(anon_const.body).value)
- });
+ match length {
+ // FIXME(generic_arg_infer): We probably want to
+ // output the inferred type here? :shrug:
+ hir::ArrayLen::Infer(..) => {}
+ hir::ArrayLen::Body(anon_const) => self
+ .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+ v.visit_expr(&map.body(anon_const.body).value)
+ }),
+ }
}
// In particular, we take this branch for call and path expressions,
// where we'll index the idents involved just by continuing to walk.
let nested = bounds_to_string(&bounds);
Ok(text_sig(nested))
}
- hir::TyKind::Array(ref ty, ref anon_const) => {
+ hir::TyKind::Array(ref ty, ref length) => {
let nested_ty = ty.make(offset + 1, id, scx)?;
- let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+ let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
let text = format!("[{}; {}]", nested_ty.text, expr);
Ok(replace_text(nested_ty, text))
}
Full,
}
+/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
+/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
+/// uses DWARF for debug-information.
+///
+/// Some debug-information requires link-time relocation and some does not. LLVM can partition
+/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
+/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
+/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
+/// them in the object file in such a way that the linker will skip them.
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SplitDwarfKind {
+ /// Sections which do not require relocation are written into object file but ignored by the
+ /// linker.
+ Single,
+ /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
+ /// which is ignored by the linker.
+ Split,
+}
+
+impl FromStr for SplitDwarfKind {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, ()> {
+ Ok(match s {
+ "single" => SplitDwarfKind::Single,
+ "split" => SplitDwarfKind::Split,
+ _ => return Err(()),
+ })
+ }
+}
+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
self.0.len()
}
- // Returns `true` if any of the output types require codegen or linking.
+ /// Returns `true` if any of the output types require codegen or linking.
pub fn should_codegen(&self) -> bool {
self.0.keys().any(|k| match *k {
OutputType::Bitcode
})
}
- // Returns `true` if any of the output types require linking.
+ /// Returns `true` if any of the output types require linking.
pub fn should_link(&self) -> bool {
self.0.keys().any(|k| match *k {
OutputType::Bitcode
pub fn split_dwarf_path(
&self,
split_debuginfo_kind: SplitDebuginfo,
+ split_dwarf_kind: SplitDwarfKind,
cgu_name: Option<&str>,
) -> Option<PathBuf> {
let obj_out = self.temp_path(OutputType::Object, cgu_name);
let dwo_out = self.temp_path_dwo(cgu_name);
- match split_debuginfo_kind {
- SplitDebuginfo::Off => None,
+ match (split_debuginfo_kind, split_dwarf_kind) {
+ (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
// (pointing at the path which is being determined here). Use the path to the current
// object file.
- SplitDebuginfo::Packed => Some(obj_out),
+ (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
+ Some(obj_out)
+ }
// Split mode emits the DWARF into a different file, use that path.
- SplitDebuginfo::Unpacked => Some(dwo_out),
+ (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
+ Some(dwo_out)
+ }
}
}
}
impl_stable_hash_via_hash!(CrateType);
+impl CrateType {
+ /// When generated, is this crate type an archive?
+ pub fn is_archive(&self) -> bool {
+ match *self {
+ CrateType::Rlib | CrateType::Staticlib => true,
+ CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
+ false
+ }
+ }
+ }
+}
+
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub enum Passes {
Some(Vec<String>),
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
pub const parse_split_debuginfo: &str =
"one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+ pub const parse_split_dwarf_kind: &str =
+ "one of supported split dwarf modes (`split` or `single`)";
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
pub const parse_stack_protector: &str =
"one of (`none` (default), `basic`, `strong`, or `all`)";
true
}
+ crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
+ match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
+ Some(e) => *slot = e,
+ _ => return false,
+ }
+ true
+ }
+
crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
match v {
None => *slot = None,
"control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+ split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
+ "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+ (default: `split`)
+
+ `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+ file which is ignored by the linker
+ `single`: sections which do not require relocation are written into object file but ignored
+ by the linker"),
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
"provide minimal debug info in the object/executable to facilitate online \
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
-/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
+/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since
/// we encode this information in the type, we can ensure at compile time that
-/// no DefIds from upstream crates get thrown into the mix. There are quite a
-/// few cases where we know that only DefIds from the local crate are expected
-/// and a DefId from a different crate would signify a bug somewhere. This
-/// is when LocalDefId comes in handy.
+/// no `DefId`s from upstream crates get thrown into the mix. There are quite a
+/// few cases where we know that only `DefId`s from the local crate are expected;
+/// a `DefId` from a different crate would signify a bug somewhere. This
+/// is when `LocalDefId` comes in handy.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct LocalDefId {
pub local_def_index: DefIndex,
}
+// To ensure correctness of incremental compilation,
+// `LocalDefId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalDefId {}
+impl !PartialOrd for LocalDefId {}
+
pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
impl Idx for LocalDefId {
///
/// * Windows - not supported
/// * macOS - supported, scattered object files
- /// * ELF - supported, scattered `*.dwo` files
+ /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
Unpacked,
}
GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
GenericParamDefKind::Const { .. },
) if tcx.type_of(param.def_id) == tcx.types.usize => {
- let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+ let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
if let Ok(snippet) = snippet {
err.span_suggestion(
arg.span(),
self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
}
hir::TyKind::Array(ref ty, ref length) => {
- let length_def_id = tcx.hir().local_def_id(length.hir_id);
- let length = ty::Const::from_anon_const(tcx, length_def_id);
+ let length = match length {
+ &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+ hir::ArrayLen::Body(constant) => {
+ let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+ ty::Const::from_anon_const(tcx, length_def_id)
+ }
+ };
+
let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
call_expr.span,
call_expr,
fn_sig.inputs(),
- &expected_arg_tys,
+ expected_arg_tys,
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::DontTupleArguments,
call_expr.span,
call_expr,
fn_sig.inputs(),
- &expected_arg_tys,
+ expected_arg_tys,
arg_exprs,
fn_sig.c_variadic,
TupleArgumentsFlag::TupleArguments,
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
- count: &'tcx hir::AnonConst,
+ count: &'tcx hir::ArrayLen,
expected: Expectation<'tcx>,
_expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
- let count = self.to_const(count);
+ let count = self.array_length_to_const(count);
let uty = match expected {
ExpectHasType(uty) => match *uty.kind() {
ty
}
+ pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+ match length {
+ &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+ hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+ }
+ }
+
pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
let c = ty::Const::from_anon_const(self.tcx, const_def_id);
sp,
expr,
&err_inputs,
- &[],
+ vec![],
args_no_rcvr,
false,
tuple_arguments,
let method = method.unwrap();
// HACK(eddyb) ignore self in the definition (see above).
- let expected_arg_tys = self.expected_inputs_for_expected_output(
+ let expected_input_tys = self.expected_inputs_for_expected_output(
sp,
expected,
method.sig.output(),
sp,
expr,
&method.sig.inputs()[1..],
- &expected_arg_tys[..],
+ expected_input_tys,
args_no_rcvr,
method.sig.c_variadic,
tuple_arguments,
/// method calls and overloaded operators.
pub(in super::super) fn check_argument_types(
&self,
- sp: Span,
- expr: &'tcx hir::Expr<'tcx>,
- fn_inputs: &[Ty<'tcx>],
- expected_arg_tys: &[Ty<'tcx>],
- args: &'tcx [hir::Expr<'tcx>],
+ // Span enclosing the call site
+ call_span: Span,
+ // Expression of the call site
+ call_expr: &'tcx hir::Expr<'tcx>,
+ // Types (as defined in the *signature* of the target function)
+ formal_input_tys: &[Ty<'tcx>],
+ // More specific expected types, after unifying with caller output types
+ expected_input_tys: Vec<Ty<'tcx>>,
+ // The expressions for each provided argument
+ provided_args: &'tcx [hir::Expr<'tcx>],
+ // Whether the function is variadic, for example when imported from C
c_variadic: bool,
+ // Whether the arguments have been bundled in a tuple (ex: closures)
tuple_arguments: TupleArgumentsFlag,
- def_id: Option<DefId>,
+ // The DefId for the function being called, for better error messages
+ fn_def_id: Option<DefId>,
) {
let tcx = self.tcx;
// Grab the argument types, supplying fresh type variables
// if the wrong number of arguments were supplied
- let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+ let supplied_arg_count =
+ if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
// All the input types from the fn signature must outlive the call
// so as to validate implied bounds.
- for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) {
+ for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
}
- let expected_arg_count = fn_inputs.len();
+ let expected_arg_count = formal_input_tys.len();
let param_count_error = |expected_count: usize,
arg_count: usize,
error_code: &str,
c_variadic: bool,
sugg_unit: bool| {
- let (span, start_span, args, ctor_of) = match &expr.kind {
+ let (span, start_span, args, ctor_of) = match &call_expr.kind {
hir::ExprKind::Call(
hir::Expr {
span,
&args[1..], // Skip the receiver.
None, // methods are never ctors
),
- k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+ k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
};
- let arg_spans = if args.is_empty() {
+ let arg_spans = if provided_args.is_empty() {
// foo()
// ^^^-- supplied 0 arguments
// |
// expected 2 arguments
- vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+ vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
} else {
// foo(1, 2, 3)
// ^^^ - - - supplied 3 arguments
);
}
- if let Some(def_id) = def_id {
+ if let Some(def_id) = fn_def_id {
if let Some(def_span) = tcx.def_ident_span(def_id) {
let mut spans: MultiSpan = def_span.into();
}
if sugg_unit {
- let sugg_span = tcx.sess.source_map().end_point(expr.span);
+ let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
// remove closing `)` from the span
let sugg_span = sugg_span.shrink_to_lo();
err.span_suggestion(
err.emit();
};
- let mut expected_arg_tys = expected_arg_tys.to_vec();
-
- let formal_tys = if tuple_arguments == TupleArguments {
- let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+ let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
+ let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
match tuple_type.kind() {
- ty::Tuple(arg_types) if arg_types.len() != args.len() => {
- param_count_error(arg_types.len(), args.len(), "E0057", false, false);
- expected_arg_tys = vec![];
- self.err_args(args.len())
+ ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
+ param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
+ (self.err_args(provided_args.len()), vec![])
}
ty::Tuple(arg_types) => {
- expected_arg_tys = match expected_arg_tys.get(0) {
+ let expected_input_tys = match expected_input_tys.get(0) {
Some(&ty) => match ty.kind() {
ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
_ => vec![],
},
None => vec![],
};
- arg_types.iter().map(|k| k.expect_ty()).collect()
+ (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
}
_ => {
struct_span_err!(
tcx.sess,
- sp,
+ call_span,
E0059,
"cannot use call notation; the first type parameter \
for the function trait is neither a tuple nor unit"
)
.emit();
- expected_arg_tys = vec![];
- self.err_args(args.len())
+ (self.err_args(provided_args.len()), vec![])
}
}
} else if expected_arg_count == supplied_arg_count {
- fn_inputs.to_vec()
+ (formal_input_tys.to_vec(), expected_input_tys)
} else if c_variadic {
if supplied_arg_count >= expected_arg_count {
- fn_inputs.to_vec()
+ (formal_input_tys.to_vec(), expected_input_tys)
} else {
param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
- expected_arg_tys = vec![];
- self.err_args(supplied_arg_count)
+ (self.err_args(supplied_arg_count), vec![])
}
} else {
// is the missing argument of type `()`?
- let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
- self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
- } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
- self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
+ let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 {
+ self.resolve_vars_if_possible(expected_input_tys[0]).is_unit()
+ } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 {
+ self.resolve_vars_if_possible(formal_input_tys[0]).is_unit()
} else {
false
};
param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
- expected_arg_tys = vec![];
- self.err_args(supplied_arg_count)
+ (self.err_args(supplied_arg_count), vec![])
};
debug!(
- "check_argument_types: formal_tys={:?}",
- formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+ "check_argument_types: formal_input_tys={:?}",
+ formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
);
- // If there is no expectation, expect formal_tys.
- let expected_arg_tys =
- if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+ // If there is no expectation, expect formal_input_tys.
+ let expected_input_tys = if !expected_input_tys.is_empty() {
+ expected_input_tys
+ } else {
+ formal_input_tys.clone()
+ };
+
+ assert_eq!(expected_input_tys.len(), formal_input_tys.len());
+ // Keep track of the fully coerced argument types
let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+ // We introduce a helper function to demand that a given argument satisfy a given input
+ // This is more complicated than just checking type equality, as arguments could be coerced
+ // This version writes those types back so further type checking uses the narrowed types
+ let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+ let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
+ let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
+ let provided_arg = &provided_args[idx];
+
+ debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
+
+ // The special-cased logic below has three functions:
+ // 1. Provide as good of an expected type as possible.
+ let expectation = Expectation::rvalue_hint(self, expected_input_ty);
+
+ let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
+
+ // 2. Coerce to the most detailed type that could be coerced
+ // to, which is `expected_ty` if `rvalue_hint` returns an
+ // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+ let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
+
+ // Keep track of these for below
+ final_arg_types.push((idx, checked_ty, coerced_ty));
+
+ // Cause selection errors caused by resolving a single argument to point at the
+ // argument and not the call. This is otherwise redundant with the `demand_coerce`
+ // call immediately after, but it lets us customize the span pointed to in the
+ // fulfillment error to be more accurate.
+ let _ =
+ self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
+ self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
+ self.point_at_arg_instead_of_call_if_possible(
+ errors,
+ &final_arg_types,
+ call_expr,
+ call_span,
+ provided_args,
+ );
+ });
+
+ // We're processing function arguments so we definitely want to use
+ // two-phase borrows.
+ self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
+
+ // 3. Relate the expected type and the formal one,
+ // if the expected type was used for the coercion.
+ self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
+ };
+
// Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments
// that are not closures, then we type-check the closures. This is so
// that we have more information about the types of arguments when we
// type-check the functions. This isn't really the right way to do this.
for check_closures in [false, true] {
- debug!("check_closures={}", check_closures);
-
// More awful hacks: before we check argument types, try to do
// an "opportunistic" trait resolution of any trait bounds on
// the call. This helps coercions.
if check_closures {
self.select_obligations_where_possible(false, |errors| {
- self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+ self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
self.point_at_arg_instead_of_call_if_possible(
errors,
&final_arg_types,
- expr,
- sp,
- &args,
+ call_expr,
+ call_span,
+ &provided_args,
);
})
}
- // For C-variadic functions, we don't have a declared type for all of
- // the arguments hence we only do our usual type checking with
- // the arguments who's types we do know.
- let t = if c_variadic {
- expected_arg_count
- } else if tuple_arguments == TupleArguments {
- args.len()
- } else {
- supplied_arg_count
- };
- for (i, arg) in args.iter().take(t).enumerate() {
+ let minimum_input_count = formal_input_tys.len();
+ for (idx, arg) in provided_args.iter().enumerate() {
// Warn only for the first loop (the "no closures" one).
// Closure arguments themselves can't be diverging, but
// a previous argument can, e.g., `foo(panic!(), || {})`.
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
}
- let is_closure = matches!(arg.kind, ExprKind::Closure(..));
+ // For C-variadic functions, we don't have a declared type for all of
+ // the arguments hence we only do our usual type checking with
+ // the arguments who's types we do know. However, we *can* check
+ // for unreachable expressions (see above).
+ // FIXME: unreachable warning current isn't emitted
+ if idx >= minimum_input_count {
+ continue;
+ }
+ let is_closure = matches!(arg.kind, ExprKind::Closure(..));
if is_closure != check_closures {
continue;
}
- let formal_ty = formal_tys[i];
- debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
-
- // The special-cased logic below has three functions:
- // 1. Provide as good of an expected type as possible.
- let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
- let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
- // 2. Coerce to the most detailed type that could be coerced
- // to, which is `expected_ty` if `rvalue_hint` returns an
- // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
- let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-
- final_arg_types.push((i, checked_ty, coerce_ty));
-
- // Cause selection errors caused by resolving a single argument to point at the
- // argument and not the call. This is otherwise redundant with the `demand_coerce`
- // call immediately after, but it lets us customize the span pointed to in the
- // fulfillment error to be more accurate.
- let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
- coerce_ty,
- |errors| {
- self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
- self.point_at_arg_instead_of_call_if_possible(
- errors,
- &final_arg_types,
- expr,
- sp,
- args,
- );
- },
- );
-
- // We're processing function arguments so we definitely want to use
- // two-phase borrows.
- self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-
- // 3. Relate the expected type and the formal one,
- // if the expected type was used for the coercion.
- self.demand_suptype(arg.span, formal_ty, coerce_ty);
+ demand_compatible(idx, &mut final_arg_types);
}
}
MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
}
- for arg in args.iter().skip(expected_arg_count) {
+ for arg in provided_args.iter().skip(expected_arg_count) {
let arg_ty = self.check_expr(&arg);
// There are a few types which get autopromoted when passed via varargs
sugg.push((span, format!(", {}", type_name)));
}
- let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+ let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
// Suggest, but only if it is not a function in const or static
if suggest {
if let hir::ExprKind::Closure(..) = expr.kind {
let def_id = self.tcx.hir().local_def_id(expr.hir_id);
self.tcx.ensure().generics_of(def_id);
- self.tcx.ensure().type_of(def_id);
+ // We do not call `type_of` for closures here as that
+ // depends on typecheck and would therefore hide
+ // any further errors in case one typeck fails.
}
intravisit::walk_expr(self, expr);
}
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
+ placeholder_kind: &'static str,
mut spans: Vec<Span>,
kind: &'static str,
) -> rustc_errors::DiagnosticBuilder<'tcx> {
tcx.sess,
spans.clone(),
E0121,
- "the type placeholder `_` is not allowed within types on item signatures for {}",
+ "the {} placeholder `_` is not allowed within types on item signatures for {}",
+ placeholder_kind,
kind
);
for span in spans {
_: Option<&ty::GenericParamDef>,
span: Span,
) -> &'tcx Const<'tcx> {
- bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+ bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
// Typeck doesn't expect erased regions to be returned from `type_of`.
let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
ty::ReErased => self.tcx.lifetimes.re_static,
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
// as they shouldn't be able to cause query cycle errors.
Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+ if constant.hir_id() == hir_id =>
+ {
+ Some(parent_def_id.to_def_id())
+ }
+ Node::Variant(Variant { disr_expr: Some(ref constant), .. })
if constant.hir_id == hir_id =>
{
Some(parent_def_id.to_def_id())
let mut visitor = PlaceholderHirTyCollector::default();
visitor.visit_ty(ty);
- let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+ let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
let ret_ty = fn_sig.skip_binder().output();
if !ret_ty.references_error() {
if !ret_ty.is_closure() {
use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
/// Computes the relevant generic parameter for a potential generic const argument.
///
Node::Field(field) => icx.to_ty(field.ty),
- Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
- let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
- if let Some(movability) = gen {
- tcx.mk_generator(def_id.to_def_id(), substs, movability)
- } else {
- tcx.mk_closure(def_id.to_def_id(), substs)
- }
- }
+ Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id),
Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
// We defer to `type_of` of the corresponding parameter
match parent_node {
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
- if constant.hir_id == hir_id =>
+ if constant.hir_id() == hir_id =>
{
tcx.types.usize
}
err.emit();
}
None => {
- let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+ let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
debug!("walk_captures({:?})", closure_expr);
- let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
- let upvars = self.tcx().upvars_mentioned(self.body_owner);
+ let tcx = self.tcx();
+ let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id();
+ let upvars = tcx.upvars_mentioned(self.body_owner);
// For purposes of this function, generator and closures are equivalent.
let body_owner_is_closure = matches!(
- self.tcx().type_of(self.body_owner.to_def_id()).kind(),
- ty::Closure(..) | ty::Generator(..)
+ tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)),
+ hir::BodyOwnerKind::Closure,
);
// If we have a nested closure, we want to include the fake reads present in the nested closure.
#[cfg_attr(not(test), lang = "box_free")]
#[inline]
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
// This signature has to be the same as `Box`, otherwise an ICE will happen.
// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
// well.
// For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
-pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
+pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Drop>(
+ ptr: Unique<T>,
+ alloc: A,
+) {
unsafe {
let size = size_of_val(ptr.as_ref());
let align = min_align_of_val(ptr.as_ref());
let layout = Layout::from_size_align_unchecked(size, align);
- alloc.deallocate(ptr.cast().into(), layout)
+ alloc.deallocate(From::from(ptr.cast()), layout)
}
}
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
#[cfg(all(not(no_global_oom_handling), not(test)))]
#[rustc_allocator_nounwind]
#[cold]
-pub fn handle_alloc_error(layout: Layout) -> ! {
- unsafe {
- __rust_alloc_error_handler(layout.size(), layout.align());
+pub const fn handle_alloc_error(layout: Layout) -> ! {
+ const fn ct_error(_: Layout) -> ! {
+ panic!("allocation failed");
}
+
+ fn rt_error(layout: Layout) -> ! {
+ unsafe {
+ __rust_alloc_error_handler(layout.size(), layout.align());
+ }
+ }
+
+ unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
}
// For alloc test `std::alloc::handle_alloc_error` can be used directly.
/// ```
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[must_use]
#[inline]
- pub fn new_in(x: T, alloc: A) -> Self {
+ pub const fn new_in(x: T, alloc: A) -> Self
+ where
+ A: ~const Allocator + ~const Drop,
+ {
let mut boxed = Self::new_uninit_in(alloc);
unsafe {
boxed.as_mut_ptr().write(x);
/// # Ok::<(), std::alloc::AllocError>(())
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
+ pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError>
+ where
+ T: ~const Drop,
+ A: ~const Allocator + ~const Drop,
+ {
let mut boxed = Self::try_new_uninit_in(alloc)?;
unsafe {
boxed.as_mut_ptr().write(x);
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[cfg(not(no_global_oom_handling))]
#[must_use]
// #[unstable(feature = "new_uninit", issue = "63291")]
- pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+ pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+ where
+ A: ~const Allocator + ~const Drop,
+ {
let layout = Layout::new::<mem::MaybeUninit<T>>();
// NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
// That would make code size bigger.
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
- pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+ pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+ where
+ A: ~const Allocator + ~const Drop,
+ {
let layout = Layout::new::<mem::MaybeUninit<T>>();
let ptr = alloc.allocate(layout)?.cast();
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
///
/// [zeroed]: mem::MaybeUninit::zeroed
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[cfg(not(no_global_oom_handling))]
// #[unstable(feature = "new_uninit", issue = "63291")]
#[must_use]
- pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+ pub const fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+ where
+ A: ~const Allocator + ~const Drop,
+ {
let layout = Layout::new::<mem::MaybeUninit<T>>();
// NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
// That would make code size bigger.
/// [zeroed]: mem::MaybeUninit::zeroed
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "new_uninit", issue = "63291")]
- pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+ pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+ where
+ A: ~const Allocator + ~const Drop,
+ {
let layout = Layout::new::<mem::MaybeUninit<T>>();
let ptr = alloc.allocate_zeroed(layout)?.cast();
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
/// `x` will be pinned in memory and unable to be moved.
#[cfg(not(no_global_oom_handling))]
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[must_use]
#[inline(always)]
- pub fn pin_in(x: T, alloc: A) -> Pin<Self>
+ pub const fn pin_in(x: T, alloc: A) -> Pin<Self>
where
- A: 'static,
+ A: 'static + ~const Allocator + ~const Drop,
{
- Self::new_in(x, alloc).into()
+ Self::into_pin(Self::new_in(x, alloc))
}
/// Converts a `Box<T>` into a `Box<[T]>`
///
/// This conversion does not allocate on the heap and happens in place.
#[unstable(feature = "box_into_boxed_slice", issue = "71582")]
- pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+ pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
let (raw, alloc) = Box::into_raw_with_allocator(boxed);
unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) }
}
/// assert_eq!(Box::into_inner(c), 5);
/// ```
#[unstable(feature = "box_into_inner", issue = "80437")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn into_inner(boxed: Self) -> T {
+ pub const fn into_inner(boxed: Self) -> T
+ where
+ Self: ~const Drop,
+ {
*boxed
}
}
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub unsafe fn assume_init(self) -> Box<T, A> {
+ pub const unsafe fn assume_init(self) -> Box<T, A> {
let (raw, alloc) = Box::into_raw_with_allocator(self);
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
}
/// }
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+ pub const fn write(mut boxed: Self, value: T) -> Box<T, A> {
unsafe {
(*boxed).write(value);
boxed.assume_init()
/// [memory layout]: self#memory-layout
/// [`Layout`]: crate::Layout
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
+ pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
}
///
/// [memory layout]: self#memory-layout
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
+ pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
let (leaked, alloc) = Box::into_unique(b);
(leaked.as_ptr(), alloc)
}
issue = "none",
reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead"
)]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
#[doc(hidden)]
- pub fn into_unique(b: Self) -> (Unique<T>, A) {
+ pub const fn into_unique(b: Self) -> (Unique<T>, A) {
// Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a
// raw pointer for the type system. Turning it directly into a raw pointer would not be
// recognized as "releasing" the unique pointer to permit aliased raw accesses,
/// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
/// is so that there is no conflict with a method on the inner type.
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn allocator(b: &Self) -> &A {
+ pub const fn allocator(b: &Self) -> &A {
&b.1
}
/// assert_eq!(*static_ref, [4, 2, 3]);
/// ```
#[stable(feature = "box_leak", since = "1.26.0")]
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
- pub fn leak<'a>(b: Self) -> &'a mut T
+ pub const fn leak<'a>(b: Self) -> &'a mut T
where
A: 'a,
{
///
/// This is also available via [`From`].
#[unstable(feature = "box_into_pin", issue = "62370")]
- pub fn into_pin(boxed: Self) -> Pin<Self>
+ #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+ pub const fn into_pin(boxed: Self) -> Pin<Self>
where
A: 'static,
{
}
#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
fn drop(&mut self) {
// FIXME: Do nothing, drop is currently performed by compiler.
}
}
#[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>>
where
A: 'static,
{
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> Deref for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
type Target = T;
fn deref(&self) -> &T {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const DerefMut for Box<T, A> {
fn deref_mut(&mut self) -> &mut T {
&mut **self
}
* could have a method to project a Pin<T> from it.
*/
#[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {}
#[unstable(feature = "generator_trait", issue = "43122")]
impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
#![feature(array_windows)]
#![feature(async_stream)]
#![feature(coerce_unsized)]
+#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
+#![feature(const_box)]
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
#![feature(const_cow_is_borrowed)]
+#![feature(const_convert)]
+#![feature(const_size_of_val)]
+#![feature(const_align_of_val)]
+#![feature(const_ptr_read)]
+#![feature(const_maybe_uninit_write)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
+#![feature(const_refs_to_cell)]
#![feature(core_intrinsics)]
+#![feature(const_eval_select)]
+#![feature(const_pin)]
#![feature(dispatch_from_dyn)]
#![feature(exact_size_is_empty)]
#![feature(extend_one)]
#![feature(box_syntax)]
#![feature(cfg_sanitize)]
#![feature(cfg_target_has_atomic)]
+#![feature(const_deref)]
#![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_write)]
+#![feature(const_precise_live_drops)]
#![feature(const_trait_impl)]
+#![feature(const_try)]
#![cfg_attr(bootstrap, feature(destructuring_assignment))]
#![feature(dropck_eyepatch)]
#![feature(exclusive_range_pattern)]
// performance than with the 2nd method.
//
// All methods were benchmarked, and the 3rd showed best results. So we chose that one.
- let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
+ let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
// Intermediate state of the insertion process is always tracked by `hole`, which
// serves two purposes:
// If `is_less` panics at any point during the process, `hole` will get dropped and
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
// initially held exactly once.
- let mut hole = InsertionHole { src: &mut *tmp, dest: &mut v[1] };
+ let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
for i in 2..v.len() {
// When dropped, copies from `src` into `dest`.
struct InsertionHole<T> {
- src: *mut T,
+ src: *const T,
dest: *mut T,
}
/// let mut output = String::new();
///
/// // Pre-reserve the memory, exiting if we can't
- /// output.try_reserve(data.len())?;
+ /// output.try_reserve_exact(data.len())?;
///
/// // Now we know this can't OOM in the middle of our complex work
/// output.push_str(data);
-use std::cell::Cell;
-use std::mem::MaybeUninit;
-use std::ptr::NonNull;
+use core::alloc::{AllocError, Allocator, Layout};
+use core::cell::Cell;
+use core::mem::MaybeUninit;
+use core::ptr::NonNull;
#[test]
fn uninitialized_zero_size_box() {
x.set(1000);
assert_eq!(x.get(), 1000);
}
+
+pub struct ConstAllocator;
+
+unsafe impl const Allocator for ConstAllocator {
+ fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+ match layout.size() {
+ 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
+ _ => unsafe {
+ let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
+ Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))
+ },
+ }
+ }
+
+ unsafe fn deallocate(&self, _ptr: NonNull<u8>, layout: Layout) {
+ match layout.size() {
+ 0 => { /* do nothing */ }
+ _ => { /* do nothing too */ }
+ }
+ }
+
+ fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+ let ptr = self.allocate(layout)?;
+ if layout.size() > 0 {
+ unsafe {
+ ptr.as_mut_ptr().write_bytes(0, layout.size());
+ }
+ }
+ Ok(ptr)
+ }
+
+ unsafe fn grow(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ debug_assert!(
+ new_layout.size() >= old_layout.size(),
+ "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
+ );
+
+ let new_ptr = self.allocate(new_layout)?;
+ if new_layout.size() > 0 {
+ new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
+ self.deallocate(ptr, old_layout);
+ }
+ Ok(new_ptr)
+ }
+
+ unsafe fn grow_zeroed(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ let new_ptr = self.grow(ptr, old_layout, new_layout)?;
+ if new_layout.size() > 0 {
+ let old_size = old_layout.size();
+ let new_size = new_layout.size();
+ let raw_ptr = new_ptr.as_mut_ptr();
+ raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+ }
+ Ok(new_ptr)
+ }
+
+ unsafe fn shrink(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ debug_assert!(
+ new_layout.size() <= old_layout.size(),
+ "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
+ );
+
+ let new_ptr = self.allocate(new_layout)?;
+ if new_layout.size() > 0 {
+ new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size());
+ self.deallocate(ptr, old_layout);
+ }
+ Ok(new_ptr)
+ }
+
+ fn by_ref(&self) -> &Self
+ where
+ Self: Sized,
+ {
+ self
+ }
+}
+
+#[test]
+fn const_box() {
+ const VALUE: u32 = {
+ let mut boxed = Box::new_in(1u32, ConstAllocator);
+ assert!(*boxed == 1);
+
+ *boxed = 42;
+ assert!(*boxed == 42);
+
+ *boxed
+ };
+
+ assert!(VALUE == 42);
+}
#![feature(allocator_api)]
+#![feature(alloc_layout_extra)]
#![feature(assert_matches)]
#![feature(box_syntax)]
#![feature(cow_is_borrowed)]
+#![feature(const_box)]
+#![feature(const_convert)]
#![feature(const_cow_is_borrowed)]
+#![feature(const_heap)]
+#![feature(const_intrinsic_copy)]
+#![feature(const_mut_refs)]
+#![feature(const_nonnull_slice_from_raw_parts)]
+#![feature(const_ptr_offset)]
+#![feature(const_ptr_write)]
+#![feature(const_try)]
+#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(new_uninit)]
#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(const_str_from_utf8)]
+#![feature(nonnull_slice_from_raw_parts)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
/// There are a number of helper methods on the [`Formatter`] struct to help you with manual
/// implementations, such as [`debug_struct`].
///
+/// [`debug_struct`]: Formatter::debug_struct
+///
+/// Types that do not wish to use the standard suite of debug representations
+/// provided by the `Formatter` trait (`debug_struct`, `debug_tuple`,
+/// `debut_list`, `debug_set`, `debug_map`) can do something totally custom by
+/// manually writing an arbitrary representation to the `Formatter`.
+///
+/// ```
+/// # use std::fmt;
+/// # struct Point {
+/// # x: i32,
+/// # y: i32,
+/// # }
+/// #
+/// impl fmt::Debug for Point {
+/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// write!(f, "Point [{} {}]", self.x, self.y)
+/// }
+/// }
+/// ```
+///
/// `Debug` implementations using either `derive` or the debug builder API
/// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`.
///
-/// [`debug_struct`]: Formatter::debug_struct
-///
/// Pretty-printing with `#?`:
///
/// ```
}
}
+ // RISC-V platform spin loop hint implementation
+ {
+ // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different
+ // modules in `core::arch`.
+ // In this case, here we call `pause` function in each core arch module.
+ #[cfg(target_arch = "riscv32")]
+ {
+ crate::arch::riscv32::pause();
+ }
+ #[cfg(target_arch = "riscv64")]
+ {
+ crate::arch::riscv64::pause();
+ }
+ }
+
#[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
{
#[cfg(target_arch = "aarch64")]
unsafe { crate::arch::arm::__yield() };
}
}
-
- #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
- {
- crate::arch::riscv::pause();
- }
}
/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
language use and is subject to change"
)]
#[allow_internal_unstable(fmt_internals)]
- #[doc(hidden)]
#[rustc_builtin_macro]
#[macro_export]
macro_rules! format_args_nl {
}
/// Attribute macro used to apply derive macros.
+ ///
+ /// See [the reference] for more info.
+ ///
+ /// [the reference]: ../../../reference/attributes/derive.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_builtin_macro]
pub macro derive($item:item) {
}
/// Attribute macro applied to a function to turn it into a unit test.
+ ///
+ /// See [the reference] for more info.
+ ///
+ /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(test, rustc_attrs)]
#[rustc_builtin_macro]
/// Attribute macro applied to a static to register it as a global allocator.
///
- /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html).
+ /// See also [`std::alloc::GlobalAlloc`](../../../std/alloc/trait.GlobalAlloc.html).
#[stable(feature = "global_allocator", since = "1.28.0")]
#[allow_internal_unstable(rustc_attrs)]
#[rustc_builtin_macro]
since = "1.52.0",
reason = "rustc-serialize is deprecated and no longer supported"
)]
+ #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
pub macro RustcDecodable($item:item) {
/* compiler built-in */
}
since = "1.52.0",
reason = "rustc-serialize is deprecated and no longer supported"
)]
+ #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
pub macro RustcEncodable($item:item) {
/* compiler built-in */
}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
-/// This is used for object safety, to check that a method's receiver type can be dispatched on.
+/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing
+/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on.
+///
+/// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different
+/// interpretation).
+///
+/// Imagine we have a trait object `t` with type `&dyn Tr`, where `Tr` is some trait with a method
+/// `m` defined as `fn m(&self);`. When calling `t.m()`, the receiver `t` is a wide pointer, but an
+/// implementation of `m` will expect a narrow pointer as `&self` (a reference to the concrete
+/// type). The compiler must generate an implicit conversion from the trait object/wide pointer to
+/// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that
+/// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as
+/// the self type in an object-safe method. (in the above example, the compiler will require
+/// `DispatchFromDyn` is implemented for `&'a U`).
+///
+/// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the
+/// conversion is hard-wired into the compiler. For the conversion to work, the following
+/// properties must hold (i.e., it is only safe to implement `DispatchFromDyn` for types which have
+/// these properties, these are also checked by the compiler):
+///
+/// * EITHER `Self` and `T` are either both references or both raw pointers; in either case, with
+/// the same mutability.
+/// * OR, all of the following hold
+/// - `Self` and `T` must have the same type constructor, and only vary in a single type parameter
+/// formal (the *coerced type*, e.g., `impl DispatchFromDyn<Rc<T>> for Rc<U>` is ok and the
+/// single type parameter (instantiated with `T` or `U`) is the coerced type,
+/// `impl DispatchFromDyn<Arc<T>> for Rc<U>` is not ok).
+/// - The definition for `Self` must be a struct.
+/// - The definition for `Self` must not be `#[repr(packed)]` or `#[repr(C)]`.
+/// - Other than one-aligned, zero-sized fields, the definition for `Self` must have exactly one
+/// field and that field's type must be the coerced type. Furthermore, `Self`'s field type must
+/// implement `DispatchFromDyn<F>` where `F` is the type of `T`'s field type.
///
/// An example implementation of the trait:
///
!self.is_some()
}
- /// Returns `true` if the option is a [`Some`] value containing the given value.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(option_result_contains)]
- ///
- /// let x: Option<u32> = Some(2);
- /// assert_eq!(x.contains(&2), true);
- ///
- /// let x: Option<u32> = Some(3);
- /// assert_eq!(x.contains(&2), false);
- ///
- /// let x: Option<u32> = None;
- /// assert_eq!(x.contains(&2), false);
- /// ```
- #[must_use]
- #[inline]
- #[unstable(feature = "option_result_contains", issue = "62358")]
- #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
- pub const fn contains<U>(&self, x: &U) -> bool
- where
- U: ~const PartialEq<T>,
- {
- match self {
- Some(y) => x.eq(y),
- None => false,
- }
- }
-
/////////////////////////////////////////////////////////////////////////
// Adapter for working with references
/////////////////////////////////////////////////////////////////////////
mem::replace(self, Some(value))
}
+ /// Returns `true` if the option is a [`Some`] value containing the given value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_result_contains)]
+ ///
+ /// let x: Option<u32> = Some(2);
+ /// assert_eq!(x.contains(&2), true);
+ ///
+ /// let x: Option<u32> = Some(3);
+ /// assert_eq!(x.contains(&2), false);
+ ///
+ /// let x: Option<u32> = None;
+ /// assert_eq!(x.contains(&2), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "option_result_contains", issue = "62358")]
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn contains<U>(&self, x: &U) -> bool
+ where
+ U: ~const PartialEq<T>,
+ {
+ match self {
+ Some(y) => x.eq(y),
+ None => false,
+ }
+ }
+
/// Zips `self` with another `Option`.
///
/// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
#[doc(no_inline)]
pub use crate::concat_bytes;
+// Do not `doc(inline)` these `doc(hidden)` items.
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(no_inline)]
-pub use crate::macros::builtin::{
- bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(no_inline)]
-pub use crate::macros::builtin::derive;
+pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
#[unstable(
feature = "cfg_accessible",
issue = "64797",
reason = "`cfg_accessible` is not fully implemented"
)]
-#[doc(no_inline)]
pub use crate::macros::builtin::cfg_accessible;
#[unstable(
issue = "82679",
reason = "`cfg_eval` is a recently implemented feature"
)]
-#[doc(no_inline)]
pub use crate::macros::builtin::cfg_eval;
!self.is_ok()
}
- /// Returns `true` if the result is an [`Ok`] value containing the given value.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(option_result_contains)]
- ///
- /// let x: Result<u32, &str> = Ok(2);
- /// assert_eq!(x.contains(&2), true);
- ///
- /// let x: Result<u32, &str> = Ok(3);
- /// assert_eq!(x.contains(&2), false);
- ///
- /// let x: Result<u32, &str> = Err("Some error message");
- /// assert_eq!(x.contains(&2), false);
- /// ```
- #[must_use]
- #[inline]
- #[unstable(feature = "option_result_contains", issue = "62358")]
- pub fn contains<U>(&self, x: &U) -> bool
- where
- U: PartialEq<T>,
- {
- match self {
- Ok(y) => x == y,
- Err(_) => false,
- }
- }
-
- /// Returns `true` if the result is an [`Err`] value containing the given value.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(result_contains_err)]
- ///
- /// let x: Result<u32, &str> = Ok(2);
- /// assert_eq!(x.contains_err(&"Some error message"), false);
- ///
- /// let x: Result<u32, &str> = Err("Some error message");
- /// assert_eq!(x.contains_err(&"Some error message"), true);
- ///
- /// let x: Result<u32, &str> = Err("Some other error message");
- /// assert_eq!(x.contains_err(&"Some error message"), false);
- /// ```
- #[must_use]
- #[inline]
- #[unstable(feature = "result_contains_err", issue = "62358")]
- pub fn contains_err<F>(&self, f: &F) -> bool
- where
- F: PartialEq<E>,
- {
- match self {
- Ok(_) => false,
- Err(e) => f == e,
- }
- }
-
/////////////////////////////////////////////////////////////////////////
// Adapter for each variant
/////////////////////////////////////////////////////////////////////////
Err(e) => e,
}
}
+
+ /////////////////////////////////////////////////////////////////////////
+ // Misc or niche
+ /////////////////////////////////////////////////////////////////////////
+
+ /// Returns `true` if the result is an [`Ok`] value containing the given value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(option_result_contains)]
+ ///
+ /// let x: Result<u32, &str> = Ok(2);
+ /// assert_eq!(x.contains(&2), true);
+ ///
+ /// let x: Result<u32, &str> = Ok(3);
+ /// assert_eq!(x.contains(&2), false);
+ ///
+ /// let x: Result<u32, &str> = Err("Some error message");
+ /// assert_eq!(x.contains(&2), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "option_result_contains", issue = "62358")]
+ pub fn contains<U>(&self, x: &U) -> bool
+ where
+ U: PartialEq<T>,
+ {
+ match self {
+ Ok(y) => x == y,
+ Err(_) => false,
+ }
+ }
+
+ /// Returns `true` if the result is an [`Err`] value containing the given value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_contains_err)]
+ ///
+ /// let x: Result<u32, &str> = Ok(2);
+ /// assert_eq!(x.contains_err(&"Some error message"), false);
+ ///
+ /// let x: Result<u32, &str> = Err("Some error message");
+ /// assert_eq!(x.contains_err(&"Some error message"), true);
+ ///
+ /// let x: Result<u32, &str> = Err("Some other error message");
+ /// assert_eq!(x.contains_err(&"Some error message"), false);
+ /// ```
+ #[must_use]
+ #[inline]
+ #[unstable(feature = "result_contains_err", issue = "62358")]
+ pub fn contains_err<F>(&self, f: &F) -> bool
+ where
+ F: PartialEq<E>,
+ {
+ match self {
+ Ok(_) => false,
+ Err(e) => f == e,
+ }
+ }
}
impl<T, E> Result<&T, E> {
/// # Examples
///
/// ```
- /// #![feature(result_copied)]
/// let val = 12;
/// let x: Result<&i32, i32> = Ok(&val);
/// assert_eq!(x, Ok(&12));
/// let copied = x.copied();
/// assert_eq!(copied, Ok(12));
/// ```
- #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
+ #[inline]
+ #[stable(feature = "result_copied", since = "1.59.0")]
pub fn copied(self) -> Result<T, E>
where
T: Copy,
/// # Examples
///
/// ```
- /// #![feature(result_cloned)]
/// let val = 12;
/// let x: Result<&i32, i32> = Ok(&val);
/// assert_eq!(x, Ok(&12));
/// let cloned = x.cloned();
/// assert_eq!(cloned, Ok(12));
/// ```
- #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
+ #[inline]
+ #[stable(feature = "result_cloned", since = "1.59.0")]
pub fn cloned(self) -> Result<T, E>
where
T: Clone,
/// # Examples
///
/// ```
- /// #![feature(result_copied)]
/// let mut val = 12;
/// let x: Result<&mut i32, i32> = Ok(&mut val);
/// assert_eq!(x, Ok(&mut 12));
/// let copied = x.copied();
/// assert_eq!(copied, Ok(12));
/// ```
- #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
+ #[inline]
+ #[stable(feature = "result_copied", since = "1.59.0")]
pub fn copied(self) -> Result<T, E>
where
T: Copy,
/// # Examples
///
/// ```
- /// #![feature(result_cloned)]
/// let mut val = 12;
/// let x: Result<&mut i32, i32> = Ok(&mut val);
/// assert_eq!(x, Ok(&mut 12));
/// let cloned = x.cloned();
/// assert_eq!(cloned, Ok(12));
/// ```
- #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
+ #[inline]
+ #[stable(feature = "result_cloned", since = "1.59.0")]
pub fn cloned(self) -> Result<T, E>
where
T: Clone,
/// When dropped, copies from `src` into `dest`.
struct CopyOnDrop<T> {
- src: *mut T,
+ src: *const T,
dest: *mut T,
}
// Read the first element into a stack-allocated variable. If a following comparison
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
- let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
+ let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
let v = v.as_mut_ptr();
- let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(1) };
+ let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(1) };
ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
for i in 2..len {
// Read the last element into a stack-allocated variable. If a following comparison
// operation panics, `hole` will get dropped and automatically write the element back
// into the slice.
- let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
+ let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
let v = v.as_mut_ptr();
- let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(len - 2) };
+ let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(len - 2) };
ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
for i in (0..len - 2).rev() {
// operation panics, the pivot will be automatically written back into the slice.
// SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
- let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
- let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+ let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+ let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
let pivot = &*tmp;
// Find the first pair of out-of-order elements.
// Read the pivot into a stack-allocated variable for efficiency. If a following comparison
// operation panics, the pivot will be automatically written back into the slice.
// SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
- let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
- let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+ let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+ let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
let pivot = &*tmp;
// Now partition the slice.
pub use std_detect::{
is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
+ is_riscv_feature_detected,
};
// Re-export macros defined in libcore.
let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
assert_eq!(None, none);
// not enough groups
- let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
assert_eq!(None, none);
// too many groups
- let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+ let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
assert_eq!(None, none);
}
#[doc(no_inline)]
pub use core::prelude::v1::concat_bytes;
-// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
-// dead links which fail link checker testing.
+// Do not `doc(inline)` these `doc(hidden)` items.
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(hidden)]
-pub use core::prelude::v1::{
- bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(hidden)]
-pub use core::prelude::v1::derive;
+pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
+// Do not `doc(no_inline)` either.
#[unstable(
feature = "cfg_accessible",
issue = "64797",
reason = "`cfg_accessible` is not fully implemented"
)]
-#[doc(hidden)]
pub use core::prelude::v1::cfg_accessible;
+// Do not `doc(no_inline)` either.
#[unstable(
feature = "cfg_eval",
issue = "82679",
reason = "`cfg_eval` is a recently implemented feature"
)]
-#[doc(hidden)]
pub use core::prelude::v1::cfg_eval;
// The file so far is equivalent to src/libcore/prelude/v1.rs,
}
/// An owning iterator over messages on a [`Receiver`],
-/// created by **Receiver::into_iter**.
+/// created by [`into_iter`].
///
/// This iterator will block whenever [`next`]
/// is called, waiting for a new message, and [`None`] will be
/// returned if the corresponding channel has hung up.
///
+/// [`into_iter`]: Receiver::into_iter
/// [`next`]: Iterator::next
///
/// # Examples
} else {
None
};
- let program = resolve_exe(&self.program, child_paths)?;
+ let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
let mut cmd_str =
make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
cmd_str.push(0); // add null terminator
// Therefore this functions first assumes `.exe` was intended.
// It falls back to the plain file name if a full path is given and the extension is omitted
// or if only a file name is given and it already contains an extension.
-fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Result<PathBuf> {
+fn resolve_exe<'a>(
+ exe_path: &'a OsStr,
+ parent_paths: impl FnOnce() -> Option<OsString>,
+ child_paths: Option<&OsStr>,
+) -> io::Result<PathBuf> {
// Early return if there is no filename.
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
return Err(io::Error::new_const(
let has_extension = exe_path.bytes().contains(&b'.');
// Search the directories given by `search_paths`.
- let result = search_paths(child_paths, |mut path| {
+ let result = search_paths(parent_paths, child_paths, |mut path| {
path.push(&exe_path);
if !has_extension {
path.set_extension(EXE_EXTENSION);
// Calls `f` for every path that should be used to find an executable.
// Returns once `f` returns the path to an executable or all paths have been searched.
-fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
+fn search_paths<Paths, Exists>(
+ parent_paths: Paths,
+ child_paths: Option<&OsStr>,
+ mut exists: Exists,
+) -> Option<PathBuf>
where
- F: FnMut(PathBuf) -> Option<PathBuf>,
+ Paths: FnOnce() -> Option<OsString>,
+ Exists: FnMut(PathBuf) -> Option<PathBuf>,
{
// 1. Child paths
// This is for consistency with Rust's historic behaviour.
if let Some(paths) = child_paths {
for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
- if let Some(path) = f(path) {
+ if let Some(path) = exists(path) {
return Some(path);
}
}
// 2. Application path
if let Ok(mut app_path) = env::current_exe() {
app_path.pop();
- if let Some(path) = f(app_path) {
+ if let Some(path) = exists(app_path) {
return Some(path);
}
}
unsafe {
if let Ok(Some(path)) = super::fill_utf16_buf(
|buf, size| c::GetSystemDirectoryW(buf, size),
- |buf| f(PathBuf::from(OsString::from_wide(buf))),
+ |buf| exists(PathBuf::from(OsString::from_wide(buf))),
) {
return Some(path);
}
{
if let Ok(Some(path)) = super::fill_utf16_buf(
|buf, size| c::GetWindowsDirectoryW(buf, size),
- |buf| f(PathBuf::from(OsString::from_wide(buf))),
+ |buf| exists(PathBuf::from(OsString::from_wide(buf))),
) {
return Some(path);
}
}
// 5. Parent paths
- if let Some(parent_paths) = env::var_os("PATH") {
+ if let Some(parent_paths) = parent_paths() {
for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) {
- if let Some(path) = f(path) {
+ if let Some(path) = exists(path) {
return Some(path);
}
}
use super::resolve_exe;
use crate::io;
+ let env_paths = || env::var_os("PATH");
+
// Test a full path, with and without the `exe` extension.
let mut current_exe = env::current_exe().unwrap();
- assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+ assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
current_exe.set_extension("");
- assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+ assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
// Test lone file names.
- assert!(resolve_exe(OsStr::new("cmd"), None).is_ok());
- assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
- assert!(resolve_exe(OsStr::new("cmd.EXE"), None).is_ok());
- assert!(resolve_exe(OsStr::new("fc"), None).is_ok());
+ assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
+ assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
+ assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
+ assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
// Invalid file names should return InvalidInput.
- assert_eq!(resolve_exe(OsStr::new(""), None).unwrap_err().kind(), io::ErrorKind::InvalidInput);
assert_eq!(
- resolve_exe(OsStr::new("\0"), None).unwrap_err().kind(),
+ resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
+ io::ErrorKind::InvalidInput
+ );
+ assert_eq!(
+ resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
// Trailing slash, therefore there's no file name component.
assert_eq!(
- resolve_exe(OsStr::new(r"C:\Path\to\"), None).unwrap_err().kind(),
+ resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
io::ErrorKind::InvalidInput
);
- /* FIXME: fix and re-enable these tests before making changes to the resolver.
-
/*
Some of the following tests may need to be changed if you are deliberately
changing the behaviour of `resolve_exe`.
*/
- let paths = env::var_os("PATH").unwrap();
- env::set_var("PATH", "");
-
- assert_eq!(resolve_exe(OsStr::new("rustc"), None).unwrap_err().kind(), io::ErrorKind::NotFound);
-
- let child_paths = Some(paths.as_os_str());
- assert!(resolve_exe(OsStr::new("rustc"), child_paths).is_ok());
+ let empty_paths = || None;
// The resolver looks in system directories even when `PATH` is empty.
- assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
+ assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
// The application's directory is also searched.
let current_exe = env::current_exe().unwrap();
- assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), None).is_ok());
-
- */
+ assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
}
// the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
pub struct Stdin {
surrogate: u16,
+ incomplete_utf8: IncompleteUtf8,
}
+
pub struct Stdout {
incomplete_utf8: IncompleteUtf8,
}
len: u8,
}
+impl IncompleteUtf8 {
+ // Implemented for use in Stdin::read.
+ fn read(&mut self, buf: &mut [u8]) -> usize {
+ // Write to buffer until the buffer is full or we run out of bytes.
+ let to_write = cmp::min(buf.len(), self.len as usize);
+ buf[..to_write].copy_from_slice(&self.bytes[..to_write]);
+
+ // Rotate the remaining bytes if not enough remaining space in buffer.
+ if usize::from(self.len) > buf.len() {
+ self.bytes.copy_within(to_write.., 0);
+ self.len -= to_write as u8;
+ } else {
+ self.len = 0;
+ }
+
+ to_write
+ }
+}
+
// Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
// #13304 for details).
//
impl Stdin {
pub const fn new() -> Stdin {
- Stdin { surrogate: 0 }
+ Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() }
}
}
}
}
- if buf.len() == 0 {
- return Ok(0);
- } else if buf.len() < 4 {
- return Err(io::Error::new_const(
- io::ErrorKind::InvalidInput,
- &"Windows stdin in console mode does not support a buffer too small to \
- guarantee holding one arbitrary UTF-8 character (4 bytes)",
- ));
+ // If there are bytes in the incomplete utf-8, start with those.
+ // (No-op if there is nothing in the buffer.)
+ let mut bytes_copied = self.incomplete_utf8.read(buf);
+
+ if bytes_copied == buf.len() {
+ return Ok(bytes_copied);
+ } else if buf.len() - bytes_copied < 4 {
+ // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
+ let mut utf16_buf = [0u16; 1];
+ // Read one u16 character.
+ let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?;
+ // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space.
+ let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?;
+
+ // Read in the bytes from incomplete_utf8 until the buffer is full.
+ self.incomplete_utf8.len = read_bytes as u8;
+ // No-op if no bytes.
+ bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]);
+ Ok(bytes_copied)
+ } else {
+ let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
+ // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
+ // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
+ // lost.
+ let amount = cmp::min(buf.len() / 3, utf16_buf.len());
+ let read =
+ read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
+
+ match utf16_to_utf8(&utf16_buf[..read], buf) {
+ Ok(value) => return Ok(bytes_copied + value),
+ Err(e) => return Err(e),
+ }
}
-
- let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
- // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
- // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
- // lost.
- let amount = cmp::min(buf.len() / 3, utf16_buf.len());
- let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
-
- utf16_to_utf8(&utf16_buf[..read], buf)
}
}
-Subproject commit 0716b22e902207efabe46879cbf28d0189ab7924
+Subproject commit 2adc17a5442614dbe34626fdd9b32de7c07b8086
def build_bootstrap(self):
"""Build bootstrap"""
+ print("Building rustbuild")
build_dir = os.path.join(self.build_dir, "bootstrap")
if self.clean and os.path.exists(build_dir):
shutil.rmtree(build_dir)
recorded_submodules[data[3]] = data[2]
for module in filtered_submodules:
self.update_submodule(module[0], module[1], recorded_submodules)
- print("Submodules updated in %.2f seconds" % (time() - start_time))
+ print(" Submodules updated in %.2f seconds" % (time() - start_time))
def set_dist_environment(self, url):
"""Set download URL for normal environment"""
}
};
- if use_new_symbol_mangling {
- rustflags.arg("-Zsymbol-mangling-version=v0");
+ // cfg(bootstrap) -- drop the compiler.stage == 0 branch.
+ if compiler.stage == 0 {
+ if use_new_symbol_mangling {
+ rustflags.arg("-Zsymbol-mangling-version=v0");
+ } else {
+ rustflags.arg("-Zsymbol-mangling-version=legacy");
+ }
} else {
- rustflags.arg("-Zsymbol-mangling-version=legacy");
+ if use_new_symbol_mangling {
+ rustflags.arg("-Csymbol-mangling-version=v0");
+ } else {
+ rustflags.arg("-Csymbol-mangling-version=legacy");
+ rustflags.arg("-Zunstable-options");
+ }
}
// FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
let libdir_bin = libdir.parent().unwrap().join("bin");
t!(fs::create_dir_all(&libdir_bin));
-
if let Some(lld_install) = lld_install {
let src_exe = exe("lld", target_compiler.host);
let dst_exe = exe("rust-lld", target_compiler.host);
}
}
- // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM
- // backend is used to avoid unnecessarily building LLVM and because LLVM is not checked
- // out by default when the LLVM backend is not enabled.
if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
- let src_exe = exe("llvm-dwp", target_compiler.host);
- let dst_exe = exe("rust-llvm-dwp", target_compiler.host);
let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host });
if !builder.config.dry_run {
let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
- builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
// Since we've already built the LLVM tools, install them to the sysroot.
// This is the equivalent of installing the `llvm-tools-preview` component via
// component for now.
maybe_install_llvm_runtime(builder, host, image);
- let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
t!(fs::create_dir_all(&dst_dir));
// Copy over lld if it's there
if builder.config.lld_enabled {
+ let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
let rust_lld = exe("rust-lld", compiler.host);
builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
// for `-Z gcc-ld=lld`
}
}
- // Copy over llvm-dwp if it's there
- let exe = exe("rust-llvm-dwp", compiler.host);
- builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe));
-
// Man pages
t!(fs::create_dir_all(image.join("share/man/man1")));
let man_src = builder.src.join("src/doc/man");
"\n
Arguments:
This subcommand accepts a number of paths to directories to the crates
- and/or artifacts to compile. For example:
-
- ./x.py build library/core
- ./x.py build library/core library/proc_macro
- ./x.py build library/std --stage 1
-
- If no arguments are passed then the complete artifacts for that stage are
- also compiled.
+ and/or artifacts to compile. For example, for a quick build of a usable
+ compiler:
- ./x.py build
- ./x.py build --stage 1
+ ./x.py build --stage 1 library/std
- For a quick build of a usable compiler, you can pass:
+ This will build a compiler and standard library from the local source code.
+ Once this is done, build/$ARCH/stage1 contains a usable compiler.
- ./x.py build --stage 1 library/test
+ If no arguments are passed then the default artifacts for that stage are
+ compiled. For example:
- This will first build everything once (like `--stage 0` without further
- arguments would), and then use the compiler built in stage 0 to build
- library/test and its dependencies.
- Once this is done, build/$ARCH/stage1 contains a usable compiler.",
+ ./x.py build --stage 0
+ ./x.py build ",
);
}
"check" | "c" => {
This subcommand accepts a number of paths to directories to the crates
and/or artifacts to compile. For example:
- ./x.py check library/core
- ./x.py check library/core library/proc_macro
+ ./x.py check library/std
- If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
- also that since we use `cargo check`, by default this will automatically enable incremental
- compilation, so there's no need to pass it separately, though it won't hurt. We also completely
- ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
- the compiler.",
+ If no arguments are passed then many artifacts are checked.",
);
}
"clippy" => {
-Subproject commit 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4
+Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c
-Subproject commit 06f9e61931bcf58b91dfe6c924057e42ce273ee1
+Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b
-Subproject commit 9bf0028b557798ddd07a6f652e4d0c635d3d6620
+Subproject commit 875464457c4104686faf667f47848aa7b0f0a744
}
TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
TyKind::Array(ref ty, ref length) => {
- let def_id = cx.tcx.hir().local_def_id(length.hir_id);
- // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
- // as we currently do not supply the parent generics to anonymous constants
- // but do allow `ConstKind::Param`.
- //
- // `const_eval_poly` tries to to first substitute generic parameters which
- // results in an ICE while manually constructing the constant and using `eval`
- // does nothing for `ConstKind::Param`.
- let ct = ty::Const::from_anon_const(cx.tcx, def_id);
- let param_env = cx.tcx.param_env(def_id);
- let length = print_const(cx, ct.eval(cx.tcx, param_env));
+ let length = match length {
+ hir::ArrayLen::Infer(_, _) => "_".to_string(),
+ hir::ArrayLen::Body(anon_const) => {
+ let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+ // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+ // as we currently do not supply the parent generics to anonymous constants
+ // but do allow `ConstKind::Param`.
+ //
+ // `const_eval_poly` tries to to first substitute generic parameters which
+ // results in an ICE while manually constructing the constant and using `eval`
+ // does nothing for `ConstKind::Param`.
+ let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+ let param_env = cx.tcx.param_env(def_id);
+ print_const(cx, ct.eval(cx.tcx, param_env))
+ }
+ };
+
Array(box ty.clean(cx), length)
}
TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
}
crate trait NestedAttributesExt {
- /// Returns `true` if the attribute list contains a specific `Word`
- fn has_word(self, word: Symbol) -> bool;
+ /// Returns `true` if the attribute list contains a specific `word`
+ fn has_word(self, word: Symbol) -> bool
+ where
+ Self: std::marker::Sized,
+ {
+ <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
+ }
+
+ /// Returns `Some(attr)` if the attribute list contains 'attr'
+ /// corresponding to a specific `word`
fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
}
-impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
- NestedAttributesExt for I
+impl<I> NestedAttributesExt for I
+where
+ I: IntoIterator<Item = ast::NestedMetaItem>,
{
- fn has_word(self, word: Symbol) -> bool {
- self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
- }
-
- fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
- self.find(|attr| attr.is_word() && attr.has_name(word))
+ fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
+ self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
}
}
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
+ font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
margin: 0;
position: relative;
}
h1 {
- font-size: 1.5em;
+ font-size: 1.5rem;
}
h2 {
- font-size: 1.4em;
+ font-size: 1.4rem;
}
h3 {
- font-size: 1.3em;
+ font-size: 1.3rem;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 500;
border-bottom: 1px solid;
}
h3.code-header {
- font-size: 1.1em;
+ font-size: 1.1rem;
}
h4.code-header {
- font-size: 1em;
+ font-size: 1rem;
}
h3.code-header, h4.code-header {
font-weight: 600;
}
.content ul.crate a.crate {
- font-size: 16px/1.6;
+ font-size: 1rem/1.6;
}
ol, ul {
nav.sub {
position: relative;
- font-size: 16px;
+ font-size: 1rem;
text-transform: uppercase;
}
.sidebar .location {
border: 1px solid;
- font-size: 17px;
+ font-size: 1.0625rem;
margin: 30px 10px 20px 10px;
text-align: center;
word-wrap: break-word;
}
.sidebar .version {
- font-size: 15px;
+ font-size: 0.9375rem;
text-align: center;
border-bottom: 1px solid;
overflow-wrap: break-word;
overflow: hidden;
line-height: 15px;
padding: 7px 5px;
- font-size: 14px;
+ font-size: 0.875rem;
font-weight: 300;
transition: border 500ms ease-out;
}
border-top: 1px solid;
border-bottom: 1px solid;
text-align: center;
- font-size: 17px;
+ font-size: 1.0625rem;
margin-bottom: 5px;
font-weight: inherit;
padding: 0;
white-space: pre-wrap;
}
-.top-doc .docblock h2 { font-size: 1.3em; }
-.top-doc .docblock h3 { font-size: 1.15em; }
+.top-doc .docblock h2 { font-size: 1.3rem; }
+.top-doc .docblock h3 { font-size: 1.15rem; }
.top-doc .docblock h4,
.top-doc .docblock h5 {
- font-size: 1.1em;
+ font-size: 1.1rem;
}
.top-doc .docblock h6 {
- font-size: 1em;
+ font-size: 1rem;
}
-.docblock h5 { font-size: 1em; }
-.docblock h6 { font-size: 0.95em; }
+.docblock h5 { font-size: 1rem; }
+.docblock h6 { font-size: 0.95rem; }
.docblock {
margin-left: 24px;
.content .out-of-band {
flex-grow: 0;
text-align: right;
- font-size: 23px;
+ font-size: 1.4375rem;
margin: 0px;
padding: 0 0 0 12px;
font-weight: normal;
.content td { vertical-align: top; }
.content td:first-child { padding-right: 20px; }
.content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; }
.content tr:first-child td { border-top: 0; }
.docblock table {
.content .multi-column li { width: 100%; display: inline-block; }
.content > .methods > .method {
- font-size: 1em;
+ font-size: 1rem;
position: relative;
}
/* Shift "where ..." part of method or fn definition down a line */
.content .fn .where,
.content .where.fmt-newline {
display: block;
- font-size: 0.8em;
+ font-size: 0.8rem;
}
.content .methods > div:not(.notable-traits):not(.method) {
}
.content .item-info code {
- font-size: 90%;
+ font-size: 0.81rem;
}
.content .item-info {
.content .item-info::before {
content: '⬑';
- font-size: 25px;
+ font-size: 1.5625rem;
position: absolute;
top: -6px;
left: -19px;
position: absolute;
top: 0;
right: 0;
- font-size: 17px;
+ font-size: 1.0625rem;
font-weight: normal;
}
border-radius: 1px;
margin-top: 5px;
padding: 10px 16px;
- font-size: 17px;
+ font-size: 1.0625rem;
transition: border-color 300ms ease;
transition: border-radius 300ms ease-in-out;
transition: box-shadow 300ms ease-in-out;
#help span.top, #help span.bottom {
text-align: center;
display: block;
- font-size: 18px;
+ font-size: 1.125rem;
}
#help span.top {
.stab {
padding: 3px;
margin-bottom: 5px;
- font-size: 90%;
+ font-size: 0.9rem;
font-weight: normal;
}
.stab p {
}
.stab .emoji {
- font-size: 1.2em;
+ font-size: 1.2rem;
}
/* Black one-pixel outline around emoji shapes */
.import-item .stab {
border-radius: 3px;
display: inline-block;
- font-size: 80%;
+ font-size: 0.8rem;
line-height: 1.2;
margin-bottom: 0;
margin-left: .3em;
.impl-items .srclink, .impl .srclink, .methods .srclink {
/* Override header settings otherwise it's too bold */
- font-size: 17px;
font-weight: normal;
+ font-size: 1rem;
+}
+.impl .srclink {
+ font-size: 1.0625rem;
}
.rightside {
}
.has-srclink {
- font-size: 16px;
+ font-size: 1rem;
margin-bottom: 12px;
/* Push the src link out to the right edge consistently */
justify-content: space-between;
a.test-arrow {
display: inline-block;
+ visibility: hidden;
position: absolute;
padding: 5px 10px 5px 10px;
border-radius: 5px;
- font-size: 130%;
+ font-size: 1.3rem;
top: 5px;
right: 5px;
z-index: 1;
}
+.example-wrap:hover .test-arrow {
+ visibility: visible;
+}
a.test-arrow:hover{
text-decoration: none;
}
-
.section-header:hover a:before {
position: absolute;
left: -25px;
.out-of-band > span.since {
position: initial;
- font-size: 20px;
+ font-size: 1.25rem;
margin-right: 5px;
}
h3.variant {
font-weight: 600;
- font-size: 1.1em;
+ font-size: 1.1rem;
margin-bottom: 10px;
border-bottom: none;
}
.sub-variant h4 {
- font-size: 1em;
+ font-size: 1rem;
font-weight: 400;
border-bottom: none;
margin-top: 0;
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
- font-size: 16px;
+ font-size: 1rem;
}
.tooltip.ignore::after {
.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
font-weight: bold;
- font-size: 20px;
+ font-size: 1.25rem;
}
.notable-traits-tooltip {
border-radius: 6px;
margin-left: 5px;
z-index: 10;
- font-size: 16px;
+ font-size: 1rem;
cursor: default;
position: absolute;
border: 1px solid;
.notable-traits .notable {
margin: 0;
margin-bottom: 13px;
- font-size: 19px;
+ font-size: 1.1875rem;
font-weight: 600;
}
.notable-traits .docblock code.content{
margin: 0;
padding: 0;
- font-size: 20px;
+ font-size: 1.25rem;
}
/* Example code has the "Run" button that needs to be positioned relative to the pre */
float: left;
width: 33.3%;
text-align: center;
- font-size: 18px;
+ font-size: 1.125rem;
cursor: pointer;
border: 0;
border-top: 2px solid;
#titles > button > div.count {
display: inline-block;
- font-size: 16px;
+ font-size: 1rem;
}
.notable-traits {
left: 0;
cursor: pointer;
font-weight: bold;
- font-size: 1.2em;
+ font-size: 1.2rem;
border-bottom: 1px solid;
display: flex;
height: 40px;
overflow: auto;
}
#source-sidebar > .title {
- font-size: 1.5em;
+ font-size: 1.5rem;
text-align: center;
border-bottom: 1px solid;
margin-bottom: 6px;
#theme-picker, #settings-menu, #help-button, #copy-path {
padding: 4px;
+ /* Rare exception to specifying font sizes in rem. Since these are acting
+ as icons, it's okay to specify their sizes in pixels. */
+ font-size: 16px;
width: 27px;
height: 29px;
border: 1px solid;
right: 30px;
font-family: "Fira Sans", Arial, sans-serif;
text-align: center;
- font-size: 17px;
+ /* Rare exception to specifying font sizes in rem. Since this is acting
+ as an icon, it's okay to specify their sizes in pixels. */
+ font-size: 16px;
padding-top: 2px;
}
border: 0;
border-collapse: collapse;
border-spacing: 0;
- font-size: 16px;
+ font-size: 1rem;
}
.table-display tr td:first-child {
}
.table-display .out-of-band {
position: relative;
- font-size: 19px;
+ font-size: 1.1875rem;
display: block;
}
#implementors-list > .impl-items .table-display .out-of-band {
- font-size: 17px;
+ font-size: 1.0625rem;
}
.table-display td:hover .anchor {
div.name::before {
content: "\25B6";
padding-left: 4px;
- font-size: 0.7em;
+ font-size: 0.7rem;
position: absolute;
left: -16px;
top: 4px;
details.rustdoc-toggle.non-exhaustive > summary,
details.rustdoc-toggle.non-exhaustive > summary::before {
font-family: 'Fira Sans';
- font-size: 16px;
+ font-size: 1rem;
}
details.non-exhaustive {
min-height: 39px;
background: inherit;
text-align: left;
- font-size: 24px;
+ font-size: 1.5rem;
}
.sidebar .location:empty {
}
.show-it > .block.items > ul > li > a {
- font-size: 21px;
+ font-size: 1.3125rem;
}
/* Because of ios, we need to actually have a full height sidebar title so the
color: #999;
}
-:target, :target > * {
- background: rgba(255, 236, 164, 0.06);
-}
-
:target {
+ background: rgba(255, 236, 164, 0.06);
border-right: 3px solid rgba(255, 180, 76, 0.85);
}
color: #999;
}
-:target, :target > * {
- background-color: #494a3d;
-}
-
:target {
+ background-color: #494a3d;
border-right: 3px solid #bb7410;
}
color: #999;
}
-:target, :target > * {
- background: #FDFFD3;
-}
-
:target {
+ background: #FDFFD3;
border-right: 3px solid #AD7C37;
}
);
}
} else if tests.found_tests > 0
- && !cx.cache.access_levels.is_public(item.def_id.expect_def_id())
+ && !cx.cache.access_levels.is_exported(item.def_id.expect_def_id())
{
cx.tcx.struct_span_lint_hir(
crate::lint::PRIVATE_DOC_TESTS,
PerNS,
};
use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::ParentScope;
use rustc_session::lint::Lint;
})
}
+ /// Convert a PrimitiveType to a Ty, where possible.
+ ///
+ /// This is used for resolving trait impls for primitives
+ fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
+ use PrimitiveType::*;
+ let tcx = self.cx.tcx;
+
+ // FIXME: Only simple types are supported here, see if we can support
+ // other types such as Tuple, Array, Slice, etc.
+ // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
+ Some(tcx.mk_ty(match prim {
+ Bool => ty::Bool,
+ Str => ty::Str,
+ Char => ty::Char,
+ Never => ty::Never,
+ I8 => ty::Int(ty::IntTy::I8),
+ I16 => ty::Int(ty::IntTy::I16),
+ I32 => ty::Int(ty::IntTy::I32),
+ I64 => ty::Int(ty::IntTy::I64),
+ I128 => ty::Int(ty::IntTy::I128),
+ Isize => ty::Int(ty::IntTy::Isize),
+ F32 => ty::Float(ty::FloatTy::F32),
+ F64 => ty::Float(ty::FloatTy::F64),
+ U8 => ty::Uint(ty::UintTy::U8),
+ U16 => ty::Uint(ty::UintTy::U16),
+ U32 => ty::Uint(ty::UintTy::U32),
+ U64 => ty::Uint(ty::UintTy::U64),
+ U128 => ty::Uint(ty::UintTy::U128),
+ Usize => ty::Uint(ty::UintTy::Usize),
+ _ => return None,
+ }))
+ }
+
/// Returns:
/// - None if no associated item was found
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
let tcx = self.cx.tcx;
match root_res {
- Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
+ Res::Primitive(prim) => {
+ self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| {
+ let assoc_item = self
+ .primitive_type_to_ty(prim)
+ .map(|ty| {
+ resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
+ })
+ .flatten();
+
+ assoc_item.map(|item| {
+ let kind = item.kind;
+ let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
+ // HACK(jynelson): `clean` expects the type, not the associated item
+ // but the disambiguator logic expects the associated item.
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
+ (root_res, fragment, Some((kind.as_def_kind(), item.def_id)))
+ })
+ })
+ }
Res::Def(DefKind::TyAlias, did) => {
// Resolve the link on the type the alias points to.
// FIXME: if the associated item is defined directly on the type alias,
// To handle that properly resolve() would have to support
// something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
.or_else(|| {
- let item =
- resolve_associated_trait_item(did, module_id, item_name, ns, self.cx);
+ let item = resolve_associated_trait_item(
+ tcx.type_of(did),
+ module_id,
+ item_name,
+ ns,
+ self.cx,
+ );
debug!("got associated item {:?}", item);
item
});
/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
/// find `std::error::Error::source` and return
/// `<io::Error as error::Error>::source`.
-fn resolve_associated_trait_item(
- did: DefId,
+fn resolve_associated_trait_item<'a>(
+ ty: Ty<'a>,
module: DefId,
item_name: Symbol,
ns: Namespace,
- cx: &mut DocContext<'_>,
+ cx: &mut DocContext<'a>,
) -> Option<ty::AssocItem> {
// FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
// `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
// Next consider explicit impls: `impl MyTrait for MyType`
// Give precedence to inherent impls.
- let traits = traits_implemented_by(cx, did, module);
+ let traits = traits_implemented_by(cx, ty, module);
debug!("considering traits {:?}", traits);
let mut candidates = traits.iter().filter_map(|&trait_| {
cx.tcx.associated_items(trait_).find_by_name_and_namespace(
///
/// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
/// So it is not stable to serialize cross-crate.
-fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet<DefId> {
+fn traits_implemented_by<'a>(
+ cx: &mut DocContext<'a>,
+ ty: Ty<'a>,
+ module: DefId,
+) -> FxHashSet<DefId> {
let mut resolver = cx.resolver.borrow_mut();
let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
resolver.access(|resolver| {
});
let tcx = cx.tcx;
- let ty = tcx.type_of(type_);
let iter = in_scope_traits.iter().flat_map(|&trait_| {
trace!("considering explicit impl for trait {:?}", trait_);
"comparing type {} with kind {:?} against type {:?}",
impl_type,
impl_type.kind(),
- type_
+ ty
);
// Fast path: if this is a primitive simple `==` will work
- let saw_impl = impl_type == ty
- || match impl_type.kind() {
- // Check if these are the same def_id
- ty::Adt(def, _) => {
- debug!("adt def_id: {:?}", def.did);
- def.did == type_
- }
- ty::Foreign(def_id) => *def_id == type_,
- _ => false,
- };
+ let saw_impl = impl_type == ty;
if saw_impl { Some(trait_) } else { None }
})
// Const generic parameter
// gdb-command:info functions -q function_names::const_generic_fn.*
// gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>();
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
// Const generic parameter
// cdb-command:x a!function_names::const_generic_fn*
// cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
-// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
+// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void)
// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
[ ! -f $(TMPDIR)/*.dwp ]
[ ! -f $(TMPDIR)/*.dwo ]
-packed:
- $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options
+packed: packed-split packed-single
+
+packed-split:
+ $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=split
+ ls $(TMPDIR)/*.dwp
+ rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+packed-single:
+ $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=single
ls $(TMPDIR)/*.dwp
ls $(TMPDIR)/*.dwo && exit 1 || exit 0
rm -rf $(TMPDIR)/*.dwp
-unpacked:
- $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options
+packed-remapped: packed-remapped-split packed-remapped-single
+
+packed-remapped-split:
+ $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+ -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-remapped-single:
+ $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+ -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-crosscrate: packed-crosscrate-split packed-crosscrate-single
+
+packed-crosscrate-split:
+ $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+ -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
+ ls $(TMPDIR)/*.rlib
+ ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+ ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+ $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+ -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
+ rm $(TMPDIR)/*.dwo
+ rm $(TMPDIR)/main.dwp
+ rm $(TMPDIR)/$(call BIN,main)
+
+packed-crosscrate-single:
+ $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+ -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
+ ls $(TMPDIR)/*.rlib
+ ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+ ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+ $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+ -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+ ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+ rm $(TMPDIR)/main.dwp
+ rm $(TMPDIR)/$(call BIN,main)
+
+unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single
+
+unpacked-split:
+ $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=split
ls $(TMPDIR)/*.dwp && exit 1 || exit 0
ls $(TMPDIR)/*.dwo
- rm -rf $(TMPDIR)/*.dwo
+ rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+unpacked-single:
+ $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=single
+ ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+ ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+
+unpacked-remapped-split:
+ $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+ -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+unpacked-remapped-single:
+ $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+ -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+ objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
endif
endif
--- /dev/null
+pub struct Bar {
+ x: u32,
+}
+
+impl Bar {
+ pub fn print(&self) {
+ println!("{}", self.x);
+ }
+}
+
+pub fn make_bar(x: u32) -> Bar {
+ Bar { x }
+}
+pub struct Foo {
+ x: u32,
+}
+
+impl Foo {
+ pub fn print(&self) {
+ println!("{}", self.x);
+ }
+}
+
+pub fn make_foo(x: u32) -> Foo {
+ Foo { x }
+}
+
fn main() {}
--- /dev/null
+extern crate bar;
+
+use bar::{Bar, make_bar};
+
+fn main() {
+ let b = make_bar(3);
+ b.print();
+}
+++ /dev/null
--include ../tools.mk
-
-# only-linux
-
-all: packed remapped
-
-remapped:
- $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
- objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
- $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
- objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
-packed:
- $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
- rm $(TMPDIR)/foo.dwp
- rm $(TMPDIR)/$(call BIN,foo)
+++ /dev/null
-fn main() {}
--- /dev/null
+// Example code blocks sometimes have a "Run" button to run them on the
+// Playground. That button is hidden until the user hovers over the code block.
+// This test checks that it is hidden, and that it shows on hover.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".test-arrow", {"visibility": "hidden"})
+move-cursor-to: ".example-wrap"
+assert-css: (".test-arrow", {"visibility": "visible"})
--- /dev/null
+// This test ensures that the "[src]" have the same font size as their headers
+// to avoid having some weird height difference in the background when the element
+// is selected.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+show-text: true
+// Check the impl headers.
+assert-css: (".impl.has-srclink .srclink", {"font-size": "17px"}, ALL)
+// The ".6" part is because the font-size is actually "1.1em".
+assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "17.6px"}, ALL)
+// Check the impl items.
+assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
+assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
//! The point of this crate is to be able to have enough different "kinds" of
//! documentation generated so we can test each different features.
+#![doc(html_playground_url="https://play.rust-lang.org/")]
#![crate_name = "test_docs"]
#![feature(rustdoc_internals)]
//! [unit::eq] //~ ERROR unresolved
//! [tuple::eq] //~ ERROR unresolved
//! [fn::eq] //~ ERROR unresolved
-//! [never::eq] //~ ERROR unresolved
// FIXME(#78800): This breaks because it's a blanket impl
// (I think? Might break for other reasons too.)
LL | //! [fn::eq]
| ^^^^^^ the builtin type `fn` has no associated item named `eq`
-error: unresolved link to `never::eq`
- --> $DIR/non-path-primitives.rs:31:6
- |
-LL | //! [never::eq]
- | ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
-
error: unresolved link to `reference::deref`
- --> $DIR/non-path-primitives.rs:35:6
+ --> $DIR/non-path-primitives.rs:34:6
|
LL | //! [reference::deref]
| ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
--- /dev/null
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```
+ /// assert!(false);
+ /// ```
+ //~^^^^^ ERROR documentation test in private item
+ pub fn bar() {}
+}
--- /dev/null
+error: documentation test in private item
+ --> $DIR/private-public-item-doc-test.rs:4:5
+ |
+LL | / /// private doc test
+LL | | ///
+LL | | /// ```
+LL | | /// assert!(false);
+LL | | /// ```
+ | |___________^
+ |
+note: the lint level is defined here
+ --> $DIR/private-public-item-doc-test.rs:1:9
+ |
+LL | #![deny(rustdoc::private_doc_tests)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+pub fn foo() {}
+
+mod private {
+ /// re-exported doc test
+ ///
+ /// ```
+ /// assert!(true);
+ /// ```
+ pub fn bar() {}
+}
+
+pub use private::bar;
--- /dev/null
+#![feature(never_type)]
+use std::str::FromStr;
+
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
+/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
+/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
+/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
+/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
+/// [`str::eq()`] [`never::eq()`]
+pub struct Number {
+ pub f_64: f64,
+ pub f_32: f32,
+ pub i_size: isize,
+ pub i_8: i8,
+ pub i_16: i16,
+ pub i_32: i32,
+ pub i_64: i64,
+ pub i_128: i128,
+ pub u_size: usize,
+ pub u_8: u8,
+ pub u_16: u16,
+ pub u_32: u32,
+ pub u_64: u64,
+ pub u_128: u128,
+ pub ch: char,
+ pub boolean: bool,
+ pub string: str,
+ pub n: !,
+}
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
--- /dev/null
+// Regression test for #92105.
+// ICE when mutating immutable reference from last statement of a block.
+
+fn main() {
+ let foo = Some(&0).unwrap();
+ *foo = 1; //~ ERROR cannot assign
+}
--- /dev/null
+error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
+ --> $DIR/issue-92015.rs:6:5
+ |
+LL | let foo = Some(&0).unwrap();
+ | --- help: consider changing this to be a mutable reference: `&mut i32`
+LL | *foo = 1;
+ | ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
--- /dev/null
+// check-pass
+
+#![feature(c_variadic)]
+
+extern "C" {
+ fn foo(f: isize, x: u8, ...);
+}
+
+fn main() {
+ unsafe {
+ // FIXME: Ideally we could give an unreachable warning
+ foo(1, loop {}, 1usize);
+ }
+}
--- /dev/null
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; _] {
+ //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
+ // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
+ [0; 3]
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
+ --> $DIR/array-in-sig.rs:4:18
+ |
+LL | fn foo() -> [u8; _] {
+ | ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
--- /dev/null
+// run-pass
+
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; 3] {
+ let x: [u8; _] = [0; _];
+ x
+}
+
+fn main() {
+ assert_eq!([0; _], foo());
+}
--- /dev/null
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+ v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+ let a: All<_, _, _>;
+ all_fn();
+ let v: [u8; _];
+ let v: [u8; 10] = [0; _];
+}
--- /dev/null
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/infer-arg-test.rs:7:17
+ |
+LL | struct BadInfer<_>;
+ | ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/infer-arg-test.rs:13:17
+ |
+LL | fn bad_infer_fn<_>() {}
+ | ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+ --> $DIR/infer-arg-test.rs:7:17
+ |
+LL | struct BadInfer<_>;
+ | ^ unused parameter
+ |
+ = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+ = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
+error[E0658]: using `_` for array lengths is unstable
+ --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+ |
+LL | let _x: [u8; 3] = [0; _];
+ | ^
+ |
+ = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+ = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+ |
+LL | let _x: [u8; 3] = [0; _];
+ | ^ `_` not allowed here
+
+error[E0658]: using `_` for array lengths is unstable
+ --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+ |
+LL | let _y: [u8; _] = [0; 3];
+ | ^
+ |
+ = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+ = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+ --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+ |
+LL | let _y: [u8; _] = [0; 3];
+ | ^ `_` not allowed here
+
error[E0747]: type provided when a constant was expected
- --> $DIR/feature-gate-generic_arg_infer.rs:11:20
+ --> $DIR/feature-gate-generic_arg_infer.rs:20:20
|
LL | let _x = foo::<_>([1,2]);
| ^
= help: const arguments cannot yet be inferred with `_`
= help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
-error: aborting due to previous error
+error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0747`.
+Some errors have detailed explanations: E0658, E0747.
+For more information about an error, try `rustc --explain E0658`.
[0; N]
}
+fn bar() {
+ let _x: [u8; 3] = [0; _];
+ //[normal]~^ ERROR: using `_` for array lengths is unstable
+ //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+ let _y: [u8; _] = [0; 3];
+ //[normal]~^ ERROR: using `_` for array lengths is unstable
+ //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+}
+
fn main() {
let _x = foo::<_>([1,2]);
//[normal]~^ ERROR: type provided when a constant was expected
+ let _y = bar();
}
--- /dev/null
+// When a MULTI-character string literal is used where a char should be,
+// DO NOT suggest changing to single quotes.
+
+fn main() {
+ let _: char = "foo"; //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/char-as-str-multi.rs:5:19
+ |
+LL | let _: char = "foo";
+ | ---- ^^^^^ expected `char`, found `&str`
+ | |
+ | expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+ let _: char = 'a'; //~ ERROR mismatched types
+ let _: char = '人'; //~ ERROR mismatched types
+}
--- /dev/null
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+ let _: char = "a"; //~ ERROR mismatched types
+ let _: char = "人"; //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/char-as-str-single.rs:9:19
+ |
+LL | let _: char = "a";
+ | ---- ^^^ expected `char`, found `&str`
+ | |
+ | expected due to this
+ |
+help: if you meant to write a `char` literal, use single quotes
+ |
+LL | let _: char = 'a';
+ | ~~~
+
+error[E0308]: mismatched types
+ --> $DIR/char-as-str-single.rs:10:19
+ |
+LL | let _: char = "人";
+ | ---- ^^^^ expected `char`, found `&str`
+ | |
+ | expected due to this
+ |
+help: if you meant to write a `char` literal, use single quotes
+ |
+LL | let _: char = '人';
+ | ~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-#![feature(generic_arg_infer)]
-
-struct All<'a, T, const N: usize> {
- v: &'a T,
-}
-
-struct BadInfer<_>;
-//~^ ERROR expected identifier
-//~| ERROR parameter `_` is never used
-
-fn all_fn<'a, T, const N: usize>() {}
-
-fn bad_infer_fn<_>() {}
-//~^ ERROR expected identifier
-
-
-fn main() {
- let a: All<_, _, _>;
- all_fn();
- let v: [u8; _];
- //~^ ERROR in expressions
- let v: [u8; 10] = [0; _];
- //~^ ERROR in expressions
-}
+++ /dev/null
-error: expected identifier, found reserved identifier `_`
- --> $DIR/infer-arg-test.rs:7:17
- |
-LL | struct BadInfer<_>;
- | ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
- --> $DIR/infer-arg-test.rs:13:17
- |
-LL | fn bad_infer_fn<_>() {}
- | ^ expected identifier, found reserved identifier
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/infer-arg-test.rs:20:15
- |
-LL | let v: [u8; _];
- | ^ `_` not allowed here
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
- --> $DIR/infer-arg-test.rs:22:25
- |
-LL | let v: [u8; 10] = [0; _];
- | ^ `_` not allowed here
-
-error[E0392]: parameter `_` is never used
- --> $DIR/infer-arg-test.rs:7:17
- |
-LL | struct BadInfer<_>;
- | ^ unused parameter
- |
- = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `_` to be a const parameter, use `const _: usize` instead
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
--- /dev/null
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+ let _: &str = "a"; //~ ERROR mismatched types
+}
--- /dev/null
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+ let _: &str = 'a'; //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/str-as-char.rs:7:19
+ |
+LL | let _: &str = 'a';
+ | ---- ^^^ expected `&str`, found `char`
+ | |
+ | expected due to this
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let _: &str = "a";
+ | ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
LL | let v: Vec(&str) = vec!['1', '2'];
| ^^^ expected `&str`, found `char`
+ |
+help: if you meant to write a `str` literal, use double quotes
+ |
+LL | let v: Vec(&str) = vec!["1", '2'];
+ | ~~~
error: aborting due to 2 previous errors
stringify_item!(
impl<T> Struct<T> {}
),
- "impl <T> Struct<T> {}", // FIXME
+ "impl<T> Struct<T> {}",
);
assert_eq!(
stringify_item!(
),
"pub impl Trait for Struct {}",
);
+ assert_eq!(
+ stringify_item!(
+ impl<T> const Trait for T {}
+ ),
+ "impl<T> const Trait for T {}",
+ );
assert_eq!(
stringify_item!(
impl ~const Struct {}
--- /dev/null
+// Regression test for issue 81708 and issue 91816 where running a drop
+// elaboration on a MIR which failed borrowck lead to an ICE.
+
+static A: () = {
+ let a: [String; 1];
+ //~^ ERROR destructors cannot be evaluated at compile-time
+ a[0] = String::new();
+ //~^ ERROR destructors cannot be evaluated at compile-time
+ //~| ERROR use of possibly-uninitialized variable
+};
+
+struct B<T>([T; 1]);
+
+impl<T> B<T> {
+ pub const fn f(mut self, other: T) -> Self {
+ let _this = self;
+ //~^ ERROR destructors cannot be evaluated at compile-time
+ self.0[0] = other;
+ //~^ ERROR destructors cannot be evaluated at compile-time
+ //~| ERROR use of moved value
+ self
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+ |
+LL | a[0] = String::new();
+ | ^^^^
+ | |
+ | statics cannot evaluate destructors
+ | value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:5:9
+ |
+LL | let a: [String; 1];
+ | ^ statics cannot evaluate destructors
+...
+LL | };
+ | - value is dropped here
+
+error[E0381]: use of possibly-uninitialized variable: `a`
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+ |
+LL | a[0] = String::new();
+ | ^^^^ use of possibly-uninitialized `a`
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+ |
+LL | self.0[0] = other;
+ | ^^^^^^^^^
+ | |
+ | constant functions cannot evaluate destructors
+ | value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:16:13
+ |
+LL | let _this = self;
+ | ^^^^^ constant functions cannot evaluate destructors
+...
+LL | }
+ | - value is dropped here
+
+error[E0382]: use of moved value: `self.0`
+ --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+ |
+LL | pub const fn f(mut self, other: T) -> Self {
+ | -------- move occurs because `self` has type `B<T>`, which does not implement the `Copy` trait
+LL | let _this = self;
+ | ---- value moved here
+LL |
+LL | self.0[0] = other;
+ | ^^^^^^^^^ value used here after move
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0381, E0382, E0493.
+For more information about an error, try `rustc --explain E0381`.
+// This test has been spuriously failing a lot recently (#92000).
+// Ignore it until the underlying issue is fixed.
+// ignore-test
+
// Regression test for #87481: short backtrace formatting cut off the entire stack trace.
// Codegen-units is specified here so that we can replicate a typical rustc invocation which
-Subproject commit fcef61230c3b6213b6b0d233a36ba4ebd1649ec3
+Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d
if let ItemKind::Struct(data, _) = &item.kind;
if let Some(last_field) = data.fields().last();
if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
+ if let rustc_hir::ArrayLen::Body(length) = length;
// Then check if that that array zero-sized
let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::{Ident, Symbol};
bind!(self, value, length);
kind!("Repeat({value}, {length})");
self.expr(value);
- self.body(field!(length.body));
+ match length.value {
+ ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"),
+ ArrayLen::Body(anon_const) => {
+ bind!(self, anon_const);
+ out!("if let ArrayLen::Body({anon_const}) = {length};");
+ self.body(field!(anon_const.body));
+ }
+ }
},
ExprKind::Err => kind!("Err"),
ExprKind::DropTemps(expr) => {
println!("{}anon_const:", ind);
print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
},
- hir::ExprKind::Repeat(val, ref anon_const) => {
+ hir::ExprKind::Repeat(val, length) => {
println!("{}Repeat", ind);
println!("{}value:", ind);
print_expr(cx, val, indent + 1);
println!("{}repeat count:", ind);
- print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+ match length {
+ hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
+ hir::ArrayLen::Body(anon_const) => {
+ print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1)
+ }
+ }
},
hir::ExprKind::Err => {
println!("{}Err", ind);
use rustc_hir::{
BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
- StmtKind, Ty, TyKind, TypeBinding,
+ StmtKind, Ty, TyKind, TypeBinding, ArrayLen
};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
}
}
+ pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool {
+ match (left, right) {
+ (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
+ (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body),
+ (_, _) => false,
+ }
+ }
+
pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
let cx = self.inner.cx;
let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
}
let is_eq = match (
- &reduce_exprkind(self.inner.cx, &left.kind),
- &reduce_exprkind(self.inner.cx, &right.kind),
+ reduce_exprkind(self.inner.cx, &left.kind),
+ reduce_exprkind(self.inner.cx, &right.kind),
) {
(&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
lb == rb && l_mut == r_mut && self.eq_expr(le, re)
},
(&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
(&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
- self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
+ self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
},
(&ExprKind::Let(l), &ExprKind::Let(r)) => {
self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
(&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
- self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
+ (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
+ self.eq_expr(le, re) && self.eq_array_length(ll, rl)
},
(&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
(&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
match (&left.kind, &right.kind) {
(&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
- (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
- self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
+ (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => {
+ self.eq_ty(lt, rt) && self.eq_array_length(ll, rl)
},
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
ExprKind::ConstBlock(ref l_id) => {
self.hash_body(l_id.body);
},
- ExprKind::Repeat(e, ref l_id) => {
+ ExprKind::Repeat(e, len) => {
self.hash_expr(e);
- self.hash_body(l_id.body);
+ self.hash_array_length(len);
},
ExprKind::Ret(ref e) => {
if let Some(e) = *e {
TyKind::Slice(ty) => {
self.hash_ty(ty);
},
- TyKind::Array(ty, anon_const) => {
+ &TyKind::Array(ty, len) => {
self.hash_ty(ty);
- self.hash_body(anon_const.body);
+ self.hash_array_length(len);
},
TyKind::Ptr(ref mut_ty) => {
self.hash_ty(mut_ty.ty);
}
}
+ pub fn hash_array_length(&mut self, length: ArrayLen) {
+ match length {
+ ArrayLen::Infer(..) => {}
+ ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
+ }
+ }
+
pub fn hash_body(&mut self, body_id: BodyId) {
// swap out TypeckResults when hashing a body
let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
def, Arm, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem,
- TraitItemKind, TraitRef, TyKind, UnOp,
+ TraitItemKind, TraitRef, TyKind, UnOp, ArrayLen
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::exports::Export;
_ => false,
},
ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
- ExprKind::Repeat(x, y) => if_chain! {
- if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
+ ExprKind::Repeat(x, len) => if_chain! {
+ if let ArrayLen::Body(len) = len;
+ if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
if let LitKind::Int(v, _) = const_lit.node;
if v <= 32 && is_default_equivalent(cx, x);
then {
if let ExprKind::Repeat(value, length) = expr.kind;
if let ExprKind::Lit(ref lit) = value.kind;
if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
- let expr1 = &cx.tcx.hir().body(length.body).value;
+ if let ArrayLen::Body(anon_const) = length;
+ let expr1 = &cx.tcx.hir().body(anon_const.body).value;
if let ExprKind::Lit(ref lit1) = expr1.kind;
if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
then {
-Subproject commit d307e6c1970d1edb63d6a08d332e0acdb72c5cc5
+Subproject commit 824816c973a3fd0596ae3a9a38c6fb6299b913b8
-Subproject commit 68319187d63707fa36d7c215ed0e444e87d9652a
+Subproject commit 8e9ccbf97a70259b6c6576e8fd7d77d28238737e
"env_logger",
"expect-test",
"fake-simd",
+ "fallible-iterator", // dependency of `thorin`
"filetime",
"fixedbitset",
"flate2",
"tempfile",
"termcolor",
"termize",
+ "thorin-dwp",
"thread_local",
"time",
"tinyvec",