"rand 0.8.3",
"rustc-workspace-hack",
"rustfix",
- "semver 1.0.1",
+ "semver 1.0.3",
"serde",
"serde_ignored",
"serde_json",
[[package]]
name = "compiler_builtins"
-version = "0.1.43"
+version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
+checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
dependencies = [
"cc",
"rustc-std-workspace-core",
[[package]]
name = "memchr"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "memmap2"
"rustc-std-workspace-core",
]
+[[package]]
+name = "object"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
[[package]]
name = "once_cell"
version = "1.7.2"
"itertools 0.9.0",
"jobserver",
"libc",
- "object",
+ "object 0.25.2",
"pathdiff",
"rustc_apfloat",
"rustc_ast",
[[package]]
name = "semver"
-version = "1.0.1"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d023dabf011d5dcb5ac64e3685d97d3b0ef412911077a2851455c6098524a723"
+checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
dependencies = [
"serde",
]
"hermit-abi",
"libc",
"miniz_oxide",
- "object",
+ "object 0.22.0",
"panic_abort",
"panic_unwind",
"profiler_builtins",
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
- _ => panic!("Called tokens_mut on {:?}", self),
+ Nonterminal::NtBlock(block) => block.tokens_mut(),
+ Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
}
}
}
AttrAnnotatedTokenTree::Attributes(data) => {
let mut outer_attrs = Vec::new();
let mut inner_attrs = Vec::new();
- let attrs: Vec<_> = data.attrs.clone().into();
- for attr in attrs {
+ for attr in &data.attrs {
match attr.style {
crate::AttrStyle::Outer => {
assert!(
// so we never reach this code.
let mut builder = TokenStreamBuilder::new();
- for inner_attr in &inner_attrs {
+ for inner_attr in inner_attrs {
builder.push(inner_attr.tokens().to_tokenstream());
}
builder.push(delim_tokens.clone());
}}
gate_doc!(
- include => external_doc
cfg => doc_cfg
masked => doc_masked
notable_trait => doc_notable_trait
"allow_fail",
cx.expr_bool(sp, should_fail(&cx.sess, &item)),
),
+ // compile_fail: true | false
+ field("compile_fail", cx.expr_bool(sp, false)),
+ // no_run: true | false
+ field("no_run", cx.expr_bool(sp, false)),
// should_panic: ...
field(
"should_panic",
}
}
}
+
+ fn inject_dll_import_lib(
+ &mut self,
+ _lib_name: &str,
+ _dll_imports: &[rustc_middle::middle::cstore::DllImport],
+ _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
+ ) {
+ bug!("injecting dll imports is not supported");
+ }
}
impl<'a> ArArchiveBuilder<'a> {
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
- use rustc_span::symbol::sym;
-
- let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
- let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
- let windows_subsystem = subsystem.map(|subsystem| {
- if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
- }
- subsystem.to_string()
- });
-
let mut work_products = FxHashMap::default();
let cgus = if tcx.sess.opts.output_types.should_codegen() {
Box::new((
CodegenResults {
- crate_name: tcx.crate_name(LOCAL_CRATE),
modules,
allocator_module,
metadata_module,
metadata,
- windows_subsystem,
linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
crate_info: CrateInfo::new(tcx),
},
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
}
}
- fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, _providers: &mut Providers) {}
- fn provide_extern(&self, _providers: &mut Providers) {}
-
fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
vec![]
}
+ fn print_version(&self) {
+ println!("Cranelift version: {}", cranelift_codegen::VERSION);
+ }
+
fn codegen_crate(
&self,
tcx: TyCtxt<'_>,
sess,
&codegen_results,
outputs,
- &codegen_results.crate_name.as_str(),
+ &codegen_results.crate_info.local_crate_name.as_str(),
);
Ok(())
use std::path::PathBuf;
-use rustc_middle::bug;
+use rustc_codegen_ssa::back::link::linker_and_flavor;
use rustc_session::Session;
-use rustc_target::spec::LinkerFlavor;
/// Tries to infer the path of a binary for the target toolchain from the linker name.
pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
linker
}
-
-// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
- fn infer_from(
- sess: &Session,
- linker: Option<PathBuf>,
- flavor: Option<LinkerFlavor>,
- ) -> Option<(PathBuf, LinkerFlavor)> {
- match (linker, flavor) {
- (Some(linker), Some(flavor)) => Some((linker, flavor)),
- // only the linker flavor is known; use the default linker for the selected flavor
- (None, Some(flavor)) => Some((
- PathBuf::from(match flavor {
- LinkerFlavor::Em => {
- if cfg!(windows) {
- "emcc.bat"
- } else {
- "emcc"
- }
- }
- LinkerFlavor::Gcc => {
- if cfg!(any(target_os = "solaris", target_os = "illumos")) {
- // On historical Solaris systems, "cc" may have
- // been Sun Studio, which is not flag-compatible
- // with "gcc". This history casts a long shadow,
- // and many modern illumos distributions today
- // ship GCC as "gcc" without also making it
- // available as "cc".
- "gcc"
- } else {
- "cc"
- }
- }
- LinkerFlavor::Ld => "ld",
- LinkerFlavor::Msvc => "link.exe",
- LinkerFlavor::Lld(_) => "lld",
- LinkerFlavor::PtxLinker => "rust-ptx-linker",
- }),
- flavor,
- )),
- (Some(linker), None) => {
- let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
- sess.fatal("couldn't extract file stem from specified linker")
- });
-
- let flavor = if stem == "emcc" {
- LinkerFlavor::Em
- } else if stem == "gcc"
- || stem.ends_with("-gcc")
- || stem == "clang"
- || stem.ends_with("-clang")
- {
- LinkerFlavor::Gcc
- } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
- LinkerFlavor::Ld
- } else if stem == "link" || stem == "lld-link" {
- LinkerFlavor::Msvc
- } else if stem == "lld" || stem == "rust-lld" {
- LinkerFlavor::Lld(sess.target.lld_flavor)
- } else {
- // fall back to the value in the target spec
- sess.target.linker_flavor
- };
-
- Some((linker, flavor))
- }
- (None, None) => None,
- }
- }
-
- // linker and linker flavor specified via command line have precedence over what the target
- // specification specifies
- if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
- return ret;
- }
-
- if let Some(ret) = infer_from(
- sess,
- sess.target.linker.clone().map(PathBuf::from),
- Some(sess.target.linker_flavor),
- ) {
- return ret;
- }
-
- bug!("Not enough information provided to determine how to invoke the linker");
-}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 => {}
+ InlineAsmArch::Bpf => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
+ InlineAsmRegClass::Bpf(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
use std::str;
use crate::llvm::archive_ro::{ArchiveRO, Child};
-use crate::llvm::{self, ArchiveKind};
+use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
}
}
+/// Map machine type strings to values of LLVM's MachineTypes enum.
+fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
+ match cpu {
+ "x86_64" => LLVMMachineType::AMD64,
+ "x86" => LLVMMachineType::I386,
+ "aarch64" => LLVMMachineType::ARM64,
+ "arm" => LLVMMachineType::ARM,
+ _ => panic!("unsupported cpu type {}", cpu),
+ }
+}
+
impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
/// Creates a new static archive, ready for modifying the archive specified
/// by `config`.
self.config.sess.fatal(&format!("failed to build archive: {}", e));
}
}
+
+ fn inject_dll_import_lib(
+ &mut self,
+ lib_name: &str,
+ dll_imports: &[DllImport],
+ tmpdir: &MaybeTempDir,
+ ) {
+ let output_path = {
+ let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+ output_path.push(format!("{}_imports", lib_name));
+ output_path.with_extension("lib")
+ };
+
+ // we've checked for \0 characters in the library name already
+ let dll_name_z = CString::new(lib_name).unwrap();
+ // All import names are Rust identifiers and therefore cannot contain \0 characters.
+ // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
+ // have any \0 characters
+ let import_name_vector: Vec<CString> = dll_imports
+ .iter()
+ .map(if self.config.sess.target.arch == "x86" {
+ |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
+ } else {
+ |import: &DllImport| CString::new(import.name.to_string()).unwrap()
+ })
+ .collect();
+
+ let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+ tracing::trace!("invoking LLVMRustWriteImportLibrary");
+ tracing::trace!(" dll_name {:#?}", dll_name_z);
+ tracing::trace!(" output_path {}", output_path.display());
+ tracing::trace!(
+ " import names: {}",
+ dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
+ );
+
+ let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
+ .iter()
+ .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
+ .collect();
+ let result = unsafe {
+ crate::llvm::LLVMRustWriteImportLibrary(
+ dll_name_z.as_ptr(),
+ output_path_z.as_ptr(),
+ ffi_exports.as_ptr(),
+ ffi_exports.len(),
+ llvm_machine_type(&self.config.sess.target.arch) as u16,
+ !self.config.sess.target.is_like_msvc,
+ )
+ };
+
+ if result == crate::llvm::LLVMRustResult::Failure {
+ self.config.sess.fatal(&format!(
+ "Error creating import library for {}: {}",
+ lib_name,
+ llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+ ));
+ }
+
+ self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+ self.config.sess.fatal(&format!(
+ "failed to add native library {}: {}",
+ output_path.display(),
+ e
+ ));
+ });
+ }
}
impl<'a> LlvmArchiveBuilder<'a> {
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{ErrorReported, FatalError, Handler};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
use rustc_session::Session;
use rustc_span::symbol::Symbol;
target_features(sess)
}
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, _providers: &mut ty::query::Providers) {}
- fn provide_extern(&self, _providers: &mut ty::query::Providers) {}
-
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
sess,
&codegen_results,
outputs,
- &codegen_results.crate_name.as_str(),
+ &codegen_results.crate_info.local_crate_name.as_str(),
);
Ok(())
Success,
Failure,
}
+
+// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp.
+#[repr(C)]
+pub struct LLVMRustCOFFShortExport {
+ pub name: *const c_char,
+}
+
+impl LLVMRustCOFFShortExport {
+ pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
+ LLVMRustCOFFShortExport { name }
+ }
+}
+
+/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
+///
+/// We include only architectures supported on Windows.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMMachineType {
+ AMD64 = 0x8664,
+ I386 = 0x14c,
+ ARM64 = 0xaa64,
+ ARM = 0x01c0,
+}
+
// Consts for the LLVM CallConv type, pre-cast to usize.
/// LLVM CallingConv::ID. Should we wrap this?
extern "C" {
pub type PassManagerBuilder;
}
-extern "C" {
- pub type ObjectFile;
-}
-#[repr(C)]
-pub struct SectionIterator<'a>(InvariantOpaque<'a>);
extern "C" {
pub type Pass;
}
pub fn LLVMDisposeMessage(message: *mut c_char);
- // Stuff that's in llvm-wrapper/ because it's not upstream yet.
-
- /// Opens an object file.
- pub fn LLVMCreateObjectFile(
- MemBuf: &'static mut MemoryBuffer,
- ) -> Option<&'static mut ObjectFile>;
- /// Closes an object file.
- pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
-
- /// Enumerates the sections in an object file.
- pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
- /// Destroys a section iterator.
- pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
- /// Returns `true` if the section iterator is at the end of the section
- /// list:
- pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
- /// Moves the section iterator to point to the next section.
- pub fn LLVMMoveToNextSection(SI: &SectionIterator<'_>);
- /// Returns the current section size.
- pub fn LLVMGetSectionSize(SI: &SectionIterator<'_>) -> c_ulonglong;
- /// Returns the current section contents as a string buffer.
- pub fn LLVMGetSectionContents(SI: &SectionIterator<'_>) -> *const c_char;
-
- /// Reads the given file and returns it as a memory buffer. Use
- /// LLVMDisposeMemoryBuffer() to get rid of it.
- pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
- Path: *const c_char,
- ) -> Option<&'static mut MemoryBuffer>;
-
pub fn LLVMStartMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
- #[allow(improper_ctypes)]
- pub fn LLVMRustGetSectionName(
- SI: &SectionIterator<'_>,
- data: &mut Option<std::ptr::NonNull<c_char>>,
- ) -> size_t;
-
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
) -> &'a mut RustArchiveMember<'a>;
pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
+ pub fn LLVMRustWriteImportLibrary(
+ ImportName: *const c_char,
+ Path: *const c_char,
+ Exports: *const LLVMRustCOFFShortExport,
+ NumExports: usize,
+ Machine: u16,
+ MinGW: bool,
+ ) -> LLVMRustResult;
+
pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
pub fn LLVMRustBuildOperandBundleDef(
}
}
-// Memory-managed interface to object files.
-
-pub struct ObjectFile {
- pub llof: &'static mut ffi::ObjectFile,
-}
-
-unsafe impl Send for ObjectFile {}
-
-impl ObjectFile {
- // This will take ownership of llmb
- pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
- unsafe {
- let llof = LLVMCreateObjectFile(llmb)?;
- Some(ObjectFile { llof })
- }
- }
-}
-
-impl Drop for ObjectFile {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
- }
- }
-}
-
-// Memory-managed interface to section iterators.
-
-pub struct SectionIter<'a> {
- pub llsi: &'a mut SectionIterator<'a>,
-}
-
-impl Drop for SectionIter<'a> {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
- }
- }
-}
-
-pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
- unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
-}
-
pub fn set_section(llglobal: &Value, section_name: &str) {
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
unsafe {
rustc_session = { path = "../rustc_session" }
[dependencies.object]
-version = "0.22.0"
+version = "0.25.2"
default-features = false
-features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"]
+features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
fn update_symbols(&mut self);
fn build(self);
+
+ fn inject_dll_import_lib(
+ &mut self,
+ lib_name: &str,
+ dll_imports: &[DllImport],
+ tmpdir: &MaybeTempDir,
+ );
}
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::Handler;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
+use rustc_middle::middle::cstore::{DllImport, LibSource};
use rustc_middle::middle::dependency_format::Linkage;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
+use rustc_target::abi::Endian;
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
};
use cc::windows_registry;
+use object::elf;
+use object::write::Object;
+use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
use tempfile::Builder as TempFileBuilder;
+use std::cmp::Ordering;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
/// directory being searched for `extern crate` (observing an incomplete file).
/// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
+pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
- let result = fs::write(&out_filename, &metadata.raw_data);
+ let result = fs::write(&out_filename, metadata);
if let Err(e) = result {
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
}
}
+ for (raw_dylib_name, raw_dylib_imports) in
+ collate_raw_dylibs(&codegen_results.crate_info.used_libraries)
+ {
+ ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
+ }
+
// After adding all files to the archive, we need to update the
// symbol table of the archive.
ab.update_symbols();
// code above.
match flavor {
RlibFlavor::Normal => {
- // Instead of putting the metadata in an object file section, rlibs
- // contain the metadata in a separate file.
- ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
+ // metadata in rlib files is wrapped in a "dummy" object file for
+ // the target platform so the rlib can be processed entirely by
+ // normal linkers for the platform.
+ let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
+ ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
// After adding all files to the archive, we need to update the
// symbol table of the archive. This currently dies on macOS (see
}
}
}
+ return ab;
+
+ // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
+ // creates a dylib crate type it will pass `--whole-archive` (or the
+ // platform equivalent) to include all object files from an rlib into the
+ // final dylib itself. This causes linkers to iterate and try to include all
+ // files located in an archive, so if metadata is stored in an archive then
+ // it needs to be of a form that the linker will be able to process.
+ //
+ // Note, though, that we don't actually want this metadata to show up in any
+ // final output of the compiler. Instead this is purely for rustc's own
+ // metadata tracking purposes.
+ //
+ // With the above in mind, each "flavor" of object format gets special
+ // handling here depending on the target:
+ //
+ // * MachO - macos-like targets will insert the metadata into a section that
+ // is sort of fake dwarf debug info. Inspecting the source of the macos
+ // linker this causes these sections to be skipped automatically because
+ // it's not in an allowlist of otherwise well known dwarf section names to
+ // go into the final artifact.
+ //
+ // * WebAssembly - we actually don't have any container format for this
+ // target. WebAssembly doesn't support the `dylib` crate type anyway so
+ // there's no need for us to support this at this time. Consequently the
+ // metadata bytes are simply stored as-is into an rlib.
+ //
+ // * COFF - Windows-like targets create an object with a section that has
+ // the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
+ // ever sees the section it doesn't process it and it's removed.
+ //
+ // * ELF - All other targets are similar to Windows in that there's a
+ // `SHF_EXCLUDE` flag we can set on sections in an object file to get
+ // automatically removed from the final output.
+ //
+ // Note that this metdata format is kept in sync with
+ // `rustc_codegen_ssa/src/back/metadata.rs`.
+ fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+ let endianness = match sess.target.options.endian {
+ Endian::Little => Endianness::Little,
+ Endian::Big => Endianness::Big,
+ };
+ let architecture = match &sess.target.arch[..] {
+ "arm" => Architecture::Arm,
+ "aarch64" => Architecture::Aarch64,
+ "x86" => Architecture::I386,
+ "s390x" => Architecture::S390x,
+ "mips" => Architecture::Mips,
+ "mips64" => Architecture::Mips64,
+ "x86_64" => {
+ if sess.target.pointer_width == 32 {
+ Architecture::X86_64_X32
+ } else {
+ Architecture::X86_64
+ }
+ }
+ "powerpc" => Architecture::PowerPc,
+ "powerpc64" => Architecture::PowerPc64,
+ "riscv32" => Architecture::Riscv32,
+ "riscv64" => Architecture::Riscv64,
+ "sparc64" => Architecture::Sparc64,
+
+ // This is used to handle all "other" targets. This includes targets
+ // in two categories:
+ //
+ // * Some targets don't have support in the `object` crate just yet
+ // to write an object file. These targets are likely to get filled
+ // out over time.
+ //
+ // * Targets like WebAssembly don't support dylibs, so the purpose
+ // of putting metadata in object files, to support linking rlibs
+ // into dylibs, is moot.
+ //
+ // In both of these cases it means that linking into dylibs will
+ // not be supported by rustc. This doesn't matter for targets like
+ // WebAssembly and for targets not supported by the `object` crate
+ // yet it means that work will need to be done in the `object` crate
+ // to add a case above.
+ _ => return metadata.to_vec(),
+ };
+
+ if sess.target.is_like_osx {
+ let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
+
+ let section =
+ file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else if sess.target.is_like_windows {
+ const IMAGE_SCN_LNK_REMOVE: u32 = 0;
+ let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags =
+ SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ } else {
+ const SHF_EXCLUDE: u64 = 0x80000000;
+ let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
+
+ match &sess.target.arch[..] {
+ // copied from `mipsel-linux-gnu-gcc foo.c -c` and
+ // inspecting the resulting `e_flags` field.
+ "mips" => {
+ let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+ // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
+ "mips64" => {
+ let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
+ // that the `+d` target feature represents whether the double
+ // float abi is enabled.
+ "riscv64" if sess.target.options.features.contains("+d") => {
+ let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+ file.flags = FileFlags::Elf { e_flags };
+ }
+
+ _ => {}
+ }
+
+ let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+ file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+ file.append_section_data(section, metadata, 1);
+ file.write().unwrap()
+ }
+ }
+}
+
+/// Extract all symbols defined in raw-dylib libraries, collated by library name.
+///
+/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
+/// then the CodegenResults value contains one NativeLib instance for each block. However, the
+/// linker appears to expect only a single import library for each library used, so we need to
+/// collate the symbols together by library name before generating the import libraries.
+fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> {
+ let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default();
+
+ for lib in used_libraries {
+ if lib.kind == NativeLibKind::RawDylib {
+ let name = lib.name.unwrap_or_else(||
+ bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier")
+ );
+ let name = if matches!(lib.verbatim, Some(true)) {
+ name.to_string()
+ } else {
+ format!("{}.dll", name)
+ };
+ dylib_table
+ .entry(name)
+ .or_default()
+ .extend(lib.dll_imports.iter().map(|import| import.name));
+ }
+ }
- ab
+ // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out
+ // what we should do if we have two DllImport values with the same name but different
+ // ordinals.
+ let mut result = dylib_table
+ .into_iter()
+ .map(|(lib_name, imported_names)| {
+ let mut names = imported_names
+ .iter()
+ .map(|name| DllImport { name: *name, ordinal: None })
+ .collect::<Vec<_>>();
+ names.sort_unstable_by(|a: &DllImport, b: &DllImport| {
+ match a.name.as_str().cmp(&b.name.as_str()) {
+ Ordering::Equal => a.ordinal.cmp(&b.ordinal),
+ x => x,
+ }
+ });
+ (lib_name, names)
+ })
+ .collect::<Vec<_>>();
+ result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
+ a.0.cmp(&b.0)
+ });
+ result
}
/// Create a static archive.
}
}
-fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
+fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
// On macOS the runtimes are distributed as dylibs which should be linked to
// both executables and dynamic shared objects. Everywhere else the runtimes
// are currently distributed as static liraries which should be linked to
&& (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
}
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
+// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
+pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
fn infer_from(
sess: &Session,
linker: Option<PathBuf>,
LinkerFlavor::Msvc => "link.exe",
LinkerFlavor::Lld(_) => "lld",
LinkerFlavor::PtxLinker => "rust-ptx-linker",
+ LinkerFlavor::BpfLinker => "bpf-linker",
}),
flavor,
)),
|| stem.ends_with("-clang")
{
LinkerFlavor::Gcc
+ } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
+ LinkerFlavor::Lld(LldFlavor::Wasm)
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
LinkerFlavor::Ld
} else if stem == "link" || stem == "lld-link" {
}
}
-/// Link native libraries corresponding to the current crate and all libraries corresponding to
-/// all its dependency crates.
-/// FIXME: Consider combining this with the functions above adding object files for the local crate.
-fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>(
- cmd: &mut dyn Linker,
- sess: &'a Session,
- crate_type: CrateType,
- codegen_results: &CodegenResults,
- tmpdir: &Path,
-) {
- // Take careful note of the ordering of the arguments we pass to the linker
- // here. Linkers will assume that things on the left depend on things to the
- // right. Things on the right cannot depend on things on the left. This is
- // all formally implemented in terms of resolving symbols (libs on the right
- // resolve unknown symbols of libs on the left, but not vice versa).
- //
- // For this reason, we have organized the arguments we pass to the linker as
- // such:
- //
- // 1. The local object that LLVM just generated
- // 2. Local native libraries
- // 3. Upstream rust libraries
- // 4. Upstream native libraries
- //
- // The rationale behind this ordering is that those items lower down in the
- // list can't depend on items higher up in the list. For example nothing can
- // depend on what we just generated (e.g., that'd be a circular dependency).
- // Upstream rust libraries are not allowed to depend on our local native
- // libraries as that would violate the structure of the DAG, in that
- // scenario they are required to link to them as well in a shared fashion.
- //
- // Note that upstream rust libraries may contain native dependencies as
- // well, but they also can't depend on what we just started to add to the
- // link line. And finally upstream native libraries can't depend on anything
- // in this DAG so far because they're only dylibs and dylibs can only depend
- // on other dylibs (e.g., other native deps).
- //
- // If -Zlink-native-libraries=false is set, then the assumption is that an
- // external build system already has the native dependencies defined, and it
- // will provide them to the linker itself.
- if sess.opts.debugging_opts.link_native_libraries {
- add_local_native_libraries(cmd, sess, codegen_results);
- }
- add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
- if sess.opts.debugging_opts.link_native_libraries {
- add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
- }
-}
-
/// Add sysroot and other globally set directories to the directory search list.
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
// The default library location, we need this to find the runtime.
) {
// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
- // addl_lib_search_paths
+ // add_lib_search_paths
if sess.opts.cg.rpath {
- let target_triple = sess.opts.target_triple.triple();
- let mut get_install_prefix_lib_path = || {
- let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
- let tlib = rustc_target::target_rustlib_path(&sess.sysroot, target_triple).join("lib");
- let mut path = PathBuf::from(install_prefix);
- path.push(&tlib);
-
- path
- };
let mut rpath_config = RPathConfig {
used_crates: &codegen_results.crate_info.used_crates_dynamic,
out_filename: out_filename.to_path_buf(),
has_rpath: sess.target.has_rpath,
is_like_osx: sess.target.is_like_osx,
linker_is_gnu: sess.target.linker_is_gnu,
- get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
};
cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
}
}
/// Produce the linker command line containing linker path and arguments.
-/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line
-/// by the user without creating a custom target specification.
-/// `OBJECT-FILES` specify whether the arguments can add object files.
-/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user
-/// or by the target spec can be inserted here.
-/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not.
+///
+/// When comments in the function say "order-(in)dependent" they mean order-dependence between
+/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies
+/// to specific libraries passed after it, and `-o` (output file, order-independent) applies
+/// to the linking process as a whole.
+/// Order-independent options may still override each other in order-dependent fashion,
+/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
path: &Path,
flavor: LinkerFlavor,
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor);
let link_output_kind = link_output_kind(sess, crate_type);
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
+ // ------------ Early order-dependent options ------------
+
+ // If we're building something like a dynamic library then some platforms
+ // need to make sure that all symbols are exported correctly from the
+ // dynamic library.
+ // Must be passed before any libraries to prevent the symbols to export from being thrown away,
+ // at least on some platforms (e.g. windows-gnu).
+ cmd.export_symbols(tmpdir, crate_type);
+
+ // Can be used for adding custom CRT objects or overriding order-dependent options above.
+ // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+ // introduce a target spec option for order-independent linker options and migrate built-in
+ // specs to it.
add_pre_link_args(cmd, sess, flavor);
- // NO-OPT-OUT, OBJECT-FILES-NO
+ // ------------ Object code and libraries, order-dependent ------------
+
+ // Pre-link CRT objects.
+ add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+ // Sanitizer libraries.
+ add_sanitizer_libraries(sess, crate_type, cmd);
+
+ // Object code from the current crate.
+ // Take careful note of the ordering of the arguments we pass to the linker
+ // here. Linkers will assume that things on the left depend on things to the
+ // right. Things on the right cannot depend on things on the left. This is
+ // all formally implemented in terms of resolving symbols (libs on the right
+ // resolve unknown symbols of libs on the left, but not vice versa).
+ //
+ // For this reason, we have organized the arguments we pass to the linker as
+ // such:
+ //
+ // 1. The local object that LLVM just generated
+ // 2. Local native libraries
+ // 3. Upstream rust libraries
+ // 4. Upstream native libraries
+ //
+ // The rationale behind this ordering is that those items lower down in the
+ // list can't depend on items higher up in the list. For example nothing can
+ // depend on what we just generated (e.g., that'd be a circular dependency).
+ // Upstream rust libraries are not supposed to depend on our local native
+ // libraries as that would violate the structure of the DAG, in that
+ // scenario they are required to link to them as well in a shared fashion.
+ // (The current implementation still doesn't prevent it though, see the FIXME below.)
+ //
+ // Note that upstream rust libraries may contain native dependencies as
+ // well, but they also can't depend on what we just started to add to the
+ // link line. And finally upstream native libraries can't depend on anything
+ // in this DAG so far because they can only depend on other native libraries
+ // and such dependencies are also required to be specified.
+ add_local_crate_regular_objects(cmd, codegen_results);
+ add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
+ add_local_crate_allocator_objects(cmd, codegen_results);
+
+ // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
+ // at the point at which they are specified on the command line.
+ // Must be passed before any (dynamic) libraries to have effect on them.
+ // On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections`
+ // so it will ignore unreferenced ELF sections from relocatable objects.
+ // For that reason, we put this flag after metadata objects as they would otherwise be removed.
+ // FIXME: Support more fine-grained dead code removal on Solaris/illumos
+ // and move this option back to the top.
+ cmd.add_as_needed();
+
+ // FIXME: Move this below to other native libraries
+ // (or alternatively link all native libraries after their respective crates).
+ // This change is somewhat breaking in practice due to local static libraries being linked
+ // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
+ if sess.opts.debugging_opts.link_native_libraries {
+ add_local_native_libraries(cmd, sess, codegen_results);
+ }
+
+ // Rust libraries.
+ add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
+
+ // Native libraries linked with `#[link]` attributes at and `-l` command line options.
+ // If -Zlink-native-libraries=false is set, then the assumption is that an
+ // external build system already has the native dependencies defined, and it
+ // will provide them to the linker itself.
+ if sess.opts.debugging_opts.link_native_libraries {
+ add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
+ }
+
+ // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
+ // command line shorter, reset it to default here before adding more libraries.
+ cmd.reset_per_library_state();
+
+ // FIXME: Built-in target specs occasionally use this for linking system libraries,
+ // eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)`
+ // and remove the option.
+ add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
+
+ // ------------ Arbitrary order-independent options ------------
+
+ // Add order-independent options determined by rustc from its compiler options,
+ // target properties and source code.
+ add_order_independent_options(
+ cmd,
+ sess,
+ link_output_kind,
+ crt_objects_fallback,
+ flavor,
+ crate_type,
+ codegen_results,
+ out_filename,
+ tmpdir,
+ );
+
+ // Can be used for arbitrary order-independent options.
+ // In practice may also be occasionally used for linking native libraries.
+ // Passed after compiler-generated options to support manual overriding when necessary.
+ add_user_defined_link_args(cmd, sess);
+
+ // ------------ Object code and libraries, order-dependent ------------
+
+ // Post-link CRT objects.
+ add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+ // ------------ Late order-dependent options ------------
+
+ // Doesn't really make sense.
+ // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+ // introduce a target spec option for order-independent linker options, migrate built-in specs
+ // to it and remove the option.
+ add_post_link_args(cmd, sess, flavor);
+
+ cmd.take_cmd()
+}
+
+fn add_order_independent_options(
+ cmd: &mut dyn Linker,
+ sess: &Session,
+ link_output_kind: LinkOutputKind,
+ crt_objects_fallback: bool,
+ flavor: LinkerFlavor,
+ crate_type: CrateType,
+ codegen_results: &CodegenResults,
+ out_filename: &Path,
+ tmpdir: &Path,
+) {
add_apple_sdk(cmd, sess, flavor);
- // NO-OPT-OUT
add_link_script(cmd, sess, tmpdir, crate_type);
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.eh_frame_header {
cmd.add_eh_frame_header();
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
// Make the binary compatible with data execution prevention schemes.
cmd.add_no_exec();
- // NO-OPT-OUT, OBJECT-FILES-NO
- // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
- // at the point at which they are specified on the command line.
- // Must be passed before any dynamic libraries.
- cmd.add_as_needed();
-
- // NO-OPT-OUT, OBJECT-FILES-NO
if crt_objects_fallback {
cmd.no_crt_objects();
}
- // NO-OPT-OUT, OBJECT-FILES-YES
- add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
if sess.target.is_like_emscripten {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
});
}
- // OBJECT-FILES-YES, AUDIT-ORDER
- link_sanitizers(sess, crate_type, cmd);
+ if flavor == LinkerFlavor::PtxLinker {
+ // Provide the linker with fallback to internal `target-cpu`.
+ cmd.arg("--fallback-arch");
+ cmd.arg(&codegen_results.linker_info.target_cpu);
+ } else if flavor == LinkerFlavor::BpfLinker {
+ cmd.arg("--cpu");
+ cmd.arg(&codegen_results.linker_info.target_cpu);
+ cmd.arg("--cpu-features");
+ cmd.arg(match &sess.opts.cg.target_feature {
+ feat if !feat.is_empty() => feat,
+ _ => &sess.target.options.features,
+ });
+ }
- // OBJECT-FILES-NO, AUDIT-ORDER
- // Linker plugins should be specified early in the list of arguments
- // FIXME: How "early" exactly?
cmd.linker_plugin_lto();
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- // FIXME: Order-dependent, at least relatively to other args adding searh directories.
add_library_search_dirs(cmd, sess, crt_objects_fallback);
- // OBJECT-FILES-YES
- add_local_crate_regular_objects(cmd, codegen_results);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
cmd.output_filename(out_filename);
- // OBJECT-FILES-NO, AUDIT-ORDER
if crate_type == CrateType::Executable && sess.target.is_like_windows {
- if let Some(ref s) = codegen_results.windows_subsystem {
+ if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
cmd.subsystem(s);
}
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- // If we're building something like a dynamic library then some platforms
- // need to make sure that all symbols are exported correctly from the
- // dynamic library.
- cmd.export_symbols(tmpdir, crate_type);
-
- // OBJECT-FILES-YES
- add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
-
- // OBJECT-FILES-YES
- add_local_crate_allocator_objects(cmd, codegen_results);
-
- // OBJECT-FILES-NO, AUDIT-ORDER
- // FIXME: Order dependent, applies to the following objects. Where should it be placed?
// Try to strip as much out of the generated object by removing unused
// sections if possible. See more comments in linker.rs
if !sess.link_dead_code() {
cmd.gc_sections(keep_metadata);
}
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
cmd.set_output_kind(link_output_kind, out_filename);
- // OBJECT-FILES-NO, AUDIT-ORDER
add_relro_args(cmd, sess);
- // OBJECT-FILES-NO, AUDIT-ORDER
// Pass optimization flags down to the linker.
cmd.optimize();
- // OBJECT-FILES-NO, AUDIT-ORDER
// Pass debuginfo and strip flags down to the linker.
cmd.debuginfo(sess.opts.debugging_opts.strip);
- // OBJECT-FILES-NO, AUDIT-ORDER
// We want to prevent the compiler from accidentally leaking in any system libraries,
// so by default we tell linkers not to link to any default libraries.
if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
cmd.no_default_libraries();
}
- // OBJECT-FILES-YES
- link_local_crate_native_libs_and_dependent_crate_libs::<B>(
- cmd,
- sess,
- crate_type,
- codegen_results,
- tmpdir,
- );
-
- // OBJECT-FILES-NO, AUDIT-ORDER
if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() {
cmd.pgo_gen();
}
- // OBJECT-FILES-NO, AUDIT-ORDER
if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
cmd.control_flow_guard();
}
- // OBJECT-FILES-NO, AUDIT-ORDER
add_rpath_args(cmd, sess, codegen_results, out_filename);
-
- // OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_user_defined_link_args(cmd, sess);
-
- // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- cmd.finalize();
-
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
-
- // NO-OPT-OUT, OBJECT-FILES-YES
- add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
- // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
- add_post_link_args(cmd, sess, flavor);
-
- cmd.take_cmd()
}
/// # Native library linking
}
// Adds the static "rlib" versions of all crates to the command line.
- // There's a bit of magic which happens here specifically related to LTO and
- // dynamic libraries. Specifically:
- //
- // * For LTO, we remove upstream object files.
- // * For dylibs we remove metadata and bytecode from upstream rlibs
+ // There's a bit of magic which happens here specifically related to LTO,
+ // namely that we remove upstream object files.
//
// When performing LTO, almost(*) all of the bytecode from the upstream
// libraries has already been included in our object file output. As a
// their bytecode wasn't included. The object files in those libraries must
// still be passed to the linker.
//
- // When making a dynamic library, linkers by default don't include any
- // object files in an archive if they're not necessary to resolve the link.
- // We basically want to convert the archive (rlib) to a dylib, though, so we
- // *do* want everything included in the output, regardless of whether the
- // linker thinks it's needed or not. As a result we must use the
- // --whole-archive option (or the platform equivalent). When using this
- // option the linker will fail if there are non-objects in the archive (such
- // as our own metadata and/or bytecode). All in all, for rlibs to be
- // entirely included in dylibs, we need to remove all non-object files.
- //
- // Note, however, that if we're not doing LTO or we're not producing a dylib
- // (aka we're making an executable), we can just pass the rlib blindly to
- // the linker (fast) because it's fine if it's not actually included as
- // we're at the end of the dependency chain.
+ // Note, however, that if we're not doing LTO we can just pass the rlib
+ // blindly to the linker (fast) because it's fine if it's not actually
+ // included as we're at the end of the dependency chain.
fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
cmd: &mut dyn Linker,
sess: &'a Session,
let src = &codegen_results.crate_info.used_crate_source[&cnum];
let cratepath = &src.rlib.as_ref().unwrap().0;
+ let mut link_upstream = |path: &Path| {
+ // If we're creating a dylib, then we need to include the
+ // whole of each object in our archive into that artifact. This is
+ // because a `dylib` can be reused as an intermediate artifact.
+ //
+ // Note, though, that we don't want to include the whole of a
+ // compiler-builtins crate (e.g., compiler-rt) because it'll get
+ // repeatedly linked anyway.
+ let path = fix_windows_verbatim_for_gcc(path);
+ if crate_type == CrateType::Dylib
+ && codegen_results.crate_info.compiler_builtins != Some(cnum)
+ {
+ cmd.link_whole_rlib(&path);
+ } else {
+ cmd.link_rlib(&path);
+ }
+ };
+
// See the comment above in `link_staticlib` and `link_rlib` for why if
// there's a static library that's not relevant we skip all object
// files.
if (!are_upstream_rust_objects_already_included(sess)
|| ignored_for_lto(sess, &codegen_results.crate_info, cnum))
- && crate_type != CrateType::Dylib
&& !skip_native
{
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
+ link_upstream(cratepath);
return;
}
return;
}
archive.build();
-
- // If we're creating a dylib, then we need to include the
- // whole of each object in our archive into that artifact. This is
- // because a `dylib` can be reused as an intermediate artifact.
- //
- // Note, though, that we don't want to include the whole of a
- // compiler-builtins crate (e.g., compiler-rt) because it'll get
- // repeatedly linked anyway.
- if crate_type == CrateType::Dylib
- && codegen_results.crate_info.compiler_builtins != Some(cnum)
- {
- cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
- } else {
- cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
- }
+ link_upstream(&dst);
});
}
// already included them when we included the rust library
// previously
NativeLibKind::Static { bundle: None | Some(true), .. } => {}
- NativeLibKind::RawDylib => {
- // FIXME(#58713): Proper handling for raw dylibs.
- bug!("raw_dylib feature not yet implemented");
- }
+ NativeLibKind::RawDylib => {}
}
}
}
/// need out of the shared crate context before we get rid of it.
#[derive(Encodable, Decodable)]
pub struct LinkerInfo {
- target_cpu: String,
+ pub(super) target_cpu: String,
exports: FxHashMap<CrateType, Vec<String>>,
}
Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
}
- LinkerFlavor::PtxLinker => {
- Box::new(PtxLinker { cmd, sess, info: self }) as Box<dyn Linker>
+ LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
+
+ LinkerFlavor::BpfLinker => {
+ Box::new(BpfLinker { cmd, sess, info: self }) as Box<dyn Linker>
}
}
}
fn add_eh_frame_header(&mut self) {}
fn add_no_exec(&mut self) {}
fn add_as_needed(&mut self) {}
- fn finalize(&mut self);
+ fn reset_per_library_state(&mut self) {}
}
impl dyn Linker + '_ {
// eliminate the metadata. If we're building an executable, however,
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
// reduction.
- } else if self.sess.target.linker_is_gnu && !keep_metadata {
+ } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
+ && !keep_metadata
+ {
self.linker_arg("--gc-sections");
}
}
fn no_gc_sections(&mut self) {
if self.sess.target.is_like_osx {
self.linker_arg("-no_dead_strip");
- } else if self.sess.target.linker_is_gnu {
+ } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
self.linker_arg("--no-gc-sections");
}
}
fn optimize(&mut self) {
- if !self.sess.target.linker_is_gnu {
+ if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
return;
}
self.linker_arg(&subsystem);
}
- fn finalize(&mut self) {
+ fn reset_per_library_state(&mut self) {
self.hint_dynamic(); // Reset to default before returning the composed command line.
}
}
}
- fn finalize(&mut self) {}
-
// MSVC doesn't need group indicators
fn group_start(&mut self) {}
fn group_end(&mut self) {}
// noop
}
- fn finalize(&mut self) {}
-
// Appears not necessary on Emscripten
fn group_start(&mut self) {}
fn group_end(&mut self) {}
fn subsystem(&mut self, _subsystem: &str) {}
- fn finalize(&mut self) {}
-
// Not needed for now with LLD
fn group_start(&mut self) {}
fn group_end(&mut self) {}
pub struct PtxLinker<'a> {
cmd: Command,
sess: &'a Session,
- info: &'a LinkerInfo,
}
impl<'a> Linker for PtxLinker<'a> {
self.cmd.arg("-o").arg(path);
}
- fn finalize(&mut self) {
- // Provide the linker with fallback to internal `target-cpu`.
- self.cmd.arg("--fallback-arch").arg(&self.info.target_cpu);
+ fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+ panic!("external dylibs not supported")
+ }
+
+ fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
+ panic!("external dylibs not supported")
+ }
+
+ fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
+ panic!("staticlibs not supported")
+ }
+
+ fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+ panic!("staticlibs not supported")
+ }
+
+ fn framework_path(&mut self, _path: &Path) {
+ panic!("frameworks not supported")
+ }
+
+ fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+ panic!("frameworks not supported")
+ }
+
+ fn full_relro(&mut self) {}
+
+ fn partial_relro(&mut self) {}
+
+ fn no_relro(&mut self) {}
+
+ fn gc_sections(&mut self, _keep_metadata: bool) {}
+
+ fn no_gc_sections(&mut self) {}
+
+ fn pgo_gen(&mut self) {}
+
+ fn no_crt_objects(&mut self) {}
+
+ fn no_default_libraries(&mut self) {}
+
+ fn control_flow_guard(&mut self) {}
+
+ fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+
+ fn subsystem(&mut self, _subsystem: &str) {}
+
+ fn group_start(&mut self) {}
+
+ fn group_end(&mut self) {}
+
+ fn linker_plugin_lto(&mut self) {}
+}
+
+pub struct BpfLinker<'a> {
+ cmd: Command,
+ sess: &'a Session,
+ info: &'a LinkerInfo,
+}
+
+impl<'a> Linker for BpfLinker<'a> {
+ fn cmd(&mut self) -> &mut Command {
+ &mut self.cmd
+ }
+
+ fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+ fn link_rlib(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn link_whole_rlib(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn include_path(&mut self, path: &Path) {
+ self.cmd.arg("-L").arg(path);
+ }
+
+ fn debuginfo(&mut self, _strip: Strip) {
+ self.cmd.arg("--debug");
+ }
+
+ fn add_object(&mut self, path: &Path) {
+ self.cmd.arg(path);
+ }
+
+ fn optimize(&mut self) {
+ self.cmd.arg(match self.sess.opts.optimize {
+ OptLevel::No => "-O0",
+ OptLevel::Less => "-O1",
+ OptLevel::Default => "-O2",
+ OptLevel::Aggressive => "-O3",
+ OptLevel::Size => "-Os",
+ OptLevel::SizeMin => "-Oz",
+ });
+ }
+
+ fn output_filename(&mut self, path: &Path) {
+ self.cmd.arg("-o").arg(path);
}
fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
fn control_flow_guard(&mut self) {}
- fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
+ let path = tmpdir.join("symbols");
+ let res: io::Result<()> = try {
+ let mut f = BufWriter::new(File::create(&path)?);
+ for sym in self.info.exports[&crate_type].iter() {
+ writeln!(f, "{}", sym)?;
+ }
+ };
+ if let Err(e) = res {
+ self.sess.fatal(&format!("failed to write symbols file: {}", e));
+ } else {
+ self.cmd.arg("--export-symbols").arg(&path);
+ }
+ }
fn subsystem(&mut self, _subsystem: &str) {}
use std::fs::File;
use std::path::Path;
+use object::{Object, ObjectSection};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_data_structures::rustc_erase_owner;
let entry = entry_result
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
if entry.name() == METADATA_FILENAME.as_bytes() {
- return Ok(entry.data());
+ let data = entry
+ .data(data)
+ .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
+ return search_for_metadata(path, data, ".rmeta");
}
}
}
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
- use object::{Object, ObjectSection};
-
- load_metadata_with(path, |data| {
- let file = object::File::parse(&data)
- .map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?;
- file.section_by_name(".rustc")
- .ok_or_else(|| format!("no .rustc section in '{}'", path.display()))?
- .data()
- .map_err(|e| {
- format!("failed to read .rustc section in '{}': {}", path.display(), e)
- })
- })
+ load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc"))
}
}
+
+fn search_for_metadata<'a>(
+ path: &Path,
+ bytes: &'a [u8],
+ section: &str,
+) -> Result<&'a [u8], String> {
+ let file = match object::File::parse(bytes) {
+ Ok(f) => f,
+ // The parse above could fail for odd reasons like corruption, but for
+ // now we just interpret it as this target doesn't support metadata
+ // emission in object files so the entire byte slice itself is probably
+ // a metadata file. Ideally though if necessary we could at least check
+ // the prefix of bytes to see if it's an actual metadata object and if
+ // not forward the error along here.
+ Err(_) => return Ok(bytes),
+ };
+ file.section_by_name(section)
+ .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
+ .data()
+ .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
+}
pub is_like_osx: bool,
pub has_rpath: bool,
pub linker_is_gnu: bool,
- pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
}
pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
// Use relative paths to the libraries. Binaries can be moved
// as long as they maintain the relative relationship to the
// crates they depend on.
- let rel_rpaths = get_rpaths_relative_to_output(config, libs);
+ let rpaths = get_rpaths_relative_to_output(config, libs);
- // And a final backup rpath to the global library location.
- let fallback_rpaths = vec![get_install_prefix_rpath(config)];
-
- fn log_rpaths(desc: &str, rpaths: &[String]) {
- debug!("{} rpaths:", desc);
- for rpath in rpaths {
- debug!(" {}", *rpath);
- }
+ debug!("rpaths:");
+ for rpath in &rpaths {
+ debug!(" {}", rpath);
}
- log_rpaths("relative", &rel_rpaths);
- log_rpaths("fallback", &fallback_rpaths);
-
- let mut rpaths = rel_rpaths;
- rpaths.extend_from_slice(&fallback_rpaths);
-
// Remove duplicates
minimize_rpaths(&rpaths)
}
diff_paths(path, base)
}
-fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
- let path = (config.get_install_prefix_lib_path)();
- let path = env::current_dir().unwrap().join(&path);
- // FIXME (#9639): This needs to handle non-utf8 paths
- path.to_str().expect("non-utf8 component in rpath").to_owned()
-}
-
fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
let mut set = FxHashSet::default();
let mut minimized = Vec::new();
is_like_osx: true,
linker_is_gnu: false,
out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
};
let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
assert_eq!(res, "@loader_path/../lib");
let config = &mut RPathConfig {
used_crates: &[],
out_filename: PathBuf::from("bin/rustc"),
- get_install_prefix_lib_path: &mut || panic!(),
has_rpath: true,
is_like_osx: false,
linker_is_gnu: true,
pub fn provide_extern(providers: &mut Providers) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
- providers.wasm_import_module_map = wasm_import_module_map;
}
fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
use rustc_session::config::{Passes, SwitchWithOptPath};
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
let (coordinator_send, coordinator_receive) = channel();
let sess = tcx.sess;
- let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
- let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
- let windows_subsystem = subsystem.map(|subsystem| {
- if subsystem != sym::windows && subsystem != sym::console {
- tcx.sess.fatal(&format!(
- "invalid windows subsystem `{}`, only \
- `windows` and `console` are allowed",
- subsystem
- ));
- }
- subsystem.to_string()
- });
let linker_info = LinkerInfo::new(tcx, target_cpu);
let crate_info = CrateInfo::new(tcx);
OngoingCodegen {
backend,
- crate_name,
metadata,
- windows_subsystem,
linker_info,
crate_info,
pub struct OngoingCodegen<B: ExtraBackendMethods> {
pub backend: B,
- pub crate_name: Symbol,
pub metadata: EncodedMetadata,
- pub windows_subsystem: Option<String>,
pub linker_info: LinkerInfo,
pub crate_info: CrateInfo,
pub coordinator_send: Sender<Box<dyn Any + Send>>,
(
CodegenResults {
- crate_name: self.crate_name,
metadata: self.metadata,
- windows_subsystem: self.windows_subsystem,
linker_info: self.linker_info,
crate_info: self.crate_info,
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, EntryFnType};
use rustc_session::Session;
+use rustc_span::symbol::sym;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
use std::ops::{Deref, DerefMut};
impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
+ let local_crate_name = tcx.crate_name(LOCAL_CRATE);
+ let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+ let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
+ let windows_subsystem = subsystem.map(|subsystem| {
+ if subsystem != sym::windows && subsystem != sym::console {
+ tcx.sess.fatal(&format!(
+ "invalid windows subsystem `{}`, only \
+ `windows` and `console` are allowed",
+ subsystem
+ ));
+ }
+ subsystem.to_string()
+ });
+
let mut info = CrateInfo {
+ local_crate_name,
panic_runtime: None,
compiler_builtins: None,
profiler_runtime: None,
lang_item_to_crate: Default::default(),
missing_lang_items: Default::default(),
dependency_formats: tcx.dependency_formats(()),
+ windows_subsystem,
};
let lang_items = tcx.lang_items();
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
/// for a gap area is only used as the line execution count if there are no other regions on a
/// line."
+#[derive(Debug)]
pub struct FunctionCoverage<'tcx> {
instance: Instance<'tcx>,
source_hash: u64,
expression_id, lhs, op, rhs, region
);
let expression_index = self.expression_index(u32::from(expression_id));
+ debug_assert!(
+ expression_index.as_usize() < self.expressions.len(),
+ "expression_index {} is out of range for expressions.len() = {}
+ for {:?}",
+ expression_index.as_usize(),
+ self.expressions.len(),
+ self,
+ );
if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
lhs,
op,
pub name: Option<Symbol>,
pub cfg: Option<ast::MetaItem>,
pub verbatim: Option<bool>,
+ pub dll_imports: Vec<cstore::DllImport>,
}
impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
- NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
+ NativeLib {
+ kind: lib.kind,
+ name: lib.name,
+ cfg: lib.cfg.clone(),
+ verbatim: lib.verbatim,
+ dll_imports: lib.dll_imports.clone(),
+ }
}
}
/// and the corresponding properties without referencing information outside of a `CrateInfo`.
#[derive(Debug, Encodable, Decodable)]
pub struct CrateInfo {
+ pub local_crate_name: Symbol,
pub panic_runtime: Option<CrateNum>,
pub compiler_builtins: Option<CrateNum>,
pub profiler_runtime: Option<CrateNum>,
pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
pub dependency_formats: Lrc<Dependencies>,
+ pub windows_subsystem: Option<String>,
}
#[derive(Encodable, Decodable)]
pub struct CodegenResults {
- pub crate_name: Symbol,
pub modules: Vec<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
pub metadata_module: Option<CompiledModule>,
pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
- pub windows_subsystem: Option<String>,
pub linker_info: back::linker::LinkerInfo,
pub crate_info: CrateInfo,
}
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::traversal;
-use rustc_middle::mir::visit::{
- MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
-};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Location, TerminatorKind};
-use rustc_middle::ty;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::LayoutOf;
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
- analyzer.visit_body(&mir);
+ for (bb, data) in mir.basic_blocks().iter_enumerated() {
+ analyzer.visit_basic_block_data(bb, data);
+ }
for (local, decl) in mir.local_decls.iter_enumerated() {
let ty = fx.monomorphize(decl.ty);
if let mir::ProjectionElem::Deref = elem {
// Deref projections typically only read the pointer.
- // (the exception being `VarDebugInfo` contexts, handled below)
base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
-
- // Indirect debuginfo requires going through memory, that only
- // the debugger accesses, following our emitted DWARF pointer ops.
- //
- // FIXME(eddyb) Investigate the possibility of relaxing this, but
- // note that `llvm.dbg.declare` *must* be used for indirect places,
- // even if we start using `llvm.dbg.value` for all other cases,
- // as we don't necessarily know when the value changes, but only
- // where it lives in memory.
- //
- // It's possible `llvm.dbg.declare` could support starting from
- // a pointer that doesn't point to an `alloca`, but this would
- // only be useful if we know the pointer being `Deref`'d comes
- // from an immutable place, and if `llvm.dbg.declare` calls
- // must be at the very start of the function, then only function
- // arguments could contain such pointers.
- if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
- // We use `NonUseContext::VarDebugInfo` for the base,
- // which might not force the base local to memory,
- // so we have to do it manually.
- self.visit_local(&place_ref.local, context, location);
- }
- }
-
- // `NonUseContext::VarDebugInfo` needs to flow all the
- // way down to the base local (see `visit_local`).
- if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
- base_context = context;
}
self.process_place(&place_base, base_context, location);
);
}
} else {
- // FIXME this is super_place code, is repeated here to avoid cloning place or changing
- // visit_place API
- let mut context = context;
-
- if !place_ref.projection.is_empty() {
- context = if context.is_mutating_use() {
- PlaceContext::MutatingUse(MutatingUseContext::Projection)
- } else {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
- };
- }
-
self.visit_local(&place_ref.local, context, location);
- self.visit_projection(*place_ref, context, location);
}
}
}
self.visit_rvalue(rvalue, location);
}
- fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
- let check = match terminator.kind {
- mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
- match *c.ty().kind() {
- ty::FnDef(did, _) => Some((did, args)),
- _ => None,
- }
- }
- _ => None,
- };
- if let Some((def_id, args)) = check {
- if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
- // box_free(x) shares with `drop x` the property that it
- // is not guaranteed to be statically dominated by the
- // definition of x, so x must always be in an alloca.
- if let mir::Operand::Move(ref place) = args[0] {
- self.visit_place(
- place,
- PlaceContext::MutatingUse(MutatingUseContext::Drop),
- location,
- );
- }
- }
- }
-
- self.super_terminator(terminator, location);
- }
-
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
debug!("visit_place(place={:?}, context={:?})", place, context);
self.process_place(&place.as_ref(), context, location);
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];
+const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
+
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
.chain(MIPS_ALLOWED_FEATURES.iter())
.chain(RISCV_ALLOWED_FEATURES.iter())
.chain(WASM_ALLOWED_FEATURES.iter())
+ .chain(BPF_ALLOWED_FEATURES.iter())
.cloned()
}
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
"wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
+ "bpf" => BPF_ALLOWED_FEATURES,
_ => &[],
}
}
None
}
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
- fn provide(&self, _providers: &mut Providers);
- fn provide_extern(&self, _providers: &mut Providers);
+ /// The metadata loader used to load rlib and dylib metadata.
+ ///
+ /// Alternative codegen backends may want to use different rlib or dylib formats than the
+ /// default native static archives and dynamic libraries.
+ fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
+ Box::new(crate::back::metadata::DefaultMetadataLoader)
+ }
+
+ fn provide(&self, _providers: &mut Providers) {}
+ fn provide_extern(&self, _providers: &mut Providers) {}
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
return Ok(());
}
- match self.active_cache.entry(cache_key.clone()) {
+ match self.active_cache.entry(cache_key) {
Entry::Occupied(o) => {
let node = &mut self.nodes[*o.get()];
if let Some(parent_index) = parent {
&& self
.error_cache
.get(&obligation_tree_id)
- .map(|errors| errors.contains(&cache_key))
- .unwrap_or(false);
+ .map_or(false, |errors| errors.contains(v.key()));
if already_failed {
Err(())
use std::ops::Add;
use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
- /// This is a single threaded variant of AtomicCell provided by crossbeam.
- /// Unlike `Atomic` this is intended for all `Copy` types,
- /// but it lacks the explicit ordering arguments.
- #[derive(Debug)]
- pub struct AtomicCell<T: Copy>(Cell<T>);
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn new(v: T) -> Self {
- AtomicCell(Cell::new(v))
- }
-
- #[inline]
- pub fn get_mut(&mut self) -> &mut T {
- self.0.get_mut()
- }
- }
-
- impl<T: Copy> AtomicCell<T> {
- #[inline]
- pub fn into_inner(self) -> T {
- self.0.into_inner()
- }
-
- #[inline]
- pub fn load(&self) -> T {
- self.0.get()
- }
-
- #[inline]
- pub fn store(&self, val: T) {
- self.0.set(val)
- }
-
- #[inline]
- pub fn swap(&self, val: T) -> T {
- self.0.replace(val)
- }
- }
-
/// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
- /// It differs from `AtomicCell` in that it has explicit ordering arguments
- /// and is only intended for use with the native atomic types.
+ /// It has explicit ordering arguments and is only intended for use with
+ /// the native atomic types.
/// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
/// as it's not intended to be used separately.
#[derive(Debug)]
(oper_a(), oper_b())
}
- pub struct SerialScope;
-
- impl SerialScope {
- pub fn spawn<F>(&self, f: F)
- where F: FnOnce(&SerialScope)
- {
- f(self)
- }
- }
-
- pub fn scope<F, R>(f: F) -> R
- where F: FnOnce(&SerialScope) -> R
- {
- f(&SerialScope)
- }
-
#[macro_export]
macro_rules! parallel {
($($blocks:tt),*) => {
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
- pub use crossbeam_utils::atomic::AtomicCell;
-
pub use std::sync::Arc as Lrc;
pub use std::sync::Weak as Weak;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
use rustc_feature::find_gated_cfg;
-use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
+use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
use rustc_metadata::locator;
}
}
-// Whether to stop or continue compilation.
+/// Whether to stop or continue compilation.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Compilation {
Stop,
println!("commit-date: {}", unw(util::commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(util::release_str()));
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_version();
- }
+
+ let debug_flags = matches.opt_strs("Z");
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_version();
}
}
}
// Don't handle -W help here, because we might first load plugins.
- let r = matches.opt_strs("Z");
- if r.iter().any(|x| *x == "help") {
+ let debug_flags = matches.opt_strs("Z");
+ if debug_flags.iter().any(|x| *x == "help") {
describe_debug_flags();
return None;
}
}
if cg_flags.iter().any(|x| *x == "passes=list") {
- if cfg!(feature = "llvm") {
- get_builtin_codegen_backend(&None, "llvm")().print_passes();
- }
+ let backend_name = debug_flags.iter().find_map(|x| {
+ if x.starts_with("codegen-backend=") {
+ Some(&x["codegen-backends=".len()..])
+ } else {
+ None
+ }
+ });
+ get_codegen_backend(&None, backend_name).print_passes();
return None;
}
Add `'static` requirement to fix them:
-```compile_fail,E0759
+```
# use std::fmt::Debug;
-fn foo(x: &i32) -> impl Debug + 'static { // ok!
+fn foo(x: &'static i32) -> impl Debug + 'static { // ok!
x
}
-fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok!
+fn bar(x: &'static i32) -> Box<dyn Debug + 'static> { // ok!
Box::new(x)
}
```
$(
$enc.emit_struct_field(
stringify!($name),
- idx,
+ idx == 0,
|enc| $name.encode(enc),
)?;
idx += 1;
// Special-case encoder to skip tool_metadata if not set
impl<E: Encoder> Encodable<E> for Diagnostic {
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct("diagnostic", 7, |s| {
+ s.emit_struct(false, |s| {
let mut idx = 0;
idx = encode_fields!(
self.resolver.check_unused_macros();
}
- /// Resolves a path mentioned inside Rust code.
+ /// Resolves a `path` mentioned inside Rust code, returning an absolute path.
///
- /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+ /// This unifies the logic used for resolving `include_X!`.
///
- /// Returns an absolute path to the file that `path` refers to.
+ /// FIXME: move this to `rustc_builtin_macros` and make it private.
pub fn resolve_path(
&self,
path: impl Into<PathBuf>,
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, is_builtin_attr};
+use rustc_attr::is_builtin_attr;
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::sync::Lrc;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
-use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{ExpnId, FileName, Span};
use smallvec::{smallvec, SmallVec};
-use std::io::ErrorKind;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::rc::Rc;
-use std::{iter, mem, slice};
+use std::{iter, mem};
macro_rules! ast_fragments {
(
noop_flat_map_generic_param(param, self)
}
- fn visit_attribute(&mut self, at: &mut ast::Attribute) {
- // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
- // contents="file contents")]` attributes
- if !self.cx.sess.check_name(at, sym::doc) {
- return noop_visit_attribute(at, self);
- }
-
- if let Some(list) = at.meta_item_list() {
- if !list.iter().any(|it| it.has_name(sym::include)) {
- return noop_visit_attribute(at, self);
- }
-
- let mut items = vec![];
-
- for mut it in list {
- if !it.has_name(sym::include) {
- items.push({
- noop_visit_meta_list_item(&mut it, self);
- it
- });
- continue;
- }
-
- if let Some(file) = it.value_str() {
- let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
- self.check_attributes(slice::from_ref(at));
- if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
- // avoid loading the file if they haven't enabled the feature
- return noop_visit_attribute(at, self);
- }
-
- let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
- Ok(filename) => filename,
- Err(mut err) => {
- err.emit();
- continue;
- }
- };
-
- match self.cx.source_map().load_file(&filename) {
- Ok(source_file) => {
- let src = source_file
- .src
- .as_ref()
- .expect("freshly loaded file should have a source");
- let src_interned = Symbol::intern(src.as_str());
-
- let include_info = vec![
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::file),
- file,
- DUMMY_SP,
- )),
- ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
- Ident::with_dummy_span(sym::contents),
- src_interned,
- DUMMY_SP,
- )),
- ];
-
- let include_ident = Ident::with_dummy_span(sym::include);
- let item = attr::mk_list_item(include_ident, include_info);
- items.push(ast::NestedMetaItem::MetaItem(item));
- }
- Err(e) => {
- let lit_span = it.name_value_literal_span().unwrap();
-
- if e.kind() == ErrorKind::InvalidData {
- self.cx
- .struct_span_err(
- lit_span,
- &format!("{} wasn't a utf-8 file", filename.display()),
- )
- .span_label(lit_span, "contains invalid utf-8")
- .emit();
- } else {
- let mut err = self.cx.struct_span_err(
- lit_span,
- &format!("couldn't read {}: {}", filename.display(), e),
- );
- err.span_label(lit_span, "couldn't read file");
-
- err.emit();
- }
- }
- }
- } else {
- let mut err = self
- .cx
- .struct_span_err(it.span(), "expected path to external documentation");
-
- // Check if the user erroneously used `doc(include(...))` syntax.
- let literal = it.meta_item_list().and_then(|list| {
- if list.len() == 1 {
- list[0].literal().map(|literal| &literal.kind)
- } else {
- None
- }
- });
-
- let (path, applicability) = match &literal {
- Some(LitKind::Str(path, ..)) => {
- (path.to_string(), Applicability::MachineApplicable)
- }
- _ => (String::from("<path>"), Applicability::HasPlaceholders),
- };
-
- err.span_suggestion(
- it.span(),
- "provide a file path with `=`",
- format!("include = \"{}\"", path),
- applicability,
- );
-
- err.emit();
- }
- }
-
- let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
- *at = ast::Attribute {
- kind: ast::AttrKind::Normal(
- AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None },
- None,
- ),
- span: at.span,
- id: at.id,
- style: at.style,
- };
- } else {
- noop_visit_attribute(at, self)
- }
- }
-
fn visit_id(&mut self, id: &mut ast::NodeId) {
if self.monotonic {
debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
(active, f16c_target_feature, "1.36.0", Some(44839), None),
(active, riscv_target_feature, "1.45.0", Some(44839), None),
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
+ (active, bpf_target_feature, "1.54.0", Some(44839), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates (target features)
/// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None),
- /// Allows `#[doc(include = "some-file")]`.
- (active, external_doc, "1.22.0", Some(44732), None),
-
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
(active, crate_visibility_modifier, "1.23.0", Some(53120), None),
(removed, const_fn, "1.54.0", Some(57563), None,
Some("split into finer-grained feature gates")),
+ /// Allows `#[doc(include = "some-file")]`.
+ (removed, external_doc, "1.54.0", Some(44732), None,
+ Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::unhash::UnhashMap;
use rustc_index::vec::IndexVec;
+use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{kw, sym, Symbol};
}
/// Adds a root definition (no parent) and a few other reserved definitions.
- pub fn new(stable_crate_id: StableCrateId) -> Definitions {
+ pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
let key = DefKey {
parent: None,
disambiguated_data: DisambiguatedDefPathData {
},
};
+ let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
let parent_hash = DefPathHash::new(stable_crate_id, 0);
let def_path_hash = key.compute_stable_hash(parent_hash);
use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::def_id::{DefPathHash, StableCrateId};
#[test]
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).
- let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]);
- let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]);
+ let d0 = CrateDisambiguator::from(Fingerprint::new(12, 34));
+ let d1 = CrateDisambiguator::from(Fingerprint::new(56, 78));
- let h0 = mk_test_hash(id0);
- let h1 = mk_test_hash(id1);
+ let h0 = mk_test_hash("foo", d0);
+ let h1 = mk_test_hash("foo", d1);
assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
assert_ne!(h0.local_hash(), h1.local_hash());
- fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
+ fn mk_test_hash(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> DefPathHash {
+ let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
let parent_hash = DefPathHash::new(stable_crate_id, 0);
let key = DefKey {
use rustc_data_structures::{base_n, flock};
use rustc_errors::ErrorReported;
use rustc_fs_util::{link_or_copy, LinkOrCopy};
-use rustc_session::{Session, StableCrateId};
+use rustc_session::{CrateDisambiguator, Session};
use std::fs as std_fs;
use std::io;
pub fn prepare_session_directory(
sess: &Session,
crate_name: &str,
- stable_crate_id: StableCrateId,
+ crate_disambiguator: CrateDisambiguator,
) -> Result<(), ErrorReported> {
if sess.opts.incremental.is_none() {
return Ok(());
debug!("prepare_session_directory");
// {incr-comp-dir}/{crate-name-and-disambiguator}
- let crate_dir = crate_path(sess, crate_name, stable_crate_id);
+ let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
debug!("crate-dir: {}", crate_dir.display());
create_dir(sess, &crate_dir, "crate")?;
Ok(UNIX_EPOCH + duration)
}
-fn crate_path(sess: &Session, crate_name: &str, stable_crate_id: StableCrateId) -> PathBuf {
+fn crate_path(
+ sess: &Session,
+ crate_name: &str,
+ crate_disambiguator: CrateDisambiguator,
+) -> PathBuf {
let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
- let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE);
+ // The full crate disambiguator is really long. 64 bits of it should be
+ // sufficient.
+ let crate_disambiguator = crate_disambiguator.to_fingerprint().to_smaller_hash();
+ let crate_disambiguator = base_n::encode(crate_disambiguator as u128, INT_ENCODE_BASE);
- let crate_name = format!("{}-{}", crate_name, stable_crate_id);
+ let crate_name = format!("{}-{}", crate_name, crate_disambiguator);
incr_dir.join(crate_name)
}
)
}
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ _info: ty::VarianceDiagInfo<'tcx>,
+ ) {
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
match dir {
EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
- SupertypeOf => {
- self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
- }
+ SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_ty,
+ b_ty,
+ ),
}?;
Ok(())
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
if self.tcx().lazy_normalization() =>
{
assert_eq!(promoted, None);
- let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+ let substs = self.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ substs,
+ substs,
+ )?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
if self.tcx().lazy_normalization() =>
{
assert_eq!(promoted, None);
- let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+ let substs = self.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ substs,
+ substs,
+ )?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
- self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+ self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
Ok(a)
}
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
// When higher-ranked types are involved, computing the LUB is
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
- self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+ self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
Ok(a)
}
}
/// - Bivariant means that it doesn't matter.
ambient_variance: ty::Variance,
+ ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
+
/// When we pass through a set of binders (e.g., when looking into
/// a `fn` type), we push a new bound region scope onto here. This
/// will contain the instantiated region for each region in those
/// satisfied for the two types to be related. `sub` and `sup` may
/// be regions from the type or new variables created through the
/// delegate.
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ );
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
delegate: D,
ambient_variance: ty::Variance,
) -> Self {
- Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] }
+ Self {
+ infcx,
+ delegate,
+ ambient_variance,
+ ambient_variance_info: ty::VarianceDiagInfo::default(),
+ a_scopes: vec![],
+ b_scopes: vec![],
+ }
}
fn ambient_covariance(&self) -> bool {
/// Push a new outlives requirement into our output set of
/// constraints.
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ ) {
debug!("push_outlives({:?}: {:?})", sup, sub);
- self.delegate.push_outlives(sup, sub);
+ self.delegate.push_outlives(sup, sub, info);
}
/// Relate a projection type and some value type lazily. This will always
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
+ self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
if self.ambient_covariance() {
// Covariance: a <= b. Hence, `b: a`.
- self.push_outlives(v_b, v_a);
+ self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
}
if self.ambient_contravariance() {
// Contravariant: b <= a. Hence, `a: b`.
- self.push_outlives(v_a, v_b);
+ self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
}
Ok(a)
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
use rustc_errors::{ErrorReported, PResult};
use rustc_expand::base::ExtCtxt;
-use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
+use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::Crate;
use rustc_lint::LintStore;
use rustc_metadata::creader::CStore;
let crate_types = util::collect_crate_types(sess, &krate.attrs);
sess.init_crate_types(crate_types);
- let stable_crate_id = StableCrateId::new(
- crate_name,
- sess.crate_types().contains(&CrateType::Executable),
- sess.opts.cg.metadata.clone(),
- );
- sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
- rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?;
+ let disambiguator = util::compute_crate_disambiguator(sess);
+ sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
+ rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?;
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {
.tempdir_in(out_filename.parent().unwrap())
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
- let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
+ let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
}
self.prepare_outputs.compute(|| {
let expansion_result = self.expansion()?;
let (krate, boxed_resolver, _) = &*expansion_result.peek();
- let crate_name = self.crate_name()?;
- let crate_name = crate_name.peek();
+ let crate_name = self.crate_name()?.peek();
passes::prepare_outputs(
self.session(),
self.compiler,
}
pub fn linker(&'tcx self) -> Result<Linker> {
- let dep_graph = self.dep_graph()?;
- let prepare_outputs = self.prepare_outputs()?;
- let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
- let ongoing_codegen = self.ongoing_codegen()?;
-
let sess = self.session().clone();
let codegen_backend = self.codegen_backend().clone();
+ let dep_graph = self.dep_graph()?.peek().clone();
+ let prepare_outputs = self.prepare_outputs()?.take();
+ let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
+ let ongoing_codegen = self.ongoing_codegen()?.take();
+
Ok(Linker {
sess,
- dep_graph: dep_graph.peek().clone(),
- prepare_outputs: prepare_outputs.take(),
- crate_hash,
- ongoing_codegen: ongoing_codegen.take(),
codegen_backend,
+
+ dep_graph,
+ prepare_outputs,
+ crate_hash,
+ ongoing_codegen,
})
}
}
pub struct Linker {
+ // compilation inputs
sess: Lrc<Session>,
+ codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+
+ // compilation outputs
dep_graph: DepGraph,
prepare_outputs: OutputFilenames,
crate_hash: Svh,
ongoing_codegen: Box<dyn Any>,
- codegen_backend: Lrc<Box<dyn CodegenBackend>>,
}
impl Linker {
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
use rustc_data_structures::jobserver;
+use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
use rustc_metadata::dynamic_lib::DynamicLibrary;
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
+use rustc_session::CrateDisambiguator;
use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use std::panic;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex, Once};
+use std::sync::{Arc, Mutex};
use std::thread;
use tracing::info;
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
make_codegen_backend(&sopts)
} else {
- get_codegen_backend(&sopts)
+ get_codegen_backend(
+ &sopts.maybe_sysroot,
+ sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]),
+ )
};
// target_override is documented to be called before init(), so this is okay
}
}
-pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
- static INIT: Once = Once::new();
-
- static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
+/// Get the codegen backend based on the name and specified sysroot.
+///
+/// A name of `None` indicates that the default backend should be used.
+pub fn get_codegen_backend(
+ maybe_sysroot: &Option<PathBuf>,
+ backend_name: Option<&str>,
+) -> Box<dyn CodegenBackend> {
+ static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
- INIT.call_once(|| {
+ let load = LOAD.get_or_init(|| {
#[cfg(feature = "llvm")]
const DEFAULT_CODEGEN_BACKEND: &str = "llvm";
#[cfg(not(feature = "llvm"))]
const DEFAULT_CODEGEN_BACKEND: &str = "cranelift";
- let codegen_name = sopts
- .debugging_opts
- .codegen_backend
- .as_ref()
- .map(|name| &name[..])
- .unwrap_or(DEFAULT_CODEGEN_BACKEND);
-
- let backend = match codegen_name {
+ match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) {
filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
- codegen_name => get_builtin_codegen_backend(&sopts.maybe_sysroot, codegen_name),
- };
-
- unsafe {
- LOAD = backend;
+ #[cfg(feature = "llvm")]
+ "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
+ backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
}
});
- unsafe { LOAD() }
+
+ // SAFETY: In case of a builtin codegen backend this is safe. In case of an external codegen
+ // backend we hope that the backend links against the same rustc_driver version. If this is not
+ // the case, we get UB.
+ unsafe { load() }
}
// This is used for rustdoc, but it uses similar machinery to codegen backend
}
}
-pub fn get_builtin_codegen_backend(
- maybe_sysroot: &Option<PathBuf>,
- backend_name: &str,
-) -> fn() -> Box<dyn CodegenBackend> {
- match backend_name {
- #[cfg(feature = "llvm")]
- "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
- _ => get_codegen_sysroot(maybe_sysroot, backend_name),
- }
-}
-
pub fn get_codegen_sysroot(
maybe_sysroot: &Option<PathBuf>,
backend_name: &str,
}
}
+pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
+ use std::hash::Hasher;
+
+ // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
+ // into various other hashes quite a bit (symbol hashes, incr. comp. hashes,
+ // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits
+ // should still be safe enough to avoid collisions in practice.
+ let mut hasher = StableHasher::new();
+
+ let mut metadata = session.opts.cg.metadata.clone();
+ // We don't want the crate_disambiguator to dependent on the order
+ // -C metadata arguments, so sort them:
+ metadata.sort();
+ // Every distinct -C metadata value is only incorporated once:
+ metadata.dedup();
+
+ hasher.write(b"metadata");
+ for s in &metadata {
+ // Also incorporate the length of a metadata string, so that we generate
+ // different values for `-Cmetadata=ab -Cmetadata=c` and
+ // `-Cmetadata=a -Cmetadata=bc`
+ hasher.write_usize(s.len());
+ hasher.write(s.as_bytes());
+ }
+
+ // Also incorporate crate type, so that we don't get symbol conflicts when
+ // linking against a library of the same name, if this is an executable.
+ let is_exe = session.crate_types().contains(&CrateType::Executable);
+ hasher.write(if is_exe { b"exe" } else { b"lib" });
+
+ CrateDisambiguator::from(hasher.finish::<Fingerprint>())
+}
+
pub(crate) fn check_attr_crate_type(
sess: &Session,
attrs: &[ast::Attribute],
if let Some(list) = attr.meta_item_list() {
for meta in list {
- if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
+ if meta.has_name(sym::hidden) {
return true;
}
}
}
}
- /// Checks the validity of lint names derived from the command line
- pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+ /// Checks the validity of lint names derived from the command line. Returns
+ /// true if the lint is valid, false otherwise.
+ pub fn check_lint_name_cmdline(
+ &self,
+ sess: &Session,
+ lint_name: &str,
+ level: Option<Level>,
+ ) -> bool {
let db = match self.check_lint_name(lint_name, None) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
};
if let Some(mut db) = db {
- let msg = format!(
- "requested on the command line with `{} {}`",
- match level {
- Level::Allow => "-A",
- Level::Warn => "-W",
- Level::Deny => "-D",
- Level::Forbid => "-F",
- },
- lint_name
- );
- db.note(&msg);
+ if let Some(level) = level {
+ let msg = format!(
+ "requested on the command line with `{} {}`",
+ match level {
+ Level::Allow => "-A",
+ Level::Warn => "-W",
+ Level::Deny => "-D",
+ Level::Forbid => "-F",
+ },
+ lint_name
+ );
+ db.note(&msg);
+ }
db.emit();
+ false
+ } else {
+ true
}
}
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
for &(ref lint_name, level) in &sess.opts.lint_opts {
- store.check_lint_name_cmdline(sess, &lint_name, level);
+ store.check_lint_name_cmdline(sess, &lint_name, Some(level));
let orig_level = level;
// If the cap is less than this specified level, e.g., if we've got
}
}
+ for lint_name in &sess.opts.force_warns {
+ let valid = store.check_lint_name_cmdline(sess, lint_name, None);
+ if valid {
+ let lints = store
+ .find_lints(lint_name)
+ .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+ self.sets.force_warns.extend(&lints);
+ }
+ }
+
self.sets.list.push(LintSet::CommandLine { specs });
}
LintLevelSource::Default => false,
LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+ LintLevelSource::ForceWarn(_symbol) => {
+ bug!("forced warn lint returned a forbid lint level")
+ }
};
debug!(
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
LintLevelSource::CommandLine(_, _) => {
diag_builder.note("`forbid` lint level was set on command line");
}
+ _ => bug!("forced warn lint returned a forbid lint level"),
}
diag_builder.emit();
};
variant: &'a ty::VariantDef,
) -> Option<&'a ty::FieldDef> {
let param_env = tcx.param_env(variant.def_id);
- for field in &variant.fields {
+ variant.fields.iter().find(|field| {
let field_ty = tcx.type_of(field.did);
let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
-
- if !is_zst {
- return Some(field);
- }
- }
-
- None
+ !is_zst
+ })
}
/// Is type known to be non-null?
return false;
}
- for variant in &def.variants {
- if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
- if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
- return true;
- }
- }
- }
-
- false
+ def.variants
+ .iter()
+ .filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
+ .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, substs), mode))
}
_ => false,
}
}
match *ty.kind() {
- ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => {
- FfiSafe
- }
-
ty::Adt(def, substs) => {
+ if def.is_box() && matches!(self.mode, CItemKind::Definition) {
+ if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+ return FfiSafe;
+ } else {
+ return FfiUnsafe {
+ ty,
+ reason: format!("box cannot be represented as a single pointer"),
+ help: None,
+ };
+ }
+ }
if def.is_phantom_data() {
return FfiPhantom(ty);
}
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
MISSING_ABI,
+ INVALID_DOC_ATTRIBUTES,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
DISJOINT_CAPTURE_MIGRATION,
LEGACY_DERIVE_HELPERS,
"nvptx",
"hexagon",
"riscv",
+ "bpf",
];
let required_components = &[
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/Support/Signals.h"
install_fatal_error_handler(FatalErrorHandler);
}
-extern "C" LLVMMemoryBufferRef
-LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
- MemoryBuffer::getFile(Path, -1, false);
- if (!BufOr) {
- LLVMRustSetLastError(BufOr.getError().message().c_str());
- return nullptr;
- }
- return wrap(BufOr.get().release());
-}
-
extern "C" char *LLVMRustGetLastError(void) {
char *Ret = LastError;
LastError = nullptr;
}
}
-// Note that the two following functions look quite similar to the
-// LLVMGetSectionName function. Sadly, it appears that this function only
-// returns a char* pointer, which isn't guaranteed to be null-terminated. The
-// function provided by LLVM doesn't return the length, so we've created our own
-// function which returns the length as well as the data pointer.
-//
-// For an example of this not returning a null terminated string, see
-// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
-// branches explicitly creates a StringRef without a null terminator, and then
-// that's returned.
-
-inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
- return reinterpret_cast<section_iterator *>(SI);
-}
-
-extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI,
- const char **Ptr) {
- auto NameOrErr = (*unwrap(SI))->getName();
- if (!NameOrErr)
- report_fatal_error(NameOrErr.takeError());
- *Ptr = NameOrErr->data();
- return NameOrErr->size();
-}
-
// LLVMArrayType function does not support 64-bit ElementCount
extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
uint64_t ElementCount) {
LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) {
return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS)));
}
+
+// This struct contains all necessary info about a symbol exported from a DLL.
+// At the moment, it's just the symbol's name, but we use a separate struct to
+// make it easier to add other information like ordinal later.
+struct LLVMRustCOFFShortExport {
+ const char* name;
+};
+
+// Machine must be a COFF machine type, as defined in PE specs.
+extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
+ const char* ImportName,
+ const char* Path,
+ const LLVMRustCOFFShortExport* Exports,
+ size_t NumExports,
+ uint16_t Machine,
+ bool MinGW)
+{
+ std::vector<llvm::object::COFFShortExport> ConvertedExports;
+ ConvertedExports.reserve(NumExports);
+
+ for (size_t i = 0; i < NumExports; ++i) {
+ ConvertedExports.push_back(llvm::object::COFFShortExport{
+ Exports[i].name, // Name
+ std::string{}, // ExtName
+ std::string{}, // SymbolName
+ std::string{}, // AliasTarget
+ 0, // Ordinal
+ false, // Noname
+ false, // Data
+ false, // Private
+ false // Constant
+ });
+ }
+
+ auto Error = llvm::object::writeImportLibrary(
+ ImportName,
+ Path,
+ ConvertedExports,
+ static_cast<llvm::COFF::MachineTypes>(Machine),
+ MinGW);
+ if (Error) {
+ std::string errorString;
+ llvm::raw_string_ostream stream(errorString);
+ stream << Error;
+ stream.flush();
+ LLVMRustSetLastError(errorString.c_str());
+ return LLVMRustResult::Failure;
+ } else {
+ return LLVMRustResult::Success;
+ }
+}
LLVMInitializeWebAssemblyAsmPrinter,
LLVMInitializeWebAssemblyAsmParser
);
+ init_target!(
+ llvm_component = "bpf",
+ LLVMInitializeBPFTargetInfo,
+ LLVMInitializeBPFTarget,
+ LLVMInitializeBPFTargetMC,
+ LLVMInitializeBPFAsmPrinter,
+ LLVMInitializeBPFAsmParser
+ );
}
let decode_body = match s.variants() {
[vi] => {
let construct = vi.construct(|field, index| decode_field(field, index, true));
- let n_fields = vi.ast().fields.len();
quote! {
::rustc_serialize::Decoder::read_struct(
__decoder,
- #ty_name,
- #n_fields,
|__decoder| { ::std::result::Result::Ok(#construct) },
)
}
quote! {
::rustc_serialize::Decoder::read_enum(
__decoder,
- #ty_name,
|__decoder| {
::rustc_serialize::Decoder::read_enum_variant(
__decoder,
quote! {
match ::rustc_serialize::Decoder::#decode_method(
- __decoder, #opt_field_name #index, #decode_inner_method) {
+ __decoder, #opt_field_name #decode_inner_method) {
::std::result::Result::Ok(__res) => __res,
::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
}
}
});
- let ty_name = s.ast().ident.to_string();
let encode_body = match s.variants() {
[_] => {
let mut field_idx = 0usize;
.ident
.as_ref()
.map_or_else(|| field_idx.to_string(), |i| i.to_string());
+ let first = field_idx == 0;
let result = quote! {
match ::rustc_serialize::Encoder::emit_struct_field(
__encoder,
#field_name,
- #field_idx,
+ #first,
|__encoder|
::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
})
.collect::<TokenStream>()
});
+ let no_fields = field_idx == 0;
quote! {
- ::rustc_serialize::Encoder::emit_struct(__encoder, #ty_name, #field_idx, |__encoder| {
+ ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
::std::result::Result::Ok(match *self { #encode_inner })
})
}
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
+ let first = field_idx == 0;
let result = quote! {
match ::rustc_serialize::Encoder::emit_enum_variant_arg(
__encoder,
- #field_idx,
+ #first,
|__encoder|
::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
result
});
quote! {
- ::rustc_serialize::Encoder::emit_enum(__encoder, #ty_name, |__encoder| {
+ ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
match *self {
#encode_inner
}
use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
-use rustc_session::Session;
+use rustc_session::{CrateDisambiguator, Session};
use rustc_span::edition::Edition;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
metadata_loader: &'a MetadataLoaderDyn,
local_crate_name: &str,
) -> Self {
+ let local_crate_stable_id =
+ StableCrateId::new(local_crate_name, sess.local_crate_disambiguator());
let mut stable_crate_ids = FxHashMap::default();
- stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
+ stable_crate_ids.insert(local_crate_stable_id, LOCAL_CRATE);
CrateLoader {
sess,
fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
// Check for (potential) conflicts with the local crate
- if self.sess.local_stable_crate_id() == root.stable_crate_id() {
+ if self.local_crate_name == root.name()
+ && self.sess.local_crate_disambiguator() == root.disambiguator()
+ {
return Err(CrateError::SymbolConflictsCurrent(root.name()));
}
// Check for conflicts with any crate loaded so far
let mut res = Ok(());
self.cstore.iter_crate_data(|_, other| {
- if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id
+ if other.name() == root.name() && // same crate-name
+ other.disambiguator() == root.disambiguator() && // same crate-disambiguator
other.hash() != root.hash()
{
// but different SVH
None => (&source, &crate_root),
};
let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
- Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
+ Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
} else {
None
};
fn dlsym_proc_macros(
&self,
path: &Path,
- stable_crate_id: StableCrateId,
+ disambiguator: CrateDisambiguator,
) -> Result<&'static [ProcMacro], CrateError> {
// Make sure the path contains a / or the linker will search for it.
let path = env::current_dir().unwrap().join(path);
Err(s) => return Err(CrateError::DlOpen(s)),
};
- let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+ let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
let decls = unsafe {
let sym = match lib.symbol(&sym) {
Ok(f) => f,
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::CanonicalizedPath;
-use rustc_session::{Session, StableCrateId};
+use rustc_session::{CrateDisambiguator, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::{Target, TargetTriple};
metadata_loader: &dyn MetadataLoader,
span: Span,
name: Symbol,
-) -> (PathBuf, StableCrateId) {
+) -> (PathBuf, CrateDisambiguator) {
match find_plugin_registrar_impl(sess, metadata_loader, name) {
Ok(res) => res,
// `core` is always available if we got as far as loading plugins.
sess: &'a Session,
metadata_loader: &dyn MetadataLoader,
name: Symbol,
-) -> Result<(PathBuf, StableCrateId), CrateError> {
+) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
info!("find plugin registrar `{}`", name);
let mut locator = CrateLocator::new(
sess,
match locator.maybe_load_library_crate()? {
Some(library) => match library.source.dylib {
- Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())),
+ Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
None => Err(CrateError::NonDylibPlugin(name)),
},
None => Err(locator.into_error()),
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::NativeLib;
+use rustc_middle::middle::cstore::{DllImport, NativeLib};
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_session::utils::NativeLibKind;
impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
- let abi = match it.kind {
- hir::ItemKind::ForeignMod { abi, .. } => abi,
+ let (abi, foreign_mod_items) = match it.kind {
+ hir::ItemKind::ForeignMod { abi, items } => (abi, items),
_ => return,
};
foreign_module: Some(it.def_id.to_def_id()),
wasm_import_module: None,
verbatim: None,
+ dll_imports: Vec::new(),
};
let mut kind_specified = false;
.span_label(m.span, "missing `name` argument")
.emit();
}
+
+ if lib.kind == NativeLibKind::RawDylib {
+ match abi {
+ Abi::C { .. } => (),
+ Abi::Cdecl => (),
+ _ => {
+ if sess.target.arch == "x86" {
+ sess.span_fatal(
+ it.span,
+ r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#,
+ );
+ }
+ }
+ };
+ lib.dll_imports.extend(
+ foreign_mod_items
+ .iter()
+ .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }),
+ );
+ }
+
self.register_native_lib(Some(m.span), lib);
}
}
)
.emit();
}
- if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib {
- feature_err(
- &self.tcx.sess.parse_sess,
- sym::raw_dylib,
- span.unwrap_or(rustc_span::DUMMY_SP),
- "kind=\"raw-dylib\" is unstable",
- )
- .emit();
+ // this just unwraps lib.name; we already established that it isn't empty above.
+ if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
+ let span = match span {
+ Some(s) => s,
+ None => {
+ bug!("raw-dylib libraries are not supported on the command line");
+ }
+ };
+
+ if !self.tcx.sess.target.options.is_like_windows {
+ self.tcx.sess.span_fatal(
+ span,
+ "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
+ );
+ } else if !self.tcx.sess.target.options.is_like_msvc {
+ self.tcx.sess.span_warn(
+ span,
+ "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
+ );
+ }
+
+ if lib_name.as_str().contains('\0') {
+ self.tcx.sess.span_err(span, "library name may not contain NUL characters");
+ }
+
+ if !self.tcx.features().raw_dylib {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::raw_dylib,
+ span,
+ "kind=\"raw-dylib\" is unstable",
+ )
+ .emit();
+ }
}
+
self.libs.push(lib);
}
foreign_module: None,
wasm_import_module: None,
verbatim: passed_lib.verbatim,
+ dll_imports: Vec::new(),
};
self.register_native_lib(None, lib);
} else {
self.name
}
+ crate fn disambiguator(&self) -> CrateDisambiguator {
+ self.disambiguator
+ }
+
crate fn hash(&self) -> Svh {
self.hash
}
self.root.name
}
- crate fn stable_crate_id(&self) -> StableCrateId {
- self.root.stable_crate_id
+ crate fn disambiguator(&self) -> CrateDisambiguator {
+ self.root.disambiguator
}
crate fn hash(&self) -> Svh {
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::utils::NativeLibKind;
-use rustc_session::{Session, StableCrateId};
+use rustc_session::{CrateDisambiguator, Session};
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Symbol;
}
native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
foreign_modules => { cdata.get_foreign_modules(tcx) }
+ crate_disambiguator => { cdata.root.disambiguator }
crate_hash => { cdata.root.hash }
crate_host_hash => { cdata.host_hash }
crate_name => { cdata.root.name }
self.get_crate_data(cnum).root.name
}
- fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId {
- self.get_crate_data(cnum).root.stable_crate_id
+ fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
+ self.get_crate_data(cnum).root.disambiguator
}
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh {
extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
triple: tcx.sess.opts.target_triple.clone(),
hash: tcx.crate_hash(LOCAL_CRATE),
+ disambiguator: tcx.sess.local_crate_disambiguator(),
stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
panic_strategy: tcx.sess.panic_strategy(),
edition: tcx.sess.edition(),
});
record!(self.tables.span[def_id] <- tcx.def_span(def_id));
record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+ record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
}
use rustc_middle::ty::{self, ReprOptions, Ty};
use rustc_serialize::opaque::Encoder;
use rustc_session::config::SymbolManglingVersion;
+use rustc_session::CrateDisambiguator;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Ident, Symbol};
triple: TargetTriple,
extra_filename: String,
hash: Svh,
+ disambiguator: CrateDisambiguator,
stable_crate_id: StableCrateId,
panic_strategy: PanicStrategy,
edition: Edition,
// required that their size stay the same, but we don't want to change
// it inadvertently. This assert just ensures we're aware of any change.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 17);
+static_assert_size!(DepNode, 18);
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
static_assert_size!(DepNode, 24);
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
use rustc_index::vec::Idx;
-use rustc_span::def_id::StableCrateId;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident, Symbol};
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
- tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
+ tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher);
let crate_hash: Fingerprint = stable_hasher.finish();
Svh::new(crate_hash.to_smaller_hash())
}
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(StableCrateId, Svh)> {
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
let mut upstream_crates: Vec<_> = cstore
.crates_untracked()
.iter()
.map(|&cnum| {
- let stable_crate_id = cstore.stable_crate_id_untracked(cnum);
+ let name = cstore.crate_name_untracked(cnum);
+ let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
let hash = cstore.crate_hash_untracked(cnum);
- (stable_crate_id, hash)
+ (name, disambiguator, hash)
})
.collect();
- upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
+ upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
upstream_crates
}
};
providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
providers.all_local_trait_impls = |tcx, ()| &tcx.hir_crate(()).trait_impls;
+ providers.expn_that_defined = |tcx, id| {
+ let id = id.expect_local();
+ tcx.definitions.expansion_that_defined(id)
+ };
}
use std::cmp;
use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_hir::HirId;
/// The provided `Level` is the level specified on the command line.
/// (The actual level may be lower due to `--cap-lints`.)
CommandLine(Symbol, Level),
+
+ /// Lint is being forced to warn no matter what.
+ ForceWarn(Symbol),
}
impl LintLevelSource {
LintLevelSource::Default => symbol::kw::Default,
LintLevelSource::Node(name, _, _) => name,
LintLevelSource::CommandLine(name, _) => name,
+ LintLevelSource::ForceWarn(name) => name,
}
}
LintLevelSource::Default => DUMMY_SP,
LintLevelSource::Node(_, span, _) => span,
LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+ LintLevelSource::ForceWarn(_) => DUMMY_SP,
}
}
}
pub struct LintLevelSets {
pub list: Vec<LintSet>,
pub lint_cap: Level,
+ pub force_warns: FxHashSet<LintId>,
}
#[derive(Debug)]
impl LintLevelSets {
pub fn new() -> Self {
- LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+ LintLevelSets {
+ list: Vec::new(),
+ lint_cap: Level::Forbid,
+ force_warns: FxHashSet::default(),
+ }
}
pub fn get_lint_level(
aux: Option<&FxHashMap<LintId, LevelAndSource>>,
sess: &Session,
) -> LevelAndSource {
+ // Check whether we should always warn
+ if self.force_warns.contains(&LintId::of(lint)) {
+ return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
+ }
+
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
#[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let LintLevelMap { ref sets, ref id_to_set } = *self;
+ let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
id_to_set.hash_stable(hcx, hasher);
- let LintLevelSets { ref list, lint_cap } = *sets;
+ let LintLevelSets { ref list, lint_cap, .. } = *sets;
lint_cap.hash_stable(hcx, hasher);
);
}
}
+ LintLevelSource::ForceWarn(_) => {
+ sess.diag_note_once(
+ &mut err,
+ DiagnosticMessageId::from(lint),
+ "warning forced by `force-warns` commandline option",
+ );
+ }
}
err.code(DiagnosticId::Lint { name, has_future_breakage });
use rustc_macros::HashStable;
use rustc_session::search_paths::PathKind;
use rustc_session::utils::NativeLibKind;
-use rustc_session::StableCrateId;
+use rustc_session::CrateDisambiguator;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_target::spec::Target;
pub foreign_module: Option<DefId>,
pub wasm_import_module: Option<Symbol>,
pub verbatim: Option<bool>,
+ pub dll_imports: Vec<DllImport>,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+pub struct DllImport {
+ pub name: Symbol,
+ pub ordinal: Option<u16>,
}
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
// "queries" used in resolve that aren't tracked for incremental compilation
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
- fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId;
+ fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
// This is basically a 1-based range of ints, which is a little
pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
format!(
- "rust_metadata_{}_{:08x}",
+ "rust_metadata_{}_{}",
tcx.crate_name(LOCAL_CRATE),
- tcx.sess.local_stable_crate_id().to_u64(),
+ tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
)
}
// local crate's ID. Otherwise there can be collisions between CGUs
// instantiating stuff for upstream crates.
let local_crate_id = if cnum != LOCAL_CRATE {
- let local_stable_crate_id = tcx.sess.local_stable_crate_id();
- format!(
- "-in-{}.{:08x}",
- tcx.crate_name(LOCAL_CRATE),
- local_stable_crate_id.to_u64()
- )
+ let local_crate_disambiguator = format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
+ format!("-in-{}.{}", tcx.crate_name(LOCAL_CRATE), &local_crate_disambiguator[0..8])
} else {
String::new()
};
- let stable_crate_id = tcx.sess.local_stable_crate_id();
- format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id.to_u64(), local_crate_id)
+ let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
+ // Using a shortened disambiguator of about 40 bits
+ format!("{}.{}{}", tcx.crate_name(cnum), &crate_disambiguator[0..8], local_crate_id)
});
write!(cgu_name, "{}", crate_prefix).unwrap();
desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// Internal helper query. Use `tcx.expansion_that_defined` instead
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+ eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
}
query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
desc { "looking up the derive registrar for a crate" }
}
+ query crate_disambiguator(_: CrateNum) -> CrateDisambiguator {
+ eval_always
+ desc { "looking up the disambiguator a crate" }
+ }
// The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
// Changing the name should cause a compiler error, but in case that changes, be aware.
query crate_hash(_: CrateNum) -> Svh {
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
pub fn def_path_debug_str(self, def_id: DefId) -> String {
// We are explicitly not going through queries here in order to get
- // crate name and stable crate id since this code is called from debug!()
+ // crate name and disambiguator since this code is called from debug!()
// statements within the query system and we'd run into endless
// recursion otherwise.
- let (crate_name, stable_crate_id) = if def_id.is_local() {
- (self.crate_name, self.sess.local_stable_crate_id())
+ let (crate_name, crate_disambiguator) = if def_id.is_local() {
+ (self.crate_name, self.sess.local_crate_disambiguator())
} else {
(
self.cstore.crate_name_untracked(def_id.krate),
- self.def_path_hash(def_id.krate.as_def_id()).stable_crate_id(),
+ self.cstore.crate_disambiguator_untracked(def_id.krate),
)
};
format!(
"{}[{}]{}",
crate_name,
- // Don't print the whole stable crate id. That's just
+ // Don't print the whole crate disambiguator. That's just
// annoying in debug output.
- &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
+ &(crate_disambiguator.to_fingerprint().to_hex())[..4],
self.def_path(def_id).to_string_no_crate_verbose()
)
}
for &i in &inverse_memory_index {
let field = fields[i as usize];
if !sized {
- bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty);
+ self.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "univariant: field #{} of `{}` comes after unsized field",
+ offsets.len(),
+ ty
+ ),
+ );
}
if field.is_unsized() {
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
use rustc_hir::{Constness, Node};
use rustc_macros::HashStable;
-use rustc_span::hygiene::ExpnId;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts,
+ RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
&& use_name
.span
.ctxt()
- .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
- }
-
- pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
- match scope.as_local() {
- // Parsing and expansion aren't incremental, so we don't
- // need to go through a query for the same-crate case.
- Some(scope) => self.hir().definitions().expansion_that_defined(scope),
- None => self.expn_that_defined(scope),
- }
+ .hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id))
}
pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
- ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope));
+ ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
ident
}
block: hir::HirId,
) -> (Ident, DefId) {
let scope =
- match ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope))
- {
+ match ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope)) {
Some(actual_expansion) => {
self.hir().definitions().parent_module_of_macro_def(actual_expansion)
}
use rustc_serialize::opaque;
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind;
+use rustc_session::CrateDisambiguator;
use rustc_target::spec::PanicStrategy;
use rustc_ast as ast;
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
Decodable, Decoder, Encodable, Encoder,
};
-use rustc_session::{Session, StableCrateId};
+use rustc_session::{CrateDisambiguator, Session};
use rustc_span::hygiene::{
ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
SyntaxContext, SyntaxContextData,
// session.
current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
- prev_cnums: Vec<(u32, StableCrateId)>,
+ prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
source_map: &'sess SourceMap,
#[derive(Encodable, Decodable)]
struct Footer {
file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
- prev_cnums: Vec<(u32, StableCrateId)>,
+ prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
query_result_index: EncodedQueryResultIndex,
diagnostics_index: EncodedQueryResultIndex,
// The location of all allocations.
let prev_cnums: Vec<_> = sorted_cnums
.iter()
.map(|&cnum| {
- let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
- (cnum.as_u32(), stable_crate_id)
+ let crate_name = tcx.crate_name(cnum).to_string();
+ let crate_disambiguator = tcx.crate_disambiguator(cnum);
+ (cnum.as_u32(), crate_name, crate_disambiguator)
})
.collect();
// maps to None.
fn compute_cnum_map(
tcx: TyCtxt<'_>,
- prev_cnums: &[(u32, StableCrateId)],
+ prev_cnums: &[(u32, String, CrateDisambiguator)],
) -> IndexVec<CrateNum, Option<CrateNum>> {
tcx.dep_graph.with_ignore(|| {
let current_cnums = tcx
.all_crate_nums(())
.iter()
.map(|&cnum| {
- let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
- (stable_crate_id, cnum)
+ let crate_name = tcx.crate_name(cnum).to_string();
+ let crate_disambiguator = tcx.crate_disambiguator(cnum);
+ ((crate_name, crate_disambiguator), cnum)
})
.collect::<FxHashMap<_, _>>();
let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
let mut map = IndexVec::from_elem_n(None, map_size as usize);
- for &(prev_cnum, stable_crate_id) in prev_cnums {
- map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&stable_crate_id).cloned();
+ for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
+ let key = (crate_name.clone(), crate_disambiguator);
+ map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
}
map[LOCAL_CRATE] = Some(LOCAL_CRATE);
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
+ info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T>;
///////////////////////////////////////////////////////////////////////////
// Relate impls
-impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
- fn relate<R: TypeRelation<'tcx>>(
- relation: &mut R,
- a: ty::TypeAndMut<'tcx>,
- b: ty::TypeAndMut<'tcx>,
- ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
- debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
- if a.mutbl != b.mutbl {
- Err(TypeError::Mutability)
- } else {
- let mutbl = a.mutbl;
- let variance = match mutbl {
- ast::Mutability::Not => ty::Covariant,
- ast::Mutability::Mut => ty::Invariant,
- };
- let ty = relation.relate_with_variance(variance, a.ty, b.ty)?;
- Ok(ty::TypeAndMut { ty, mutbl })
- }
+fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::TypeAndMut<'tcx>,
+ b: ty::TypeAndMut<'tcx>,
+ kind: ty::VarianceDiagMutKind,
+) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
+ debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
+ if a.mutbl != b.mutbl {
+ Err(TypeError::Mutability)
+ } else {
+ let mutbl = a.mutbl;
+ let (variance, info) = match mutbl {
+ ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+ ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }),
+ };
+ let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
+ Ok(ty::TypeAndMut { ty, mutbl })
}
}
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
let variance = variances.map_or(ty::Invariant, |v| v[i]);
- relation.relate_with_variance(variance, a, b)
+ relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
});
tcx.mk_substs(params)
if is_output {
relation.relate(a, b)
} else {
- relation.relate_with_variance(ty::Contravariant, a, b)
+ relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a,
+ b,
+ )
}
})
.enumerate()
b.item_def_id,
)))
} else {
- let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
- let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?;
+ let ty = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.ty,
+ b.ty,
+ )?;
+ let substs = relation.relate_with_variance(
+ ty::Invariant,
+ ty::VarianceDiagInfo::default(),
+ a.substs,
+ b.substs,
+ )?;
Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
}
}
(&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
- relation.relate_with_variance(ty::Contravariant, a_region, b_region)
+ relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_region,
+ b_region,
+ )
})?;
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
}
}
(&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
- let mt = relation.relate(a_mt, b_mt)?;
+ let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
Ok(tcx.mk_ptr(mt))
}
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
- let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+ let r = relation.relate_with_variance(
+ ty::Contravariant,
+ ty::VarianceDiagInfo::default(),
+ a_r,
+ b_r,
+ )?;
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
- let mt = relation.relate(a_mt, b_mt)?;
+ let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
Ok(tcx.mk_ref(r, mt))
}
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if au.def == bu.def && au.promoted == bu.promoted =>
{
- let substs =
- relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?;
+ let substs = relation.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ au.substs,
+ bu.substs,
+ )?;
return Ok(tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def,
matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
- #[inline]
- pub fn is_machine(&self) -> bool {
- matches!(self.kind(), Int(..) | Uint(..) | Float(..))
- }
-
#[inline]
pub fn has_concrete_skeleton(&self) -> bool {
!matches!(self.kind(), Param(_) | Infer(_) | Error(_))
}
}
}
+
+/// Extra information about why we ended up with a particular variance.
+/// This is only used to add more information to error messages, and
+/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
+/// may lead to confusing notes in error messages, it will never cause
+/// a miscompilation or unsoundness.
+///
+/// When in doubt, use `VarianceDiagInfo::default()`
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagInfo<'tcx> {
+ /// No additional information - this is the default.
+ /// We will not add any additional information to error messages.
+ None,
+ /// We switched our variance because a type occurs inside
+ /// the generic argument of a mutable reference or pointer
+ /// (`*mut T` or `&mut T`). In either case, our variance
+ /// will always be `Invariant`.
+ Mut {
+ /// Tracks whether we had a mutable pointer or reference,
+ /// for better error messages
+ kind: VarianceDiagMutKind,
+ /// The type parameter of the mutable pointer/reference
+ /// (the `T` in `&mut T` or `*mut T`).
+ ty: Ty<'tcx>,
+ },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagMutKind {
+ /// A mutable raw pointer (`*mut T`)
+ RawPtr,
+ /// A mutable reference (`&mut T`)
+ Ref,
+}
+
+impl<'tcx> VarianceDiagInfo<'tcx> {
+ /// Mirrors `Variance::xform` - used to 'combine' the existing
+ /// and new `VarianceDiagInfo`s when our variance changes.
+ pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
+ // For now, just use the first `VarianceDiagInfo::Mut` that we see
+ match self {
+ VarianceDiagInfo::None => other,
+ VarianceDiagInfo::Mut { .. } => self,
+ }
+ }
+}
+
+impl<'tcx> Default for VarianceDiagInfo<'tcx> {
+ fn default() -> Self {
+ Self::None
+ }
+}
use rustc_data_structures::graph;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use rustc_span::DUMMY_SP;
use crate::borrow_check::{
/// Marker trait that controls whether a `R1: R2` constraint
/// represents an edge `R1 -> R2` or `R2 -> R1`.
crate trait ConstraintGraphDirecton: Copy + 'static {
- fn start_region(c: &OutlivesConstraint) -> RegionVid;
- fn end_region(c: &OutlivesConstraint) -> RegionVid;
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
fn is_normal() -> bool;
}
crate struct Normal;
impl ConstraintGraphDirecton for Normal {
- fn start_region(c: &OutlivesConstraint) -> RegionVid {
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sup
}
- fn end_region(c: &OutlivesConstraint) -> RegionVid {
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sub
}
crate struct Reverse;
impl ConstraintGraphDirecton for Reverse {
- fn start_region(c: &OutlivesConstraint) -> RegionVid {
+ fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sub
}
- fn end_region(c: &OutlivesConstraint) -> RegionVid {
+ fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
c.sup
}
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
/// construct SCCs for region inference but also for error
/// reporting.
- crate fn new(direction: D, set: &OutlivesConstraintSet, num_region_vars: usize) -> Self {
+ crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self {
let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
/// Given the constraint set from which this graph was built
/// creates a region graph so that you can iterate over *regions*
/// and not constraints.
- crate fn region_graph<'rg>(
+ crate fn region_graph<'rg, 'tcx>(
&'rg self,
- set: &'rg OutlivesConstraintSet,
+ set: &'rg OutlivesConstraintSet<'tcx>,
static_region: RegionVid,
- ) -> RegionGraph<'rg, D> {
+ ) -> RegionGraph<'rg, 'tcx, D> {
RegionGraph::new(set, self, static_region)
}
/// Given a region `R`, iterate over all constraints `R: R1`.
- crate fn outgoing_edges<'a>(
+ crate fn outgoing_edges<'a, 'tcx>(
&'a self,
region_sup: RegionVid,
- constraints: &'a OutlivesConstraintSet,
+ constraints: &'a OutlivesConstraintSet<'tcx>,
static_region: RegionVid,
- ) -> Edges<'a, D> {
+ ) -> Edges<'a, 'tcx, D> {
//if this is the `'static` region and the graph's direction is normal,
//then setup the Edges iterator to return all regions #53178
if region_sup == static_region && D::is_normal() {
}
}
-crate struct Edges<'s, D: ConstraintGraphDirecton> {
+crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
graph: &'s ConstraintGraph<D>,
- constraints: &'s OutlivesConstraintSet,
+ constraints: &'s OutlivesConstraintSet<'tcx>,
pointer: Option<OutlivesConstraintIndex>,
next_static_idx: Option<usize>,
static_region: RegionVid,
}
-impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
- type Item = OutlivesConstraint;
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
+ type Item = OutlivesConstraint<'tcx>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(p) = self.pointer {
self.pointer = self.graph.next_constraints[p];
- Some(self.constraints[p])
+ Some(self.constraints[p].clone())
} else if let Some(next_static_idx) = self.next_static_idx {
self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
None
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
category: ConstraintCategory::Internal,
+ variance_info: VarianceDiagInfo::default(),
})
} else {
None
/// This struct brings together a constraint set and a (normal, not
/// reverse) constraint graph. It implements the graph traits and is
/// usd for doing the SCC computation.
-crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
- set: &'s OutlivesConstraintSet,
+crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
+ set: &'s OutlivesConstraintSet<'tcx>,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
}
-impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
/// Creates a "dependency graph" where each region constraint `R1:
/// R2` is treated as an edge `R1 -> R2`. We use this graph to
/// construct SCCs for region inference but also for error
/// reporting.
crate fn new(
- set: &'s OutlivesConstraintSet,
+ set: &'s OutlivesConstraintSet<'tcx>,
constraint_graph: &'s ConstraintGraph<D>,
static_region: RegionVid,
) -> Self {
/// Given a region `R`, iterate over all regions `R1` such that
/// there exists a constraint `R: R1`.
- crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
+ crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
Successors {
edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
}
}
}
-crate struct Successors<'s, D: ConstraintGraphDirecton> {
- edges: Edges<'s, D>,
+crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
+ edges: Edges<'s, 'tcx, D>,
}
-impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> {
type Item = RegionVid;
fn next(&mut self) -> Option<Self::Item> {
}
}
-impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
type Node = RegionVid;
}
-impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
fn num_nodes(&self) -> usize {
self.constraint_graph.first_constraints.len()
}
}
-impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
self.outgoing_regions(node)
}
}
-impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> {
+impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
+ for RegionGraph<'s, 'tcx, D>
+{
type Item = RegionVid;
- type Iter = Successors<'graph, D>;
+ // FIXME - why can't this be `'graph, 'tcx`
+ type Iter = Successors<'graph, 'graph, D>;
}
use rustc_data_structures::graph::scc::Sccs;
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use std::fmt;
use std::ops::Index;
/// a unique `OutlivesConstraintIndex` and you can index into the set
/// (`constraint_set[i]`) to access the constraint details.
#[derive(Clone, Default)]
-crate struct OutlivesConstraintSet {
- outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint>,
+crate struct OutlivesConstraintSet<'tcx> {
+ outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
}
-impl OutlivesConstraintSet {
- crate fn push(&mut self, constraint: OutlivesConstraint) {
+impl<'tcx> OutlivesConstraintSet<'tcx> {
+ crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
debug!(
"OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
constraint.sup, constraint.sub, constraint.locations
Sccs::new(region_graph)
}
- crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint> {
+ crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
&self.outlives
}
}
-impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet {
- type Output = OutlivesConstraint;
+impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
+ type Output = OutlivesConstraint<'tcx>;
fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output {
&self.outlives[i]
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct OutlivesConstraint {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct OutlivesConstraint<'tcx> {
// NB. The ordering here is not significant for correctness, but
// it is for convenience. Before we dump the constraints in the
// debugging logs, we sort them, and we'd like the "super region"
/// What caused this constraint?
pub category: ConstraintCategory,
+
+ /// Variance diagnostic information
+ pub variance_info: VarianceDiagInfo<'tcx>,
}
-impl fmt::Debug for OutlivesConstraint {
+impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(formatter, "({:?}: {:?}) due to {:?}", self.sup, self.sub, self.locations)
+ write!(
+ formatter,
+ "({:?}: {:?}) due to {:?} ({:?})",
+ self.sup, self.sub, self.locations, self.variance_info
+ )
}
}
use rustc_span::symbol::Symbol;
use rustc_span::Span;
+use crate::borrow_check::region_infer::BlameConstraint;
use crate::borrow_check::{
borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
WriteKind,
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
- let (category, from_closure, span) = self.regioncx.best_blame_constraint(
- &self.body,
- borrow_region,
- NllRegionVariableOrigin::FreeRegion,
- |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
- );
+ let BlameConstraint { category, from_closure, span, variance_info: _ } =
+ self.regioncx.best_blame_constraint(
+ &self.body,
+ borrow_region,
+ NllRegionVariableOrigin::FreeRegion,
+ |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+ );
let outlived_fr_name = self.give_region_a_name(outlived_region);
use crate::util::borrowck_errors;
+use crate::borrow_check::region_infer::BlameConstraint;
use crate::borrow_check::{
nll::ConstraintDescription,
region_infer::{values::RegionElement, TypeTest},
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
- let (category, _, span) =
+ let BlameConstraint { category, span, variance_info, from_closure: _ } =
self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
- debug!("report_region_error: category={:?} {:?}", category, span);
+ debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
// Check if we can use one of the "nice region errors".
if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
let nice = NiceRegionError::new_from_span(self.infcx, span, o, f);
span,
};
- let diag = match (category, fr_is_local, outlived_fr_is_local) {
+ let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
self.report_fnmut_error(&errci, kind)
}
}
};
+ match variance_info {
+ ty::VarianceDiagInfo::None => {}
+ ty::VarianceDiagInfo::Mut { kind, ty } => {
+ let kind_name = match kind {
+ ty::VarianceDiagMutKind::Ref => "reference",
+ ty::VarianceDiagMutKind::RawPtr => "pointer",
+ };
+ diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
+ diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+ diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
+ }
+ }
+
diag.buffer(&mut self.errors_buffer);
}
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort();
for constraint in &constraints {
- let OutlivesConstraint { sup, sub, locations, category } = constraint;
+ let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
- type Edge = OutlivesConstraint;
+ type Edge = OutlivesConstraint<'tcx>;
fn graph_id(&'this self) -> dot::Id<'this> {
dot::Id::new("RegionInferenceContext").unwrap()
fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", n).into())
}
- fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
+ fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
}
}
impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
type Node = RegionVid;
- type Edge = OutlivesConstraint;
+ type Edge = OutlivesConstraint<'tcx>;
fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
vids.into()
}
- fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
+ fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
(&self.regioncx.constraints.outlives().raw[..]).into()
}
// Render `a: b` as `a -> b`, indicating the flow
// of data during inference.
- fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+ fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sup
}
- fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+ fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
edge.sub
}
}
liveness_constraints: LivenessValues<RegionVid>,
/// The outlives constraints computed by the type-check.
- constraints: Frozen<OutlivesConstraintSet>,
+ constraints: Frozen<OutlivesConstraintSet<'tcx>>,
/// The constraint-set, but in graph form, making it easy to traverse
/// the constraints adjacent to a particular region. Used to construct
Error,
}
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Trace {
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum Trace<'tcx> {
StartRegion,
- FromOutlivesConstraint(OutlivesConstraint),
+ FromOutlivesConstraint(OutlivesConstraint<'tcx>),
NotVisited,
}
universal_regions: Rc<UniversalRegions<'tcx>>,
placeholder_indices: Rc<PlaceholderIndices>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
- outlives_constraints: OutlivesConstraintSet,
+ outlives_constraints: OutlivesConstraintSet<'tcx>,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
closure_bounds_mapping: FxHashMap<
Location,
crate fn retrieve_closure_constraint_info(
&self,
body: &Body<'tcx>,
- constraint: &OutlivesConstraint,
- ) -> (ConstraintCategory, bool, Span) {
+ constraint: &OutlivesConstraint<'tcx>,
+ ) -> BlameConstraint<'tcx> {
let loc = match constraint.locations {
- Locations::All(span) => return (constraint.category, false, span),
+ Locations::All(span) => {
+ return BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span,
+ variance_info: constraint.variance_info.clone(),
+ };
+ }
Locations::Single(loc) => loc,
};
let opt_span_category =
self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
- opt_span_category.map(|&(category, span)| (category, true, span)).unwrap_or((
- constraint.category,
- false,
- body.source_info(loc).span,
- ))
+ opt_span_category
+ .map(|&(category, span)| BlameConstraint {
+ category,
+ from_closure: true,
+ span: span,
+ variance_info: constraint.variance_info.clone(),
+ })
+ .unwrap_or(BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span: body.source_info(loc).span,
+ variance_info: constraint.variance_info.clone(),
+ })
}
/// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory, Span) {
- let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| {
- self.provides_universal_region(r, fr1, fr2)
- });
+ let BlameConstraint { category, span, .. } =
+ self.best_blame_constraint(body, fr1, fr1_origin, |r| {
+ self.provides_universal_region(r, fr1, fr2)
+ });
(category, span)
}
&self,
from_region: RegionVid,
target_test: impl Fn(RegionVid) -> bool,
- ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
+ ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
context[from_region] = Trace::StartRegion;
let mut result = vec![];
let mut p = r;
loop {
- match context[p] {
+ match context[p].clone() {
Trace::NotVisited => {
bug!("found unvisited region {:?} on path to {:?}", p, r)
}
Trace::FromOutlivesConstraint(c) => {
- result.push(c);
p = c.sup;
+ result.push(c);
}
Trace::StartRegion => {
// Always inline this closure because it can be hot.
let mut handle_constraint = #[inline(always)]
- |constraint: OutlivesConstraint| {
+ |constraint: OutlivesConstraint<'tcx>| {
debug_assert_eq!(constraint.sup, r);
let sub_region = constraint.sub;
if let Trace::NotVisited = context[sub_region] {
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
category: ConstraintCategory::OpaqueType,
+ variance_info: ty::VarianceDiagInfo::default(),
};
handle_constraint(constraint);
}
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
- ) -> (ConstraintCategory, bool, Span) {
+ ) -> BlameConstraint<'tcx> {
debug!(
"best_blame_constraint(from_region={:?}, from_region_origin={:?})",
from_region, from_region_origin
debug!(
"best_blame_constraint: path={:#?}",
path.iter()
- .map(|&c| format!(
+ .map(|c| format!(
"{:?} ({:?}: {:?})",
c,
self.constraint_sccs.scc(c.sup),
);
// Classify each of the constraints along the path.
- let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
+ let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
.map(|constraint| {
if constraint.category == ConstraintCategory::ClosureBounds {
self.retrieve_closure_constraint_info(body, &constraint)
} else {
- (constraint.category, false, constraint.locations.span(body))
+ BlameConstraint {
+ category: constraint.category,
+ from_closure: false,
+ span: constraint.locations.span(body),
+ variance_info: constraint.variance_info.clone(),
+ }
}
})
.collect();
};
let find_region = |i: &usize| {
- let constraint = path[*i];
+ let constraint = &path[*i];
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
if blame_source {
- match categorized_path[*i].0 {
+ match categorized_path[*i].category {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
_ => constraint_sup_scc != target_scc,
}
} else {
- match categorized_path[*i].0 {
+ match categorized_path[*i].category {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
- if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
- && next.0 == ConstraintCategory::OpaqueType
+ if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
+ && next.category == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
- return *next;
+ return next.clone();
}
}
- if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
+ if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
+ {
let field = categorized_path.iter().find_map(|p| {
- if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
+ if let ConstraintCategory::ClosureUpvar(f) = p.category {
+ Some(f)
+ } else {
+ None
+ }
});
if let Some(field) = field {
- categorized_path[i].0 =
+ categorized_path[i].category =
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
}
}
- return categorized_path[i];
+ return categorized_path[i].clone();
}
// If that search fails, that is.. unusual. Maybe everything
// is in the same SCC or something. In that case, find what
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
- categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+ categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
debug!("`: sorted_path={:#?}", categorized_path);
- *categorized_path.first().unwrap()
+ categorized_path.remove(0)
}
}
.collect()
}
}
+
+#[derive(Clone, Debug)]
+pub struct BlameConstraint<'tcx> {
+ pub category: ConstraintCategory,
+ pub from_closure: bool,
+ pub span: Span,
+ pub variance_info: ty::VarianceDiagInfo<'tcx>,
+}
category: self.category,
sub,
sup,
+ variance_info: ty::VarianceDiagInfo::default(),
});
}
fn regions_that_outlive_free_regions(
num_region_vars: usize,
universal_regions: &UniversalRegions<'tcx>,
- constraint_set: &OutlivesConstraintSet,
+ constraint_set: &OutlivesConstraintSet<'tcx>,
) -> FxHashSet<RegionVid> {
// Build a graph of the outlives constraints thus far. This is
// a reverse graph, so for each constraint `R1: R2` we have an
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = cx.location_table;
facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
- |constraint: &OutlivesConstraint| {
+ |constraint: &OutlivesConstraint<'_>| {
if let Some(from_location) = constraint.locations.from_location() {
Either::Left(iter::once((
constraint.sup,
let locations = location.to_locations();
for constraint in constraints.outlives().iter() {
- let mut constraint = *constraint;
+ let mut constraint = constraint.clone();
constraint.locations = locations;
if let ConstraintCategory::Return(_)
| ConstraintCategory::UseAsConst
/// hence it must report on their liveness constraints.
crate liveness_constraints: LivenessValues<RegionVid>,
- crate outlives_constraints: OutlivesConstraintSet,
+ crate outlives_constraints: OutlivesConstraintSet<'tcx>,
crate member_constraints: MemberConstraintSet<'tcx, RegionVid>,
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
category,
+ variance_info: ty::VarianceDiagInfo::default(),
});
match mutbl {
)
}
- fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+ fn push_outlives(
+ &mut self,
+ sup: ty::Region<'tcx>,
+ sub: ty::Region<'tcx>,
+ info: ty::VarianceDiagInfo<'tcx>,
+ ) {
if let Some(borrowck_context) = &mut self.borrowck_context {
let sub = borrowck_context.universal_regions.to_region_vid(sub);
let sup = borrowck_context.universal_regions.to_region_vid(sup);
sub,
locations: self.locations,
category: self.category,
+ variance_info: info,
});
}
}
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
+#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(map_try_insert)]
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
if let ty::RawPtr(_) = base_ty.kind() {
if proj_base.is_empty() {
- if let (local, []) = (place_local, proj_base) {
- let decl = &self.body.local_decls[local];
- if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
- let span = decl.source_info.span;
- self.check_static(def_id, span);
- return;
- }
+ let decl = &self.body.local_decls[place_local];
+ if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+ let span = decl.source_info.span;
+ self.check_static(def_id, span);
+ return;
}
}
self.check_op(ops::RawPtrDeref);
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
simplify_locals(body, tcx);
}
}
if has_opts_to_apply {
let mut opt_applier = OptApplier { tcx, duplicates };
opt_applier.visit_body(body);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
// Since this optimization adds new basic blocks and invalidates others,
// clean up the cfg to make it nicer for other passes
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
// Make sure we remove dead blocks to remove
// unrelated code from the resume part of the function
- simplify::remove_dead_blocks(&mut body);
+ simplify::remove_dead_blocks(tcx, &mut body);
dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
// Make sure we remove dead blocks to remove
// unrelated code from the drop part of the function
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
}
if inline(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
}
}
}
}
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
}
- simplify::remove_dead_blocks(body)
+ simplify::remove_dead_blocks(tcx, body)
}
}
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
for block in basic_blocks.iter_mut() {
for statement in block.statements.iter_mut() {
- match statement.kind {
- StatementKind::Assign(box (place, _)) => {
- let place_ty = place.ty(local_decls, tcx).ty;
- if !maybe_zst(place_ty) {
- continue;
- }
- let layout = match tcx.layout_of(param_env.and(place_ty)) {
- Ok(layout) => layout,
- Err(_) => continue,
- };
- if !layout.is_zst() {
- continue;
- }
- if involves_a_union(place, local_decls, tcx) {
- continue;
- }
- if tcx.consider_optimizing(|| {
- format!(
- "RemoveZsts - Place: {:?} SourceInfo: {:?}",
- place, statement.source_info
- )
- }) {
- statement.make_nop();
- }
+ if let StatementKind::Assign(box (place, _)) = statement.kind {
+ let place_ty = place.ty(local_decls, tcx).ty;
+ if !maybe_zst(place_ty) {
+ continue;
+ }
+ let layout = match tcx.layout_of(param_env.and(place_ty)) {
+ Ok(layout) => layout,
+ Err(_) => continue,
+ };
+ if !layout.is_zst() {
+ continue;
+ }
+ if involves_a_union(place, local_decls, tcx) {
+ continue;
+ }
+ if tcx.consider_optimizing(|| {
+ format!(
+ "RemoveZsts - Place: {:?} SourceInfo: {:?}",
+ place, statement.source_info
+ )
+ }) {
+ statement.make_nop();
}
- _ => {}
}
}
}
use crate::transform::MirPass;
use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
}
}
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
CfgSimplifier::new(body).simplify();
- remove_dead_blocks(body);
+ remove_dead_blocks(tcx, body);
// FIXME: Should probably be moved into some kind of pass manager
body.basic_blocks_mut().raw.shrink_to_fit();
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
}
}
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
let reachable = traversal::reachable_as_bitset(body);
let num_blocks = body.basic_blocks().len();
if num_blocks == reachable.count() {
}
used_blocks += 1;
}
+
+ if tcx.sess.instrument_coverage() {
+ save_unreachable_coverage(basic_blocks, used_blocks);
+ }
+
basic_blocks.raw.truncate(used_blocks);
for block in basic_blocks {
}
}
+/// Some MIR transforms can determine at compile time that a sequences of
+/// statements will never be executed, so they can be dropped from the MIR.
+/// For example, an `if` or `else` block that is guaranteed to never be executed
+/// because its condition can be evaluated at compile time, such as by const
+/// evaluation: `if false { ... }`.
+///
+/// Those statements are bypassed by redirecting paths in the CFG around the
+/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// include `Coverage` statements representing the Rust source code regions to
+/// be counted at runtime. Without these `Coverage` statements, the regions are
+/// lost, and the Rust source code will show no coverage information.
+///
+/// What we want to show in a coverage report is the dead code with coverage
+/// counts of `0`. To do this, we need to save the code regions, by injecting
+/// `Unreachable` coverage statements. These are non-executable statements whose
+/// code regions are still recorded in the coverage map, representing regions
+/// with `0` executions.
+fn save_unreachable_coverage(
+ basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+ first_dead_block: usize,
+) {
+ let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
+ live_block.statements.iter().any(|statement| {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ matches!(coverage.kind, CoverageKind::Counter { .. })
+ } else {
+ false
+ }
+ })
+ });
+ if !has_live_counters {
+ // If there are no live `Counter` `Coverage` statements anymore, don't
+ // move dead coverage to the `START_BLOCK`. Just allow the dead
+ // `Coverage` statements to be dropped with the dead blocks.
+ //
+ // The `generator::StateTransform` MIR pass can create atypical
+ // conditions, where all live `Counter`s are dropped from the MIR.
+ //
+ // At least one Counter per function is required by LLVM (and necessary,
+ // to add the `function_hash` to the counter's call to the LLVM
+ // intrinsic `instrprof.increment()`).
+ return;
+ }
+
+ // Retain coverage info for dead blocks, so coverage reports will still
+ // report `0` executions for the uncovered code regions.
+ let mut dropped_coverage = Vec::new();
+ for dead_block in basic_blocks.raw[first_dead_block..].iter() {
+ for statement in dead_block.statements.iter() {
+ if let StatementKind::Coverage(coverage) = &statement.kind {
+ if let Some(code_region) = &coverage.code_region {
+ dropped_coverage.push((statement.source_info, code_region.clone()));
+ }
+ }
+ }
+ }
+
+ let start_block = &mut basic_blocks[START_BLOCK];
+ for (source_info, code_region) in dropped_coverage {
+ start_block.statements.push(Statement {
+ source_info,
+ kind: StatementKind::Coverage(box Coverage {
+ kind: CoverageKind::Unreachable,
+ code_region: Some(code_region),
+ }),
+ })
+ }
+}
+
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
if did_remove_blocks {
// We have dead blocks now, so remove those.
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
}
if replaced {
- simplify::remove_dead_blocks(body);
+ simplify::remove_dead_blocks(tcx, body);
}
}
}
// If we support tokens at all
if let Some(target_tokens) = ret.tokens_mut() {
- if let Some(target_tokens) = target_tokens {
- assert!(
- !self.capture_cfg,
- "Encountered existing tokens with capture_cfg set: {:?}",
- target_tokens
- );
- } else {
+ if target_tokens.is_none() {
// Store se our newly captured tokens into the AST node
*target_tokens = Some(tokens.clone());
- };
+ }
}
let final_attrs = ret.attrs();
/// Parses an expression, forcing tokens to be collected
pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
- // If we have outer attributes, then the call to `collect_tokens_trailing_token`
- // will be made for us.
- if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
- self.parse_expr()
- } else {
- // If we don't have outer attributes, then we need to ensure
- // that collection happens by using `collect_tokens_no_attrs`.
- // Expression don't support custom inner attributes, so `parse_expr`
- // will never try to collect tokens if we don't have outer attributes.
- self.collect_tokens_no_attrs(|this| this.parse_expr())
- }
+ self.collect_tokens_no_attrs(|this| this.parse_expr())
}
pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
/// Whether or not we should force collection of tokens for an AST node,
/// regardless of whether or not it has attributes
+#[derive(Clone, Copy, PartialEq)]
pub enum ForceCollect {
Yes,
No,
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Nonterminal, NonterminalKind, Token};
+use rustc_ast::AstLike;
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_span::symbol::{kw, Ident};
// which requires having captured tokens available. Since we cannot determine
// in advance whether or not a proc-macro will be (transitively) invoked,
// we always capture tokens for any `Nonterminal` which needs them.
- Ok(match kind {
+ let mut nt = match kind {
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
Some(item) => token::NtItem(item),
None => {
return Err(self.struct_span_err(self.token.span, msg));
}
}
- })
+ };
+
+ // If tokens are supported at all, they should be collected.
+ if matches!(nt.tokens_mut(), Some(None)) {
+ panic!(
+ "Missing tokens for nt {:?} at {:?}: {:?}",
+ nt,
+ nt.span(),
+ pprust::nonterminal_to_string(&nt)
+ );
+ }
+
+ Ok(nt)
}
}
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
match self.parse_angle_args() {
Ok(args) => Ok(args),
- Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
- // Cancel error from being unable to find `>`. We know the error
- // must have been this due to a non-zero unmatched angle bracket
- // count.
- e.cancel();
-
+ Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
// Swap `self` with our backup of the parser state before attempting to parse
// generic arguments.
let snapshot = mem::replace(self, snapshot.unwrap());
- debug!(
- "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
- snapshot.count={:?}",
- snapshot.unmatched_angle_bracket_count,
- );
-
// Eat the unmatched angle brackets.
- for _ in 0..snapshot.unmatched_angle_bracket_count {
- self.eat_lt();
- }
-
- // Make a span over ${unmatched angle bracket count} characters.
- let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
- self.struct_span_err(
- span,
- &format!(
- "unmatched angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- String::new(),
- Applicability::MachineApplicable,
- )
- .emit();
+ let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
+ .fold(true, |a, _| a && self.eat_lt());
+
+ if !all_angle_brackets {
+ // If there are other tokens in between the extraneous `<`s, we cannot simply
+ // suggest to remove them. This check also prevents us from accidentally ending
+ // up in the middle of a multibyte character (issue #84104).
+ let _ = mem::replace(self, snapshot);
+ Err(e)
+ } else {
+ // Cancel error from being unable to find `>`. We know the error
+ // must have been this due to a non-zero unmatched angle bracket
+ // count.
+ e.cancel();
+
+ debug!(
+ "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
+ snapshot.count={:?}",
+ snapshot.unmatched_angle_bracket_count,
+ );
+
+ // Make a span over ${unmatched angle bracket count} characters.
+ // This is safe because `all_angle_brackets` ensures that there are only `<`s,
+ // i.e. no multibyte characters, in this range.
+ let span =
+ lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
+ self.struct_span_err(
+ span,
+ &format!(
+ "unmatched angle bracket{}",
+ pluralize!(snapshot.unmatched_angle_bracket_count)
+ ),
+ )
+ .span_suggestion(
+ span,
+ &format!(
+ "remove extra angle bracket{}",
+ pluralize!(snapshot.unmatched_angle_bracket_count)
+ ),
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
- // Try again without unmatched angle bracket characters.
- self.parse_angle_args()
+ // Try again without unmatched angle bracket characters.
+ self.parse_angle_args()
+ }
}
Err(e) => Err(e),
}
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
// that starts like a path (1 token), but it fact not a path.
// Also, we avoid stealing syntax from `parse_item_`.
- self.parse_stmt_path_start(lo, attrs, force_collect)?
+ if force_collect == ForceCollect::Yes {
+ self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))
+ } else {
+ self.parse_stmt_path_start(lo, attrs)
+ }?
} else if let Some(item) =
self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
{
self.mk_stmt(lo, StmtKind::Empty)
} else if self.token != token::CloseDelim(token::Brace) {
// Remainder are line-expr stmts.
- let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
+ let e = if force_collect == ForceCollect::Yes {
+ self.collect_tokens_no_attrs(|this| {
+ this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+ })
+ } else {
+ self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+ }?;
self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
} else {
self.error_outer_attrs(&attrs.take_for_recovery());
}))
}
- fn parse_stmt_path_start(
- &mut self,
- lo: Span,
- attrs: AttrWrapper,
- force_collect: ForceCollect,
- ) -> PResult<'a, Stmt> {
- let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
+ let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
let path = this.parse_path(PathStyle::Expr)?;
if this.eat(&token::Not) {
mut bounds: GenericBounds,
plus: bool,
) -> PResult<'a, TyKind> {
- assert_ne!(self.token, token::Question);
if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
target: Target,
specified_inline: &mut Option<(bool, Span)>,
) -> bool {
- if target == Target::Use {
+ if target == Target::Use || target == Target::ExternCrate {
let do_inline = meta.name_or_empty() == sym::inline;
if let Some((prev_inline, prev_span)) = *specified_inline {
if do_inline != prev_inline {
let mut is_valid = true;
if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) {
- for meta in list {
+ for meta in &list {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
sym::alias
| sym::html_no_source
| sym::html_playground_url
| sym::html_root_url
- | sym::include
| sym::inline
| sym::issue_tracker_base_url
| sym::keyword
);
diag.note("`doc(spotlight)` is now a no-op");
}
+ if i_meta.has_name(sym::include) {
+ if let Some(value) = i_meta.value_str() {
+ // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
+ let applicability = if list.len() == 1 {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ };
+ let inner = if attr.style == AttrStyle::Inner {
+ "!"
+ } else {
+ ""
+ };
+ diag.span_suggestion(
+ attr.meta().unwrap().span,
+ "use `doc = include_str!` instead",
+ format!(
+ "#{}[doc = include_str!(\"{}\")]",
+ inner, value
+ ),
+ applicability,
+ );
+ }
+ }
diag.emit();
},
);
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
if let Some(def_id) = path.res.opt_def_id() {
- let method_span = match path.segments {
- [.., _, last] => Some(last.ident.span),
- _ => None,
- };
- self.tcx.check_stability(def_id, Some(id), path.span, method_span)
+ self.tcx.check_stability(def_id, Some(id), path.span, None)
}
intravisit::walk_path(self, path)
}
let mut edge_list_data = Vec::with_capacity(edge_count);
for _index in 0..node_count {
- d.read_struct("NodeInfo", 3, |d| {
- let dep_node: DepNode<K> = d.read_struct_field("node", 0, Decodable::decode)?;
+ d.read_struct(|d| {
+ let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?;
let _i: SerializedDepNodeIndex = nodes.push(dep_node);
debug_assert_eq!(_i.index(), _index);
let fingerprint: Fingerprint =
- d.read_struct_field("fingerprint", 1, Decodable::decode)?;
+ d.read_struct_field("fingerprint", Decodable::decode)?;
let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
debug_assert_eq!(_i.index(), _index);
- d.read_struct_field("edges", 2, |d| {
+ d.read_struct_field("edges", |d| {
d.read_seq(|d, len| {
let start = edge_list_data.len().try_into().unwrap();
- for e in 0..len {
- let edge = d.read_seq_elt(e, Decodable::decode)?;
+ for _ in 0..len {
+ let edge = d.read_seq_elt(Decodable::decode)?;
edge_list_data.push(edge);
}
let end = edge_list_data.len().try_into().unwrap();
let mut module_map = FxHashMap::default();
module_map.insert(root_local_def_id, graph_root);
- let definitions = Definitions::new(session.local_stable_crate_id());
+ let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
let root = definitions.get_root_def();
let mut visibilities = FxHashMap::default();
let data = CratePreludeData {
crate_id: GlobalCrateId {
name: name.into(),
- disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0),
+ disambiguator: self
+ .tcx
+ .sess
+ .local_crate_disambiguator()
+ .to_fingerprint()
+ .as_value(),
},
crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
external_crates: self.save_ctxt.get_external_crates(),
num: n.as_u32(),
id: GlobalCrateId {
name: self.tcx.crate_name(n).to_string(),
- disambiguator: (
- self.tcx.def_path_hash(n.as_def_id()).stable_crate_id().to_u64(),
- 0,
- ),
+ disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(),
},
});
}
// FIXME: Should save-analysis beautify doc strings itself or leave it to users?
result.push_str(&beautify_doc_string(val).as_str());
result.push('\n');
- } else if self.tcx.sess.check_name(attr, sym::doc) {
- if let Some(meta_list) = attr.meta_item_list() {
- meta_list
- .into_iter()
- .filter(|it| it.has_name(sym::include))
- .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
- .flat_map(|it| it)
- .filter(|meta| meta.has_name(sym::contents))
- .filter_map(|meta| meta.value_str())
- .for_each(|val| {
- result.push_str(&val.as_str());
- result.push('\n');
- });
- }
}
}
d.read_seq(|d, len| {
let mut vec = SmallVec::with_capacity(len);
// FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
- for i in 0..len {
- vec.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ vec.push(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(vec)
})
fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
d.read_seq(|d, len| {
let mut list = LinkedList::new();
- for i in 0..len {
- list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(list)
})
fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
d.read_seq(|d, len| {
let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
- for i in 0..len {
- deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(deque)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
d.read_map(|d, len| {
let mut map = BTreeMap::new();
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
d.read_seq(|d, len| {
let mut set = BTreeSet::new();
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
d.read_map(|d, len| {
let state = Default::default();
let mut map = HashMap::with_capacity_and_hasher(len, state);
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
d.read_seq(|d, len| {
let state = Default::default();
let mut set = HashSet::with_capacity_and_hasher(len, state);
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
e.emit_map(self.len(), |e| {
for (i, (key, val)) in self.iter().enumerate() {
e.emit_map_elt_key(i, |e| key.encode(e))?;
- e.emit_map_elt_val(i, |e| val.encode(e))?;
+ e.emit_map_elt_val(|e| val.encode(e))?;
}
Ok(())
})
d.read_map(|d, len| {
let state = Default::default();
let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
- for i in 0..len {
- let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
- let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ for _ in 0..len {
+ let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
map.insert(key, val);
}
Ok(map)
d.read_seq(|d, len| {
let state = Default::default();
let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
- for i in 0..len {
- set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(set)
})
Ok(())
}
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+ fn emit_enum<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
}
}
- fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
write!(self.writer, ",")?;
}
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- name: &str,
- id: usize,
- cnt: usize,
- f: F,
- ) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant(name, id, cnt, f)
- }
-
- fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant_arg(idx, f)
- }
-
- fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult
+ fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+ fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
write!(self.writer, ",")?;
}
escape_str(self.writer, name)?;
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
fn emit_option<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
Ok(())
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+ fn emit_enum<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
}
}
- fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+ fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx != 0 {
+ if !first {
writeln!(self.writer, ",")?;
}
spaces(self.writer, self.curr_indent)?;
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- name: &str,
- id: usize,
- cnt: usize,
- f: F,
- ) -> EncodeResult
+ fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- self.emit_enum_variant(name, id, cnt, f)
- }
-
- fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_enum_variant_arg(idx, f)
- }
-
- fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- if len == 0 {
+ if no_fields {
write!(self.writer, "{{}}")?;
} else {
write!(self.writer, "{{")?;
Ok(())
}
- fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+ fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
if self.is_emitting_map_key {
return Err(EncoderError::BadHashmapKey);
}
- if idx == 0 {
+ if first {
writeln!(self.writer)?;
} else {
writeln!(self.writer, ",")?;
self.emit_seq_elt(idx, f)
}
- fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq(len, f)
- }
- fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
- where
- F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
- {
- if self.is_emitting_map_key {
- return Err(EncoderError::BadHashmapKey);
- }
- self.emit_seq_elt(idx, f)
- }
-
fn emit_option<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
Ok(())
}
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+ fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
where
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
{
Ok(())
}
- fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T>
+ fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self, idx)
}
- fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T>
- where
- F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
- {
- self.read_enum_variant(names, f)
- }
-
- fn read_enum_struct_variant_field<T, F>(
- &mut self,
- _name: &str,
- idx: usize,
- f: F,
- ) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_enum_variant_arg(idx, f)
- }
-
- fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T>
+ fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
Ok(value)
}
- fn read_struct_field<T, F>(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
})
}
- fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_seq_elt(idx, f)
- }
-
- fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> DecodeResult<T>
- where
- F: FnOnce(&mut Decoder) -> DecodeResult<T>,
- {
- self.read_tuple(len, f)
- }
-
- fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
- self.read_tuple_arg(idx, f)
+ self.read_seq_elt(f)
}
fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
f(self, len)
}
- fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
f(self)
}
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T>
where
F: FnOnce(&mut Decoder) -> DecodeResult<T>,
{
// Compound types:
#[inline]
- fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error>
+ fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
}
#[inline]
- fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error>
+ fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
f(self)
}
- fn emit_enum_struct_variant<F>(
- &mut self,
- v_name: &str,
- v_id: usize,
- len: usize,
- f: F,
- ) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum_variant(v_name, v_id, len, f)
- }
-
- fn emit_enum_struct_variant_field<F>(
- &mut self,
- _f_name: &str,
- f_idx: usize,
- f: F,
- ) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_enum_variant_arg(f_idx, f)
- }
-
#[inline]
- fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error>
+ fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
}
#[inline]
- fn emit_struct_field<F>(
- &mut self,
- _f_name: &str,
- _f_idx: usize,
- f: F,
- ) -> Result<(), Self::Error>
+ fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
f(self)
}
- fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_tuple(len, f)
- }
-
- fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<(), Self::Error>,
- {
- self.emit_tuple_arg(f_idx, f)
- }
-
// Specialized types:
fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
- self.emit_enum("Option", f)
+ self.emit_enum(f)
}
#[inline]
}
#[inline]
- fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+ fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
where
F: FnOnce(&mut Self) -> Result<(), Self::Error>,
{
// Compound types:
#[inline]
- fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
+ fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
f(self)
}
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error>
- where
- F: FnMut(&mut Self, usize) -> Result<T, Self::Error>,
- {
- self.read_enum_variant(names, f)
- }
-
- fn read_enum_struct_variant_field<T, F>(
- &mut self,
- _f_name: &str,
- f_idx: usize,
- f: F,
- ) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_enum_variant_arg(f_idx, f)
- }
-
#[inline]
- fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, Self::Error>
+ fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_struct_field<T, F>(
- &mut self,
- _f_name: &str,
- _f_idx: usize,
- f: F,
- ) -> Result<T, Self::Error>
+ fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
f(self)
}
- fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_tuple(len, f)
- }
-
- fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error>
- where
- F: FnOnce(&mut Self) -> Result<T, Self::Error>,
- {
- self.read_tuple_arg(a_idx, f)
- }
-
// Specialized types:
fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
where
F: FnMut(&mut Self, bool) -> Result<T, Self::Error>,
{
- self.read_enum("Option", move |this| {
+ self.read_enum(move |this| {
this.read_enum_variant(&["None", "Some"], move |this, idx| match idx {
0 => f(this, false),
1 => f(this, true),
}
#[inline]
- fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
}
#[inline]
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where
F: FnOnce(&mut Self) -> Result<T, Self::Error>,
{
default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
d.read_seq(|d, len| {
let mut v = Vec::with_capacity(len);
- for i in 0..len {
- v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ for _ in 0..len {
+ v.push(d.read_seq_elt(|d| Decodable::decode(d))?);
}
Ok(v)
})
assert!(len == N);
let mut v = [0u8; N];
for i in 0..len {
- v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?;
+ v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
}
Ok(v)
})
impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_enum("Result", |s| match *self {
+ s.emit_enum(|s| match *self {
Ok(ref v) => {
- s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+ s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
}
Err(ref v) => {
- s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+ s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
}
})
}
impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
- d.read_enum("Result", |d| {
+ d.read_enum(|d| {
d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
- 0 => Ok(Ok(d.read_enum_variant_arg(0, |d| T1::decode(d))?)),
- 1 => Ok(Err(d.read_enum_variant_arg(0, |d| T2::decode(d))?)),
+ 0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)),
+ 1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)),
_ => {
panic!(
"Encountered invalid discriminant while \
fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
let len: usize = count!($($name)+);
d.read_tuple(len, |d| {
- let mut i = 0;
- let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {
+ let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> {
Decodable::decode(d)
})?,)+);
Ok(ret)
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
lint_opts: Vec::new(),
+ force_warns: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: OutputTypes(BTreeMap::new()),
level",
"LEVEL",
),
+ opt::multi_s(
+ "",
+ "force-warns",
+ "Specifiy lints that should warn even if \
+ they are allowed somewhere else",
+ "LINT",
+ ),
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag_s("V", "version", "Print version info and exit"),
opt::flag_s("v", "verbose", "Use verbose output"),
pub fn get_cmd_lint_options(
matches: &getopts::Matches,
error_format: ErrorOutputType,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
+ debugging_opts: &DebuggingOptions,
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
lint::Level::from_str(&cap)
.unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
});
- (lint_opts, describe_lints, lint_cap)
+
+ if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to enable \
+ the flag `--force-warns=lints`",
+ );
+ }
+
+ let force_warns = matches.opt_strs("force-warns");
+
+ (lint_opts, describe_lints, lint_cap, force_warns)
}
/// Parses the `--color` flag.
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e[..]));
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, force_warns) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
+
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
if !debugging_opts.unstable_options && json_unused_externs {
optimize: opt_level,
debuginfo,
lint_opts,
+ force_warns,
lint_cap,
describe_lints,
output_types,
)+};
}
+ impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
+ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ match self {
+ Some(x) => {
+ Hash::hash(&1, hasher);
+ DepTrackingHash::hash(x, hasher, error_format);
+ }
+ None => Hash::hash(&0, hasher),
+ }
+ }
+ }
+
impl_dep_tracking_hash_via_hash!(
bool,
usize,
+ NonZeroUsize,
u64,
String,
PathBuf,
lint::Level,
- Option<bool>,
- Option<u32>,
- Option<usize>,
- Option<NonZeroUsize>,
- Option<String>,
- Option<(String, u64)>,
- Option<Vec<String>>,
- Option<MergeFunctions>,
- Option<RelocModel>,
- Option<CodeModel>,
- Option<TlsModel>,
- Option<WasiExecModel>,
- Option<PanicStrategy>,
- Option<RelroLevel>,
- Option<InstrumentCoverage>,
- Option<lint::Level>,
- Option<PathBuf>,
+ WasiExecModel,
+ u32,
+ RelocModel,
+ CodeModel,
+ TlsModel,
+ InstrumentCoverage,
CrateType,
MergeFunctions,
PanicStrategy,
TargetTriple,
Edition,
LinkerPluginLto,
- Option<SplitDebuginfo>,
+ SplitDebuginfo,
SwitchWithOptPath,
- Option<SymbolManglingVersion>,
- Option<SourceFileHashAlgorithm>,
+ SymbolManglingVersion,
+ SourceFileHashAlgorithm,
TrimmedDefPaths,
);
debuginfo: DebugInfo [TRACKED],
lint_opts: Vec<(String, lint::Level)> [TRACKED],
lint_cap: Option<lint::Level> [TRACKED],
+ force_warns: Vec<String> [TRACKED],
describe_lints: bool [UNTRACKED],
output_types: OutputTypes [TRACKED],
search_paths: Vec<SearchPath> [UNTRACKED],
use rustc_errors::registry::Registry;
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_lint_defs::FutureBreakage;
-pub use rustc_span::def_id::StableCrateId;
+pub use rustc_span::crate_disambiguator::CrateDisambiguator;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
use rustc_span::{edition::Edition, RealFileName};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
/// in order to avoid redundantly verbose output (Issue #24690, #44953).
pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
crate_types: OnceCell<Vec<CrateType>>,
- /// The `stable_crate_id` is constructed out of the crate name and all the
- /// `-C metadata` arguments passed to the compiler. Its value forms a unique
- /// global identifier for the crate. It is used to allow multiple crates
- /// with the same name to coexist. See the
+ /// The `crate_disambiguator` is constructed out of all the `-C metadata`
+ /// arguments passed to the compiler. Its value together with the crate-name
+ /// forms a unique global identifier for the crate. It is used to allow
+ /// multiple crates with the same name to coexist. See the
/// `rustc_codegen_llvm::back::symbol_names` module for more information.
- pub stable_crate_id: OnceCell<StableCrateId>,
+ pub crate_disambiguator: OnceCell<CrateDisambiguator>,
features: OnceCell<rustc_feature::Features>,
self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage);
}
- pub fn local_stable_crate_id(&self) -> StableCrateId {
- self.stable_crate_id.get().copied().unwrap()
+ pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
+ self.crate_disambiguator.get().copied().unwrap()
}
pub fn crate_types(&self) -> &[CrateType] {
/// Returns the symbol name for the registrar function,
/// given the crate `Svh` and the function `DefIndex`.
- pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String {
- format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64())
+ pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
+ format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex())
}
- pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
- format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
+ pub fn generate_proc_macro_decls_symbol(&self, disambiguator: CrateDisambiguator) -> String {
+ format!("__rustc_proc_macro_decls_{}__", disambiguator.to_fingerprint().to_hex())
}
pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
working_dir,
one_time_diagnostics: Default::default(),
crate_types: OnceCell::new(),
- stable_crate_id: OnceCell::new(),
+ crate_disambiguator: OnceCell::new(),
features: OnceCell::new(),
lint_store: OnceCell::new(),
recursion_limit: OnceCell::new(),
--- /dev/null
+// This is here because `rustc_session` wants to refer to it,
+// and so does `rustc_hir`, but `rustc_hir` shouldn't refer to `rustc_session`.
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::{base_n, impl_stable_hash_via_hash};
+
+use std::fmt;
+
+/// Hash value constructed out of all the `-C metadata` arguments passed to the
+/// compiler. Together with the crate-name forms a unique global identifier for
+/// the crate.
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)]
+pub struct CrateDisambiguator(Fingerprint);
+
+impl CrateDisambiguator {
+ pub fn to_fingerprint(self) -> Fingerprint {
+ self.0
+ }
+}
+
+impl fmt::Display for CrateDisambiguator {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ let (a, b) = self.0.as_value();
+ let as_u128 = a as u128 | ((b as u128) << 64);
+ f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
+ }
+}
+
+impl From<Fingerprint> for CrateDisambiguator {
+ fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
+ CrateDisambiguator(fingerprint)
+ }
+}
+
+impl_stable_hash_via_hash!(CrateDisambiguator);
+use crate::crate_disambiguator::CrateDisambiguator;
use crate::HashStableContext;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
}
}
-/// A [StableCrateId] is a 64 bit hash of the crate name combined with all
-/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to
-/// [DefId]. It is stable across compilation sessions.
+/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It
+/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across
+/// compilation sessions.
///
/// Since the ID is a hash value there is a (very small) chance that two crates
/// end up with the same [StableCrateId]. The compiler will check for such
/// collisions when loading crates and abort compilation in order to avoid
/// further trouble.
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
-#[derive(HashStable_Generic, Encodable, Decodable)]
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)]
pub struct StableCrateId(u64);
impl StableCrateId {
- pub fn to_u64(self) -> u64 {
- self.0
- }
-
/// Computes the stable ID for a crate with the given name and
- /// `-Cmetadata` arguments.
- pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
+ /// disambiguator.
+ pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId {
use std::hash::Hash;
- use std::hash::Hasher;
let mut hasher = StableHasher::new();
crate_name.hash(&mut hasher);
-
- // We don't want the stable crate id to dependent on the order
- // -C metadata arguments, so sort them:
- metadata.sort();
- // Every distinct -C metadata value is only incorporated once:
- metadata.dedup();
-
- hasher.write(b"metadata");
- for s in &metadata {
- // Also incorporate the length of a metadata string, so that we generate
- // different values for `-Cmetadata=ab -Cmetadata=c` and
- // `-Cmetadata=a -Cmetadata=bc`
- hasher.write_usize(s.len());
- hasher.write(s.as_bytes());
- }
-
- // Also incorporate crate type, so that we don't get symbol conflicts when
- // linking against a library of the same name, if this is an executable.
- hasher.write(if is_exe { b"exe" } else { b"lib" });
-
+ crate_disambiguator.hash(&mut hasher);
StableCrateId(hasher.finish())
}
}
impl<E: Encoder> Encodable<E> for DefId {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct("DefId", 2, |s| {
- s.emit_struct_field("krate", 0, |s| self.krate.encode(s))?;
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
- s.emit_struct_field("index", 1, |s| self.index.encode(s))
+ s.emit_struct_field("index", false, |s| self.index.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for DefId {
default fn decode(d: &mut D) -> Result<DefId, D::Error> {
- d.read_struct("DefId", 2, |d| {
+ d.read_struct(|d| {
Ok(DefId {
- krate: d.read_struct_field("krate", 0, Decodable::decode)?,
- index: d.read_struct_field("index", 1, Decodable::decode)?,
+ krate: d.read_struct_field("krate", Decodable::decode)?,
+ index: d.read_struct_field("index", Decodable::decode)?,
})
})
}
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
+pub mod crate_disambiguator;
+
pub mod symbol;
pub use symbol::{sym, Symbol};
// an added assert statement
impl<S: Encoder> Encodable<S> for RealFileName {
fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
- encoder.emit_enum("RealFileName", |encoder| match *self {
+ encoder.emit_enum(|encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
Ok({
- encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
})
})
}
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
Ok({
- encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
- encoder.emit_enum_variant_arg(1, |encoder| virtual_name.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ encoder
+ .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
})
}),
})
impl<E: Encoder> Encodable<E> for Span {
default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
let span = self.data();
- s.emit_struct("Span", 2, |s| {
- s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?;
- s.emit_struct_field("hi", 1, |s| span.hi.encode(s))
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
+ s.emit_struct_field("hi", false, |s| span.hi.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for Span {
default fn decode(s: &mut D) -> Result<Span, D::Error> {
- s.read_struct("Span", 2, |d| {
- let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
- let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
+ s.read_struct(|d| {
+ let lo = d.read_struct_field("lo", Decodable::decode)?;
+ let hi = d.read_struct_field("hi", Decodable::decode)?;
Ok(Span::new(lo, hi, SyntaxContext::root()))
})
impl<S: Encoder> Encodable<S> for SourceFile {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_struct("SourceFile", 8, |s| {
- s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
- s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
- s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
- s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
- s.emit_struct_field("lines", 5, |s| {
+ s.emit_struct(false, |s| {
+ s.emit_struct_field("name", true, |s| self.name.encode(s))?;
+ s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
+ s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
+ s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
+ s.emit_struct_field("lines", false, |s| {
let lines = &self.lines[..];
// Store the length.
s.emit_u32(lines.len() as u32)?;
Ok(())
})?;
- s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?;
- s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?;
- s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?;
- s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?;
- s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s))
+ s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
+ s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
+ s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
+ s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
+ s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
})
}
}
impl<D: Decoder> Decodable<D> for SourceFile {
fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
- d.read_struct("SourceFile", 8, |d| {
- let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
+ d.read_struct(|d| {
+ let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?;
let src_hash: SourceFileHash =
- d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
- let start_pos: BytePos =
- d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
- let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
- let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| {
+ d.read_struct_field("src_hash", |d| Decodable::decode(d))?;
+ let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?;
+ let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?;
+ let lines: Vec<BytePos> = d.read_struct_field("lines", |d| {
let num_lines: u32 = Decodable::decode(d)?;
let mut lines = Vec::with_capacity(num_lines as usize);
Ok(lines)
})?;
let multibyte_chars: Vec<MultiByteChar> =
- d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?;
+ d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?;
let non_narrow_chars: Vec<NonNarrowChar> =
- d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
- let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
+ d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?;
+ let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?;
let normalized_pos: Vec<NormalizedPos> =
- d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
- let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
+ d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?;
+ let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?;
Ok(SourceFile {
name,
start_pos,
box_free,
box_patterns,
box_syntax,
+ bpf_target_feature,
braced_empty_structs,
branch,
breakpoint,
wrapping_add,
wrapping_mul,
wrapping_sub,
+ wreg,
write_bytes,
xmm_reg,
ymm_reg,
substs.hash_stable(&mut hcx, &mut hasher);
if let Some(instantiating_crate) = instantiating_crate {
- tcx.def_path_hash(instantiating_crate.as_def_id())
- .stable_crate_id()
- .hash_stable(&mut hcx, &mut hasher);
+ tcx.crate_name(instantiating_crate).as_str().hash_stable(&mut hcx, &mut hasher);
+ tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher);
}
// We want to avoid accidental collision between different types of instances.
// FIXME(eddyb) Precompute a custom symbol name based on attributes.
let is_foreign = if let Some(def_id) = def_id.as_local() {
if tcx.plugin_registrar_fn(()) == Some(def_id) {
- let stable_crate_id = tcx.sess.local_stable_crate_id();
- return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id);
+ let disambiguator = tcx.sess.local_crate_disambiguator();
+ return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
}
if tcx.proc_macro_decls_static(()) == Some(def_id) {
- let stable_crate_id = tcx.sess.local_stable_crate_id();
- return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+ let disambiguator = tcx.sess.local_crate_disambiguator();
+ return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
matches!(tcx.hir().get(hir_id), Node::ForeignItem(_))
fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.push("C");
- let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
- self.push_disambiguator(stable_crate_id.to_u64());
+ let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
+ self.push_disambiguator(fingerprint.to_smaller_hash());
let name = self.tcx.crate_name(cnum).as_str();
self.push_ident(&name);
Ok(self)
--- /dev/null
+// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td
+use crate::abi::call::{ArgAbi, FnAbi};
+
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+ if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
+ ret.make_indirect();
+ } else {
+ ret.extend_integer_width_to(32);
+ }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+ if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
+ arg.make_indirect();
+ } else {
+ arg.extend_integer_width_to(32);
+ }
+}
+
+pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+ if !fn_abi.ret.is_ignore() {
+ classify_ret(&mut fn_abi.ret);
+ }
+
+ for arg in &mut fn_abi.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg(arg);
+ }
+}
mod amdgpu;
mod arm;
mod avr;
+mod bpf;
mod hexagon;
mod mips;
mod mips64;
}
}
"asmjs" => wasm::compute_c_abi_info(cx, self),
+ "bpf" => bpf::compute_abi_info(self),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
}
match *self {
FieldsShape::Primitive => 0,
FieldsShape::Union(count) => count.get(),
- FieldsShape::Array { count, .. } => {
- let usize_count = count as usize;
- assert_eq!(usize_count as u64, count);
- usize_count
- }
+ FieldsShape::Array { count, .. } => count.try_into().unwrap(),
FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
}
}
unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
}
FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
- FieldsShape::Arbitrary { ref memory_index, .. } => {
- let r = memory_index[i];
- assert_eq!(r as usize as u32, r);
- r as usize
- }
+ FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(),
}
}
--- /dev/null
+use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+ Bpf BpfInlineAsmRegClass {
+ reg,
+ wreg,
+ }
+}
+
+impl BpfInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, I64; },
+ Self::wreg => types! { "alu32": I8, I16, I32; },
+ }
+ }
+}
+
+fn only_alu32(
+ _arch: InlineAsmArch,
+ mut has_feature: impl FnMut(&str) -> bool,
+ _target: &Target,
+) -> Result<(), &'static str> {
+ if !has_feature("alu32") {
+ Err("register can't be used without the `alu32` target feature")
+ } else {
+ Ok(())
+ }
+}
+
+def_regs! {
+ Bpf BpfInlineAsmReg BpfInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ w0: wreg = ["w0"] % only_alu32,
+ w1: wreg = ["w1"] % only_alu32,
+ w2: wreg = ["w2"] % only_alu32,
+ w3: wreg = ["w3"] % only_alu32,
+ w4: wreg = ["w4"] % only_alu32,
+ w5: wreg = ["w5"] % only_alu32,
+ w6: wreg = ["w6"] % only_alu32,
+ w7: wreg = ["w7"] % only_alu32,
+ w8: wreg = ["w8"] % only_alu32,
+ w9: wreg = ["w9"] % only_alu32,
+
+ #error = ["r10", "w10"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ }
+}
+
+impl BpfInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+
+ pub fn overlapping_regs(self, mut cb: impl FnMut(BpfInlineAsmReg)) {
+ cb(self);
+
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $r:ident : $w:ident
+ ),*
+ ) => {
+ match self {
+ $(
+ Self::$r => {
+ cb(Self::$w);
+ }
+ Self::$w => {
+ cb(Self::$r);
+ }
+ )*
+ }
+ };
+ }
+
+ reg_conflicts! {
+ r0 : w0,
+ r1 : w1,
+ r2 : w2,
+ r3 : w3,
+ r4 : w4,
+ r5 : w5,
+ r6 : w6,
+ r7 : w7,
+ r8 : w8,
+ r9 : w9
+ }
+ }
+}
mod aarch64;
mod arm;
+mod bpf;
mod hexagon;
mod mips;
mod nvptx;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
PowerPC64,
SpirV,
Wasm32,
+ Bpf,
}
impl FromStr for InlineAsmArch {
"mips64" => Ok(Self::Mips64),
"spirv" => Ok(Self::SpirV),
"wasm32" => Ok(Self::Wasm32),
+ "bpf" => Ok(Self::Bpf),
_ => Err(()),
}
}
Mips(MipsInlineAsmReg),
SpirV(SpirVInlineAsmReg),
Wasm(WasmInlineAsmReg),
+ Bpf(BpfInlineAsmReg),
// Placeholder for invalid register constraints for the current target
Err,
}
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
+ Self::Bpf(r) => r.name(),
Self::Err => "<reg>",
}
}
Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
+ Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
}
}
InlineAsmArch::Wasm32 => {
Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
+ InlineAsmArch::Bpf => {
+ Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
})
}
Self::PowerPC(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
+ Self::Bpf(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
Self::PowerPC(_) => cb(self),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::Mips(_) => cb(self),
+ Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
}
Mips(MipsInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
Wasm(WasmInlineAsmRegClass),
+ Bpf(BpfInlineAsmRegClass),
// Placeholder for invalid register constraints for the current target
Err,
}
Self::Mips(r) => r.name(),
Self::SpirV(r) => r.name(),
Self::Wasm(r) => r.name(),
+ Self::Bpf(r) => r.name(),
Self::Err => rustc_span::symbol::sym::reg,
}
}
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
+ Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
Self::Wasm(r) => r.suggest_modifier(arch, ty),
+ Self::Bpf(r) => r.suggest_modifier(arch, ty),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
Self::Wasm(r) => r.default_modifier(arch),
+ Self::Bpf(r) => r.default_modifier(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
Self::Mips(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
Self::Wasm(r) => r.supported_types(arch),
+ Self::Bpf(r) => r.supported_types(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
}
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
+ InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
})
}
Self::Mips(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
Self::Wasm(r) => r.valid_modifiers(arch),
+ Self::Bpf(r) => r.valid_modifiers(arch),
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
}
}
wasm::fill_reg_map(arch, has_feature, target, &mut map);
map
}
+ InlineAsmArch::Bpf => {
+ let mut map = bpf::regclass_map();
+ bpf::fill_reg_map(arch, has_feature, target, &mut map);
+ map
+ }
}
}
--- /dev/null
+use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions};
+use crate::{abi::Endian, spec::abi::Abi};
+
+pub fn opts(endian: Endian) -> TargetOptions {
+ TargetOptions {
+ allow_asm: true,
+ endian,
+ linker_flavor: LinkerFlavor::BpfLinker,
+ atomic_cas: false,
+ executables: true,
+ dynamic_linking: true,
+ no_builtins: true,
+ panic_strategy: PanicStrategy::Abort,
+ position_independent_executables: true,
+ // Disable MergeFunctions since:
+ // - older kernels don't support bpf-to-bpf calls
+ // - on newer kernels, userspace still needs to relocate before calling
+ // BPF_PROG_LOAD and not all BPF libraries do that yet
+ merge_functions: MergeFunctions::Disabled,
+ obj_is_bitcode: true,
+ requires_lto: false,
+ singlethread: true,
+ max_atomic_width: Some(64),
+ unsupported_abis: vec![
+ Abi::Cdecl,
+ Abi::Stdcall { unwind: false },
+ Abi::Stdcall { unwind: true },
+ Abi::Fastcall,
+ Abi::Vectorcall,
+ Abi::Thiscall { unwind: false },
+ Abi::Thiscall { unwind: true },
+ Abi::Aapcs,
+ Abi::Win64,
+ Abi::SysV64,
+ Abi::PtxKernel,
+ Abi::Msp430Interrupt,
+ Abi::X86Interrupt,
+ Abi::AmdGpuKernel,
+ ],
+ ..Default::default()
+ }
+}
--- /dev/null
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "bpfeb".to_string(),
+ data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+ pointer_width: 64,
+ arch: "bpf".to_string(),
+ options: bpf_base::opts(Endian::Big),
+ }
+}
--- /dev/null
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "bpfel".to_string(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+ pointer_width: 64,
+ arch: "bpf".to_string(),
+ options: bpf_base::opts(Endian::Little),
+ }
+}
mod apple_sdk_base;
mod arm_base;
mod avr_gnu_base;
+mod bpf_base;
mod dragonfly_base;
mod freebsd_base;
mod fuchsia_base;
Msvc,
Lld(LldFlavor),
PtxLinker,
+ BpfLinker,
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
((LinkerFlavor::Ld), "ld"),
((LinkerFlavor::Msvc), "msvc"),
((LinkerFlavor::PtxLinker), "ptx-linker"),
+ ((LinkerFlavor::BpfLinker), "bpf-linker"),
((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
+
+ ("bpfeb-unknown-none", bpfeb_unknown_none),
+ ("bpfel-unknown-none", bpfel_unknown_none),
}
/// Everything `rustc` knows about how to compile for a specific target.
// dependency on this specific gcc.
asm_args: vec!["-mcpu=msp430".to_string()],
linker: Some("msp430-elf-gcc".to_string()),
+ linker_is_gnu: false,
// There are no atomic CAS instructions available in the MSP430
// instruction set, and the LLVM backend doesn't currently support
// we use the LLD shipped with the Rust toolchain by default
linker: Some("rust-lld".to_owned()),
lld_flavor: LldFlavor::Wasm,
-
- // No need for indirection here, simd types can always be passed by
- // value as the whole module either has simd or not, which is different
- // from x86 (for example) where programs can have functions that don't
- // enable simd features.
- simd_types_indirect: false,
+ linker_is_gnu: false,
pre_link_args,
hir::intravisit::NestedVisitorMap::None
}
+ fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+ // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+ }
+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{
self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
};
+use rustc_session::CrateDisambiguator;
use rustc_span::Span;
use rustc_trait_selection::traits;
tcx.param_env(def_id).with_reveal_all_normalized(tcx)
}
+fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
+ assert_eq!(crate_num, LOCAL_CRATE);
+ tcx.sess.local_crate_disambiguator()
+}
+
fn instance_def_size_estimate<'tcx>(
tcx: TyCtxt<'tcx>,
instance_def: ty::InstanceDef<'tcx>,
param_env,
param_env_reveal_all_normalized,
trait_of_item,
+ crate_disambiguator,
instance_def_size_estimate,
issue33140_self_ty,
impl_defaultness,
}
}
+ // Check that we use types valid for use in the lanes of a SIMD "vector register"
+ // These are scalar types which directly match a "machine" type
+ // Yes: Integers, floats, "thin" pointers
+ // No: char, "fat" pointers, compound types
match e.kind() {
- ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
- _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
- ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
+ ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+ ty::Array(t, _clen)
+ if matches!(
+ t.kind(),
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
+ ) =>
+ { /* struct([f32; 4]) is ok */ }
_ => {
struct_span_err!(
tcx.sess,
use super::method::probe;
use std::fmt;
+use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn emit_coerce_suggestions(
// We have `&T`, check if what was expected was `T`. If so,
// we may want to suggest removing a `&`.
if sm.is_imported(expr.span) {
- if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = src.strip_prefix('&') {
+ // Go through the spans from which this span was expanded,
+ // and find the one that's pointing inside `sp`.
+ //
+ // E.g. for `&format!("")`, where we want the span to the
+ // `format!()` invocation instead of its expansion.
+ if let Some(call_span) =
+ iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
+ {
+ if let Ok(code) = sm.span_to_snippet(call_span) {
return Some((
sp,
"consider removing the borrow",
- src.to_string(),
+ code,
Applicability::MachineApplicable,
));
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
_: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
a: T,
b: T,
) -> RelateResult<'tcx, T> {
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
+ Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
if !ty.references_error() {
diag.span_suggestion(
span,
- "replace `_` with the correct type",
+ "replace with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
# support. You'll need to write a target specification at least, and most
# likely, teach rustc about the C ABI of the target. Get in touch with the
# Rust team and file an issue if you need assistance in porting!
-#targets = "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
+#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
# LLVM experimental targets to build support for. These targets are specified in
# the same format as above, but since these targets are experimental, they are
#[bench]
fn bench_chain_collect(b: &mut Bencher) {
let data = black_box([0; LEN]);
- b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::<Vec<_>>());
+ b.iter(|| data.iter().cloned().chain([1]).collect::<Vec<_>>());
}
#[bench]
fn bench_chain_chain_collect(b: &mut Bencher) {
let data = black_box([0; LEN]);
- b.iter(|| {
- data.iter()
- .cloned()
- .chain([1].iter().cloned())
- .chain([2].iter().cloned())
- .collect::<Vec<_>>()
- });
+ b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::<Vec<_>>());
}
#[bench]
-use core::array;
use core::cmp::{self};
use core::mem::replace;
}
pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
- array::IntoIter::new([self.b0, self.b1])
+ IntoIterator::into_iter([self.b0, self.b1])
}
}
#![allow(unused_attributes)]
#![stable(feature = "alloc", since = "1.36.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
use core::hash;
#[cfg(not(no_global_oom_handling))]
use core::iter::FromIterator;
-use core::iter::FusedIterator;
+use core::iter::{from_fn, FusedIterator};
#[cfg(not(no_global_oom_handling))]
use core::ops::Add;
#[cfg(not(no_global_oom_handling))]
{
use core::str::pattern::Searcher;
- let matches = {
+ let rejections = {
let mut searcher = pat.into_searcher(self);
- let mut matches = Vec::new();
-
- while let Some(m) = searcher.next_match() {
- matches.push(m);
- }
-
- matches
+ // Per Searcher::next:
+ //
+ // A Match result needs to contain the whole matched pattern,
+ // however Reject results may be split up into arbitrary many
+ // adjacent fragments. Both ranges may have zero length.
+ //
+ // In practice the implementation of Searcher::next_match tends to
+ // be more efficient, so we use it here and do some work to invert
+ // matches into rejections since that's what we want to copy below.
+ let mut front = 0;
+ let rejections: Vec<_> = from_fn(|| {
+ let (start, end) = searcher.next_match()?;
+ let prev_front = front;
+ front = end;
+ Some((prev_front, start))
+ })
+ .collect();
+ rejections.into_iter().chain(core::iter::once((front, self.len())))
};
- let len = self.len();
- let mut shrunk_by = 0;
+ let mut len = 0;
+ let ptr = self.vec.as_mut_ptr();
+
+ for (start, end) in rejections {
+ let count = end - start;
+ if start != len {
+ // SAFETY: per Searcher::next:
+ //
+ // The stream of Match and Reject values up to a Done will
+ // contain index ranges that are adjacent, non-overlapping,
+ // covering the whole haystack, and laying on utf8
+ // boundaries.
+ unsafe {
+ ptr::copy(ptr.add(start), ptr.add(len), count);
+ }
+ }
+ len += count;
+ }
- // SAFETY: start and end will be on utf8 byte boundaries per
- // the Searcher docs
unsafe {
- for (start, end) in matches {
- ptr::copy(
- self.vec.as_mut_ptr().add(end - shrunk_by),
- self.vec.as_mut_ptr().add(start - shrunk_by),
- len - end,
- );
- shrunk_by += end - start;
- }
- self.vec.set_len(len - shrunk_by);
+ self.vec.set_len(len);
}
}
///
/// ```
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10);
/// vec.shrink_to_fit();
/// assert!(vec.capacity() >= 3);
/// ```
/// #![feature(shrink_to)]
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
/// assert_eq!(vec.capacity(), 10);
/// vec.shrink_to(4);
/// assert!(vec.capacity() >= 4);
///
/// ```
/// let mut vec = Vec::with_capacity(10);
- /// vec.extend([1, 2, 3].iter().cloned());
+ /// vec.extend([1, 2, 3]);
///
/// assert_eq!(vec.capacity(), 10);
/// let slice = vec.into_boxed_slice();
/// ```
/// let mut v = vec![1, 2, 3];
/// let new = [7, 8];
- /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+ /// let u: Vec<_> = v.splice(..2, new).collect();
/// assert_eq!(v, &[7, 8, 3]);
/// assert_eq!(u, &[1, 2]);
/// ```
/// ```
/// let mut v = vec![0, 1, 2];
/// let new = [7, 8];
-/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
+/// let iter: std::vec::Splice<_> = v.splice(1.., new);
/// ```
#[derive(Debug)]
#[stable(feature = "vec_splice", since = "1.21.0")]
fn test_splice() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(2..4, a.iter().cloned());
+ v.splice(2..4, a);
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
v.splice(1..3, Some(20));
assert_eq!(v, &[1, 20, 11, 12, 5]);
fn test_splice_inclusive_range() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect();
+ let t1: Vec<_> = v.splice(2..=3, a).collect();
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
assert_eq!(t1, &[3, 4]);
let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
fn test_splice_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(5..6, a.iter().cloned());
+ v.splice(5..6, a);
}
#[test]
fn test_splice_inclusive_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- v.splice(5..=5, a.iter().cloned());
+ v.splice(5..=5, a);
}
#[test]
fn test_splice_forget() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
- std::mem::forget(v.splice(2..4, a.iter().cloned()));
+ std::mem::forget(v.splice(2..4, a));
assert_eq!(v, &[1, 2]);
}
{
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
- unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) }
+ unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
}
/// 'Zips up' two arrays into a single array of pairs.
/// ```
#[unstable(feature = "array_zip", issue = "80094")]
pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
- let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs));
+ let mut iter = IntoIterator::into_iter(self).zip(rhs);
// SAFETY: we know for certain that this iterator will yield exactly `N`
// items.
/// ];
///
/// assert_eq!(
- /// decode_utf16(v.iter().cloned())
+ /// decode_utf16(v)
/// .map(|r| r.map_err(|e| e.unpaired_surrogate()))
/// .collect::<Vec<_>>(),
/// vec![
/// ];
///
/// assert_eq!(
- /// decode_utf16(v.iter().cloned())
+ /// decode_utf16(v)
/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
/// .collect::<String>(),
/// "𝄞mus�ic�"
#![cfg(not(test))]
#![stable(feature = "core", since = "1.6.0")]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#![feature(const_fn_transmute)]
#![feature(abi_unadjusted)]
#![feature(adx_target_feature)]
-#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_caller_location)]
#![feature(slice_ptr_get)]
Unbounded,
}
-#[unstable(feature = "bound_as_ref", issue = "80996")]
impl<T> Bound<T> {
/// Converts from `&Bound<T>` to `Bound<&T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_ref(&self) -> Bound<&T> {
match *self {
Included(ref x) => Included(x),
/// Converts from `&mut Bound<T>` to `Bound<&T>`.
#[inline]
+ #[unstable(feature = "bound_as_ref", issue = "80996")]
pub fn as_mut(&mut self) -> Bound<&mut T> {
match *self {
Included(ref mut x) => Included(x),
Unbounded => Unbounded,
}
}
+
+ /// Maps a `Bound<T>` to a `Bound<U>` by applying a function to the contained value (including
+ /// both `Included` and `Excluded`), returning a `Bound` of the same kind.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound::*;
+ ///
+ /// let bound_string = Included("Hello, World!");
+ ///
+ /// assert_eq!(bound_string.map(|s| s.len()), Included(13));
+ /// ```
+ ///
+ /// ```
+ /// #![feature(bound_map)]
+ /// use std::ops::Bound;
+ /// use Bound::*;
+ ///
+ /// let unbounded_string: Bound<String> = Unbounded;
+ ///
+ /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded);
+ /// ```
+ #[inline]
+ #[unstable(feature = "bound_map", issue = "86026")]
+ pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Bound<U> {
+ match self {
+ Unbounded => Unbounded,
+ Included(x) => Included(f(x)),
+ Excluded(x) => Excluded(f(x)),
+ }
+ }
}
impl<T: Clone> Bound<&T> {
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
///
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
///
///
/// If the value is found then [`Result::Ok`] is returned, containing the
/// index of the matching element. If there are multiple matches, then any
- /// one of the matches could be returned. If the value is not found then
- /// [`Result::Err`] is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// one of the matches could be returned. The index is chosen
+ /// deterministically, but is subject to change in future versions of Rust.
+ /// If the value is not found then [`Result::Err`] is returned, containing
+ /// the index where a matching element could be inserted while maintaining
+ /// sorted order.
///
/// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
///
-use core::array::{self, IntoIter};
+use core::array;
use core::convert::TryFrom;
#[test]
#[test]
fn iterator_collect() {
let arr = [0, 1, 2, 5, 9];
- let v: Vec<_> = IntoIter::new(arr.clone()).collect();
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect();
assert_eq!(&arr[..], &v[..]);
}
#[test]
fn iterator_rev_collect() {
let arr = [0, 1, 2, 5, 9];
- let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect();
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect();
assert_eq!(&v[..], &[9, 5, 2, 1, 0]);
}
fn iterator_nth() {
let v = [0, 1, 2, 3, 4];
for i in 0..v.len() {
- assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]);
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]);
}
- assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None);
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None);
- let mut iter = IntoIter::new(v);
+ let mut iter = IntoIterator::into_iter(v);
assert_eq!(iter.nth(2).unwrap(), v[2]);
assert_eq!(iter.nth(1).unwrap(), v[4]);
}
#[test]
fn iterator_last() {
let v = [0, 1, 2, 3, 4];
- assert_eq!(IntoIter::new(v).last().unwrap(), 4);
- assert_eq!(IntoIter::new([0]).last().unwrap(), 0);
+ assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4);
+ assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0);
- let mut it = IntoIter::new([0, 9, 2, 4]);
+ let mut it = IntoIterator::into_iter([0, 9, 2, 4]);
assert_eq!(it.next_back(), Some(4));
assert_eq!(it.last(), Some(2));
}
#[test]
fn iterator_clone() {
- let mut it = IntoIter::new([0, 2, 4, 6, 8]);
+ let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next_back(), Some(8));
let mut clone = it.clone();
#[test]
fn iterator_fused() {
- let mut it = IntoIter::new([0, 9, 2]);
+ let mut it = IntoIterator::into_iter([0, 9, 2]);
assert_eq!(it.next(), Some(0));
assert_eq!(it.next(), Some(9));
assert_eq!(it.next(), Some(2));
#[test]
fn iterator_len() {
- let mut it = IntoIter::new([0, 1, 2, 5, 9]);
+ let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]);
assert_eq!(it.size_hint(), (5, Some(5)));
assert_eq!(it.len(), 5);
assert_eq!(it.is_empty(), false);
assert_eq!(it.is_empty(), false);
// Empty
- let it = IntoIter::new([] as [String; 0]);
+ let it = IntoIterator::into_iter([] as [String; 0]);
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.len(), 0);
assert_eq!(it.is_empty(), true);
#[test]
fn iterator_count() {
let v = [0, 1, 2, 3, 4];
- assert_eq!(IntoIter::new(v.clone()).count(), 5);
+ assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5);
- let mut iter2 = IntoIter::new(v);
+ let mut iter2 = IntoIterator::into_iter(v);
iter2.next();
iter2.next();
assert_eq!(iter2.count(), 3);
#[test]
fn iterator_flat_map() {
- assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10));
+ assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10));
}
#[test]
fn iterator_debug() {
let arr = [0, 1, 2, 5, 9];
- assert_eq!(format!("{:?}", IntoIter::new(arr)), "IntoIter([0, 1, 2, 5, 9])",);
+ assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",);
}
#[test]
// Simple: drop new iterator.
let i = Cell::new(0);
{
- IntoIter::new(five(&i));
+ IntoIterator::into_iter(five(&i));
}
assert_eq!(i.get(), 5);
// Call `next()` once.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
let _x = iter.next();
assert_eq!(i.get(), 0);
assert_eq!(iter.count(), 4);
// Check `clone` and calling `next`/`next_back`.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
iter.next();
assert_eq!(i.get(), 1);
iter.next_back();
// Check via `nth`.
let i = Cell::new(0);
{
- let mut iter = IntoIter::new(five(&i));
+ let mut iter = IntoIterator::into_iter(five(&i));
let _x = iter.nth(2);
assert_eq!(i.get(), 2);
let _y = iter.last();
// Check every element.
let i = Cell::new(0);
- for (index, _x) in IntoIter::new(five(&i)).enumerate() {
+ for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);
let i = Cell::new(0);
- for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() {
+ for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() {
assert_eq!(i.get(), index);
}
assert_eq!(i.get(), 5);
fn test_double_ended_zip() {
let xs = [1, 2, 3, 4, 5, 6];
let ys = [1, 2, 3, 7];
- let a = xs.iter().cloned();
- let b = ys.iter().cloned();
- let mut it = a.zip(b);
+ let mut it = xs.iter().cloned().zip(ys);
assert_eq!(it.next(), Some((1, 1)));
assert_eq!(it.next(), Some((2, 2)));
assert_eq!(it.next_back(), Some((4, 7)));
#![no_std]
#![unstable(feature = "panic_abort", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(nll)]
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
#![deny(missing_docs)]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.43" }
+compiler_builtins = { version = "0.1.44" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(deny(warnings))),
#[stable(feature = "box_from_path", since = "1.17.0")]
impl From<&Path> for Box<Path> {
+ /// Creates a boxed [`Path`] from a reference.
+ ///
+ /// This will allocate and clone `path` to it.
fn from(path: &Path) -> Box<Path> {
let boxed: Box<OsStr> = path.inner.into();
let rw = Box::into_raw(boxed) as *mut Path;
#[stable(feature = "box_from_cow", since = "1.45.0")]
impl From<Cow<'_, Path>> for Box<Path> {
+ /// Creates a boxed [`Path`] from a clone-on-write pointer.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(cow: Cow<'_, Path>) -> Box<Path> {
match cow {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+ /// Converts a borrowed `OsStr` to a `PathBuf`.
+ ///
+ /// Allocates a [`PathBuf`] and copies the data into it.
#[inline]
fn from(s: &T) -> PathBuf {
PathBuf::from(s.as_ref().to_os_string())
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<&'a Path> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`Path`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: &'a Path) -> Cow<'a, Path> {
Cow::Borrowed(s)
#[stable(feature = "cow_from_path", since = "1.6.0")]
impl<'a> From<PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from an owned
+ /// instance of [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(s: PathBuf) -> Cow<'a, Path> {
Cow::Owned(s)
#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
#[inline]
fn from(p: &'a PathBuf) -> Cow<'a, Path> {
Cow::Borrowed(p.as_path())
#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
impl<'a> From<Cow<'a, Path>> for PathBuf {
+ /// Converts a clone-on-write pointer to an owned path.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
#[inline]
fn from(p: Cow<'a, Path>) -> Self {
p.into_owned()
/// Returns `true` if the path points at an existing entity.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a regular file.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
/// Returns `true` if the path exists on disk and is pointing at a directory.
///
/// This function will traverse symbolic links to query information about the
- /// destination file. In case of broken symbolic links this will return `false`.
+ /// destination file.
///
- /// If you cannot access the directory containing the file, e.g., because of a
- /// permission error, this will return `false`.
+ /// If you cannot access the metadata of the file, e.g. because of a
+ /// permission error or broken symbolic links, this will return `false`.
///
/// # Examples
///
if #[cfg(target_os = "android")] {
#[link(name = "dl")]
#[link(name = "log")]
- #[link(name = "gcc")]
extern "C" {}
} else if #[cfg(target_os = "freebsd")] {
#[link(name = "execinfo")]
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] |
/// Currently, the following system calls are being used to get the current time using `now()`:
///
/// | Platform | System call |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] |
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
-#![doc(
- html_root_url = "https://doc.rust-lang.org/nightly/",
- html_playground_url = "https://play.rust-lang.org/",
- test(attr(deny(warnings)))
-)]
+#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))]
#![deny(missing_docs)]
#![cfg_attr(windows, feature(libc))]
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
- self.write_plain(&format!("test {} ... ", name))?;
+ if let Some(test_mode) = desc.test_mode() {
+ self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ } else {
+ self.write_plain(&format!("test {} ... ", name))?;
+ }
Ok(())
}
fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
let name = desc.padded_name(self.max_name_len, desc.name.padding());
- self.write_plain(&format!("test {} ... ", name))?;
+ if let Some(test_mode) = desc.test_mode() {
+ self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+ } else {
+ self.write_plain(&format!("test {} ... ", name))?;
+ }
Ok(())
}
#![crate_name = "test"]
#![unstable(feature = "test", issue = "50297")]
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
+#![doc(test(attr(deny(warnings))))]
#![cfg_attr(unix, feature(libc))]
#![feature(rustc_private)]
#![feature(nll)]
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: true,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::Yes,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage("error message"),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::YesWithMessage(expected),
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type,
},
testfn: DynTestFn(Box::new(f)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type,
}
}
ignore: false,
should_panic: ShouldPanic::Yes,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(move || {})),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
},
testfn: DynTestFn(Box::new(testfn)),
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
ignore: false,
should_panic: ShouldPanic::No,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: TestType::Unknown,
};
pub ignore: bool,
pub should_panic: options::ShouldPanic,
pub allow_fail: bool,
+ #[cfg(not(bootstrap))]
+ pub compile_fail: bool,
+ #[cfg(not(bootstrap))]
+ pub no_run: bool,
pub test_type: TestType,
}
}
}
}
+
+ /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test.
+ /// Descriptions include "should panic", "compile fail" and "compile".
+ #[cfg(not(bootstrap))]
+ pub fn test_mode(&self) -> Option<&'static str> {
+ if self.ignore {
+ return None;
+ }
+ match self.should_panic {
+ options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => {
+ return Some("should panic");
+ }
+ options::ShouldPanic::No => {}
+ }
+ if self.allow_fail {
+ return Some("allow fail");
+ }
+ if self.compile_fail {
+ return Some("compile fail");
+ }
+ if self.no_run {
+ return Some("compile");
+ }
+ None
+ }
+
+ #[cfg(bootstrap)]
+ pub fn test_mode(&self) -> Option<&'static str> {
+ None
+ }
}
#[derive(Debug)]
// linking for Linux is handled in lib.rs
if target.contains("musl") {
llvm_libunwind::compile();
+ } else if target.contains("android") {
+ let build = cc::Build::new();
+
+ // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+ // check if we have `libunwind` available and if so use it. Otherwise
+ // fall back to `libgcc` to support older ndk versions.
+ let has_unwind =
+ build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+
+ if has_unwind {
+ println!("cargo:rustc-link-lib=unwind");
+ } else {
+ println!("cargo:rustc-link-lib=gcc");
+ }
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
cmd.arg("-C").arg("target-feature=-crt-static");
}
}
+
+ if stage == "0" {
+ // Cargo doesn't pass RUSTFLAGS to proc_macros:
+ // https://github.com/rust-lang/cargo/issues/4423
+ // Set `--cfg=bootstrap` explicitly instead.
+ cmd.arg("--cfg=bootstrap");
+ }
}
if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
rev_parse = ["git", "rev-parse", "--show-toplevel"]
top_level = subprocess.check_output(rev_parse, universal_newlines=True).strip()
compiler = "{}/compiler/".format(top_level)
+ library = "{}/library/".format(top_level)
# Look for a version to compare to based on the current commit.
# Only commits merged by bors will have CI artifacts.
merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"]
commit = subprocess.check_output(merge_base, universal_newlines=True).strip()
- # Warn if there were changes to the compiler since the ancestor commit.
- status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler])
+ # Warn if there were changes to the compiler or standard library since the ancestor commit.
+ status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library])
if status != 0:
if download_rustc == "if-unchanged":
return None
- print("warning: `download-rustc` is enabled, but there are changes to compiler/")
+ print("warning: `download-rustc` is enabled, but there are changes to \
+ compiler/ or library/")
if self.verbose:
print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
}
+ /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable.
+ pub fn doc_rust_lang_org_channel(&self) -> String {
+ let channel = match &*self.config.channel {
+ "stable" => &self.version,
+ "beta" => "beta",
+ "nightly" | "dev" => "nightly",
+ // custom build of rustdoc maybe? link to the latest stable docs just in case
+ _ => "stable",
+ };
+ "https://doc.rust-lang.org/".to_owned() + channel
+ }
+
fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
StepDescription::run(v, self, paths);
}
if builder.no_std(target) == Some(true) {
let mut features = "compiler-builtins-mem".to_string();
- features.push_str(compiler_builtins_c_feature);
+ if !target.starts_with("bpf") {
+ features.push_str(compiler_builtins_c_feature);
+ }
// for no-std targets we only compile a few no_std crates
cargo
if target.contains("riscv") {
cargo.rustflag("-Cforce-unwind-tables=yes");
}
+
+ let html_root =
+ format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);
+ cargo.rustflag(&html_root);
+ cargo.rustdocflag(&html_root);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
cargo
.env("CFG_RELEASE", builder.rust_release())
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
- .env("CFG_VERSION", builder.rust_version())
- .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default());
+ .env("CFG_VERSION", builder.rust_version());
let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
build.verbose("finding compilers");
cc_detect::find(&mut build);
- build.verbose("running sanity check");
- sanity::check(&mut build);
+ // When running `setup`, the profile is about to change, so any requirements we have now may
+ // be different on the next invocation. Don't check for them until the next time x.py is
+ // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
+ if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
+ build.verbose("running sanity check");
+ sanity::check(&mut build);
+ }
// If local-rust is the same major.minor as the current version, then force a
// local-rebuild
eprintln!(
"
Couldn't find required command: ninja
-You should install ninja, or set ninja=false in config.toml
+You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section.
"
);
std::process::exit(1);
let llvm_targets = match &builder.config.llvm_targets {
Some(s) => s,
None => {
- "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
+ "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
Sparc;SystemZ;WebAssembly;X86"
}
};
}
}
cmd.env("RUSTC_BOOTSTRAP", "1");
+ cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
builder.add_rust_test_threads(&mut cmd);
if builder.config.sanitizers_enabled(target) {
cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
cargo.env("CFG_VERSION", builder.rust_version());
cargo.env("CFG_RELEASE_NUM", &builder.version);
+ cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
let info = GitInfo::new(builder.config.ignore_git, &dir);
if let Some(sha) = info.sha() {
|| target.contains("wasm32")
|| target.contains("nvptx")
|| target.contains("fortanix")
- || target.contains("fuchsia"))
+ || target.contains("fuchsia")
+ || target.contains("bpf"))
}
* `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated.
* `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind
- tables are required by the target or `-C panic=unwind`, an error will be
- emitted.
+ tables are required by the target an error will be emitted.
The default if not specified depends on the target.
* `ptx-linker`: use
[`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia
NVPTX GPGPU support.
+* `bpf-linker`: use
+ [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
* `wasm-ld`: use the [`wasm-ld`](https://lld.llvm.org/WebAssembly.html)
executable, a port of LLVM `lld` for WebAssembly.
* `ld64.lld`: use the LLVM `lld` executable with the [`-flavor darwin`
`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
`armv7s-apple-ios` | ✓ | |
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
+`bpfeb-unknown-none` | * | | BPF (big endian)
+`bpfel-unknown-none` | * | | BPF (little endian)
`hexagon-unknown-linux-musl` | ? | |
`i386-apple-ios` | ✓ | | 32-bit x86 iOS
`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
`lib.rs` to test your README as part of your doctests:
```rust,no_run
-#![feature(external_doc)]
-
-#[doc(include = "../README.md")]
+#[doc = include_str!("../README.md")]
#[cfg(doctest)]
pub struct ReadmeDoctests;
```
[unstable-masked]: ../unstable-book/language-features/doc-masked.html
[issue-masked]: https://github.com/rust-lang/rust/issues/44027
-### Include external files as API documentation
-
-As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
-is useful if certain documentation is so long that it would break the flow of reading the source.
-Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to
-instead read that file and use it as if it were written inline.
-
-[RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
-
-`#[doc(include = "...")]` currently requires the `#![feature(external_doc)]` feature gate. For more
-information, see [its chapter in the Unstable Book][unstable-include] and [its tracking
-issue][issue-include].
-
-[unstable-include]: ../unstable-book/language-features/external-doc.html
-[issue-include]: https://github.com/rust-lang/rust/issues/44732
-
## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
--- /dev/null
+# `force-warns`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
+++ /dev/null
-# `external_doc`
-
-The tracking issue for this feature is: [#44732]
-
-The `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to
-include external files in documentation. Use the attribute in place of, or in addition to, regular
-doc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders
-documentation for your crate.
-
-With the following files in the same directory:
-
-`external-doc.md`:
-
-```markdown
-# My Awesome Type
-
-This is the documentation for this spectacular type.
-```
-
-`lib.rs`:
-
-```no_run (needs-external-files)
-#![feature(external_doc)]
-
-#[doc(include = "external-doc.md")]
-pub struct MyAwesomeType;
-```
-
-`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`
-struct.
-
-When locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the
-`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,
-start your paths with `../docs/` for `rustdoc` to properly find the file.
-
-This feature was proposed in [RFC #1990] and initially implemented in PR [#44781].
-
-[#44732]: https://github.com/rust-lang/rust/issues/44732
-[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990
-[#44781]: https://github.com/rust-lang/rust/pull/44781
- Hexagon
- MIPS32r2 and MIPS64r2
- wasm32
+- BPF
## Basic usage
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
| PowerPC | `freg` | `f[0-31]` | `f` |
| wasm32 | `local` | None\* | `r` |
+| BPF | `reg` | `r[0-10]` | `r` |
+| BPF | `wreg` | `w[0-10]` | `w` |
> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
>
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
| PowerPC | `freg` | None | `f32`, `f64` |
| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
+| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
+| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
| Hexagon | `r29` | `sp` |
| Hexagon | `r30` | `fr` |
| Hexagon | `r31` | `lr` |
+| BPF | `r[0-10]` | `w[0-10]` |
Some registers cannot be used for input or output operands:
unichr = chr
+channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+
class CustomHTMLParser(HTMLParser):
"""simplified HTML parser.
def normalize_xpath(path):
+ path = path.replace("{{channel}}", channel)
if path.startswith('//'):
return '.' + path # avoid warnings
elif path.startswith('.//'):
def check_string(data, pat, regexp):
+ pat = pat.replace("{{channel}}", channel)
if not pat:
return True # special case a presence testing
elif regexp:
format!("{}/std/", s.trim_end_matches('/'))
}
Some(ExternalLocation::Unknown) | None => {
- "https://doc.rust-lang.org/nightly/std/".to_string()
+ format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
}
};
// This is a primitive so the url is done "by hand".
// #[doc(...)]
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
for item in list {
- // #[doc(include)]
+ // #[doc(hidden)]
if !item.has_name(sym::cfg) {
continue;
}
SugaredDoc,
/// A doc fragment created from a "raw" `#[doc=""]` attribute.
RawDoc,
- /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
- /// given filename and the file contents.
- Include { filename: Symbol },
}
// The goal of this function is to apply the `DocFragment` transformations that are required when
where
T: IntoIterator<Item = &'a DocFragment>,
{
- let mut prev_kind: Option<DocFragmentKind> = None;
iter.into_iter().fold(String::new(), |mut acc, frag| {
- if !acc.is_empty()
- && prev_kind
- .take()
- .map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
- .unwrap_or(false)
- {
- acc.push('\n');
- }
add_doc_fragment(&mut acc, &frag);
- prev_kind = Some(frag.kind);
acc
})
}
self.other_attrs.lists(name)
}
- /// Reads a `MetaItem` from within an attribute, looks for whether it is a
- /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
- /// its expansion.
- crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
- mi.meta_item_list().and_then(|list| {
- for meta in list {
- if meta.has_name(sym::include) {
- // the actual compiled `#[doc(include="filename")]` gets expanded to
- // `#[doc(include(file="filename", contents="file contents")]` so we need to
- // look for that instead
- return meta.meta_item_list().and_then(|list| {
- let mut filename: Option<Symbol> = None;
- let mut contents: Option<Symbol> = None;
-
- for it in list {
- if it.has_name(sym::file) {
- if let Some(name) = it.value_str() {
- filename = Some(name);
- }
- } else if it.has_name(sym::contents) {
- if let Some(docs) = it.value_str() {
- contents = Some(docs);
- }
- }
- }
-
- if let (Some(filename), Some(contents)) = (filename, contents) {
- Some((filename, contents))
- } else {
- None
- }
- });
- }
- }
-
- None
- })
- }
-
crate fn has_doc_flag(&self, flag: Symbol) -> bool {
for attr in &self.other_attrs {
if !attr.has_name(sym::doc) {
let mut doc_strings: Vec<DocFragment> = vec![];
let mut doc_line = 0;
- fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
+ fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
if let Some(prev) = doc_strings.last_mut() {
- if matches!(prev.kind, DocFragmentKind::Include { .. })
- || prev.kind != frag.kind
- || prev.parent_module != frag.parent_module
- {
- // add a newline for extra padding between segments
- prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
- || prev.kind == DocFragmentKind::RawDoc
- } else {
- prev.need_backline = true;
- }
+ prev.need_backline = true;
}
}
indent: 0,
};
- update_need_backline(&mut doc_strings, &frag);
+ update_need_backline(&mut doc_strings);
doc_strings.push(frag);
None
} else {
- if attr.has_name(sym::doc) {
- if let Some(mi) = attr.meta() {
- if let Some((filename, contents)) = Attributes::extract_include(&mi) {
- let line = doc_line;
- doc_line += contents.as_str().lines().count();
- let frag = DocFragment {
- line,
- span: attr.span,
- doc: contents,
- kind: DocFragmentKind::Include { filename },
- parent_module,
- need_backline: false,
- indent: 0,
- };
- update_need_backline(&mut doc_strings, &frag);
- doc_strings.push(frag);
- }
- }
- }
Some(attr.clone())
}
};
let mut out = String::new();
add_doc_fragment(&mut out, &ori);
while let Some(new_frag) = iter.next() {
- if matches!(ori.kind, DocFragmentKind::Include { .. })
- || new_frag.kind != ori.kind
- || new_frag.parent_module != ori.parent_module
- {
+ if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
break;
}
add_doc_fragment(&mut out, &new_frag);
}
}
- crate fn as_str(&self) -> &'static str {
- use self::PrimitiveType::*;
- match *self {
- Isize => "isize",
- I8 => "i8",
- I16 => "i16",
- I32 => "i32",
- I64 => "i64",
- I128 => "i128",
- Usize => "usize",
- U8 => "u8",
- U16 => "u16",
- U32 => "u32",
- U64 => "u64",
- U128 => "u128",
- F32 => "f32",
- F64 => "f64",
- Str => "str",
- Bool => "bool",
- Char => "char",
- Array => "array",
- Slice => "slice",
- Tuple => "tuple",
- Unit => "unit",
- RawPointer => "pointer",
- Reference => "reference",
- Fn => "fn",
- Never => "never",
- }
- }
-
crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
}
})
}
- crate fn to_url_str(&self) -> &'static str {
- self.as_str()
- }
-
crate fn as_sym(&self) -> Symbol {
use PrimitiveType::*;
match self {
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
- MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
+ Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
auto_impls.into_iter().chain(blanket_impls)
}
+/// If `res` has a documentation page associated, store it in the cache.
+///
+/// This is later used by [`href()`] to determine the HTML link for the item.
+///
+/// [`href()`]: crate::html::format::href
crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
+ use DefKind::*;
debug!("register_res({:?})", res);
let (did, kind) = match res {
- Res::Def(DefKind::Fn, i) => (i, ItemType::Function),
- Res::Def(DefKind::TyAlias, i) => (i, ItemType::Typedef),
- Res::Def(DefKind::Enum, i) => (i, ItemType::Enum),
- Res::Def(DefKind::Trait, i) => (i, ItemType::Trait),
Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+ // associated items are documented, but on the page of their parent
(cx.tcx.parent(i).unwrap(), ItemType::Trait)
}
- Res::Def(DefKind::Struct, i) => (i, ItemType::Struct),
- Res::Def(DefKind::Union, i) => (i, ItemType::Union),
- Res::Def(DefKind::Mod, i) => (i, ItemType::Module),
- Res::Def(DefKind::ForeignTy, i) => (i, ItemType::ForeignType),
- Res::Def(DefKind::Const, i) => (i, ItemType::Constant),
- Res::Def(DefKind::Static, i) => (i, ItemType::Static),
Res::Def(DefKind::Variant, i) => {
+ // variant items are documented, but on the page of their parent
(cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
}
- Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
- MacroKind::Bang => (i, ItemType::Macro),
- MacroKind::Attr => (i, ItemType::ProcAttribute),
- MacroKind::Derive => (i, ItemType::ProcDerive),
- },
- Res::Def(DefKind::TraitAlias, i) => (i, ItemType::TraitAlias),
- Res::SelfTy(Some(def_id), _) => (def_id, ItemType::Trait),
- Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
- _ => return res.def_id(),
+ // Each of these have their own page.
+ Res::Def(
+ kind
+ @
+ (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
+ | Macro(..) | TraitAlias),
+ i,
+ ) => (i, kind.into()),
+ // This is part of a trait definition; document the trait.
+ Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait),
+ // This is an inherent impl; it doesn't have its own page.
+ Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id,
+ Res::SelfTy(None, None)
+ | Res::PrimTy(_)
+ | Res::ToolMod
+ | Res::SelfCtor(_)
+ | Res::Local(_)
+ | Res::NonMacroAttr(_)
+ | Res::Err => return res.def_id(),
+ Res::Def(
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
+ | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ id,
+ ) => return id,
};
if did.is_local() {
return did;
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
})
}
+
+/// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links
+/// so that the channel is consistent.
+///
+/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
+crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
let generate_redirect_map = matches.opt_present("generate-redirect-map");
let show_type_layout = matches.opt_present("show-type-layout");
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+ let (lint_opts, describe_lints, lint_cap, _) =
+ get_cmd_lint_options(matches, error_format, &debugging_opts);
Ok(Options {
input,
// By default, rustdoc ignores all lints.
// Specifically unblock lints relevant to documentation or the lint machinery itself.
let mut lints_to_show = vec![
- // it's unclear whether this should be part of rustdoc directly (#77364)
+ // it's unclear whether these should be part of rustdoc directly (#77364)
rustc_lint::builtin::MISSING_DOCS.name.to_string(),
+ rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(),
// these are definitely not part of rustdoc, but we want to warn on them anyway.
rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
- let help = "The following guide may be of use:\n\
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
+ let help = format!(
+ "The following guide may be of use:\n\
+ {}/rustdoc/how-to-write-documentation.html",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
tcx.struct_lint_node(
crate::lint::MISSING_CRATE_LEVEL_DOCS,
DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
|lint| {
let mut diag =
lint.build("no documentation found for this crate's top-level module");
- diag.help(help);
+ diag.help(&help);
diag.emit();
},
);
let target = self.options.target.clone();
let target_str = target.to_string();
let unused_externs = self.unused_extern_reports.clone();
+ let no_run = config.no_run || options.no_run;
if !config.compile_fail {
self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
}
// compiler failures are test failures
should_panic: testing::ShouldPanic::No,
allow_fail: config.allow_fail,
+ #[cfg(not(bootstrap))]
+ compile_fail: config.compile_fail,
+ #[cfg(not(bootstrap))]
+ no_run,
test_type: testing::TestType::DocTest,
},
testfn: testing::DynTestFn(box move || {
let report_unused_externs = |uext| {
unused_externs.lock().unwrap().push(uext);
};
- let no_run = config.no_run || options.no_run;
let res = run_test(
&test,
&cratename,
f,
"<a class=\"primitive\" href=\"{}primitive.{}.html\">",
"../".repeat(len),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
f,
"<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
loc.join("/"),
- prim.to_url_str()
+ prim.as_sym()
)?;
needs_termination = true;
}
fmt::Display::fmt(&tybounds(param_names, cx), f)
}
clean::Infer => write!(f, "_"),
- clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cx),
+ clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
clean::BareFunction(ref decl) => {
if f.alternate() {
write!(
{sidebar}\
</nav>\
<div class=\"theme-picker\">\
- <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
+ <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
<img src=\"{static_root_path}brush{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Pick another theme!\">\
placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
type=\"search\">\
</div>\
- <button type=\"button\" id=\"help-button\">?</button>
- <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+ <button type=\"button\" id=\"help-button\" title=\"help\">?</button>\
+ <a id=\"settings-menu\" href=\"{root_path}settings.html\" title=\"settings\">\
<img src=\"{static_root_path}wheel{suffix}.svg\" \
width=\"18\" height=\"18\" \
alt=\"Change settings\">\
}
},
title = page.title,
- description = page.description,
+ description = Escape(page.description),
keywords = page.keywords,
favicon = if layout.favicon.is_empty() {
format!(
if !e.is_empty() {
let mut e: Vec<&ItemEntry> = e.iter().collect();
e.sort();
- write!(f, "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", title, title, class);
+ write!(
+ f,
+ "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">",
+ title.replace(' ', "-"), // IDs cannot contain whitespaces.
+ title,
+ class
+ );
for s in e.iter() {
write!(f, "<li>{}</li>", s.print());
</h1>",
);
// Note: print_entries does not escape the title, because we know the current set of titles
- // don't require escaping.
+ // doesn't require escaping.
print_entries(f, &self.structs, "Structs", "structs");
print_entries(f, &self.enums, "Enums", "enums");
print_entries(f, &self.unions, "Unions", "unions");
write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap());
write!(
buf,
- "<button id=\"copy-path\" onclick=\"copy_path(this)\">\
+ "<button id=\"copy-path\" onclick=\"copy_path(this)\" title=\"copy path\">\
<img src=\"{static_root_path}clipboard{suffix}.svg\" \
width=\"19\" height=\"18\" \
alt=\"Copy item import\" \
.search-results .result-name > span {
display: inline-block;
+ margin: 0;
+ font-weight: normal;
}
body.blur > :not(#help) {
.unwrap_or_default(),
},
Generic(s) => Type::Generic(s.to_string()),
- Primitive(p) => Type::Primitive(p.as_str().to_string()),
+ Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
use rustc_session::getopts;
use rustc_session::{early_error, early_warn};
+use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+
/// A macro to create a FxHashMap.
///
/// Example:
"LEVEL",
)
}),
+ unstable("force-warns", |o| {
+ o.optopt(
+ "",
+ "force-warns",
+ "Lints that will warn even if allowed somewhere else",
+ "LINTS",
+ )
+ }),
unstable("index-page", |o| {
o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
}),
}
println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
println!(" @path Read newline separated options from `path`\n");
- println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
+ println!(
+ "More information available at {}/rustdoc/what-is-rustdoc.html",
+ DOC_RUST_LANG_ORG_CHANNEL
+ );
}
/// A result type used by several functions under `main()`.
}
}
- fn name(self, tcx: TyCtxt<'_>) -> String {
+ fn name(self, tcx: TyCtxt<'_>) -> Symbol {
match self {
- Res::Def(_, id) => tcx.item_name(id).to_string(),
- Res::Primitive(prim) => prim.as_str().to_string(),
+ Res::Def(_, id) => tcx.item_name(id),
+ Res::Primitive(prim) => prim.as_sym(),
}
}
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
- let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
+ let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
})
})
AnchorFailure::RustdocAnchorConflict(res),
));
}
- return Ok((res, Some(ty.as_str().to_owned())));
+ return Ok((res, Some(ty.as_sym().to_string())));
}
_ => return Ok((res, extra_fragment.clone())),
}
return None;
}
res = prim;
- fragment = Some(prim.name(self.cx.tcx));
+ fragment = Some(prim.name(self.cx.tcx).to_string());
} else {
// `[char]` when a `char` module is in scope
let candidates = vec![res, prim];
) {
diag_info.link_range = disambiguator_range;
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
- let msg = "see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators";
- diag.note(msg);
+ let msg = format!(
+ "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
+ crate::DOC_RUST_LANG_ORG_CHANNEL
+ );
+ diag.note(&msg);
});
}
-Subproject commit 5f67a5715771b7d29e4713e8d68338602d216dcf
+Subproject commit 39c5555872cc5d379cc3535a31dc0cdac969466f
--- /dev/null
+// min-llvm-version: 10.0.1
+// assembly-output: emit-asm
+// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
+// needs-llvm-components: bpf
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+ () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const u64;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+ ($func:ident $ty:ident $class:ident) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!("{} = {}", out($class) y, in($class) x);
+ y
+ }
+ };
+}
+
+macro_rules! check_reg {
+ ($func:ident $ty:ident $reg:tt) => {
+ #[no_mangle]
+ pub unsafe fn $func(x: $ty) -> $ty {
+ let y;
+ asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x);
+ y
+ }
+ };
+}
+
+extern "C" {
+ fn extern_func();
+}
+
+// CHECK-LABEL: sym_fn
+// CHECK: #APP
+// CHECK: call extern_func
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+ asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i16 i16 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i64:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i64 i64 reg);
+
+// CHECK-LABEL: wreg_i8:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i8 i8 wreg);
+
+// CHECK-LABEL: wreg_i16:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i16 i16 wreg);
+
+// CHECK-LABEL: wreg_i32:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i32 i32 wreg);
+
+// CHECK-LABEL: r0_i8:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i8 i8 "r0");
+
+// CHECK-LABEL: r0_i16:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i16 i16 "r0");
+
+// CHECK-LABEL: r0_i32:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i32 i32 "r0");
+
+// CHECK-LABEL: r0_i64:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i64 i64 "r0");
+
+// CHECK-LABEL: w0_i8:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i8 i8 "w0");
+
+// CHECK-LABEL: w0_i16:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i16 i16 "w0");
+
+// CHECK-LABEL: w0_i32:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i32 i32 "w0");
--- /dev/null
+// only-bpf
+#![crate_type = "lib"]
+#![feature(bpf_target_feature)]
+#![no_std]
+
+#[no_mangle]
+#[target_feature(enable = "alu32")]
+// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 {
+pub unsafe fn foo(arg: u8) -> u8 {
+ arg
+}
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
-+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
- // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + val: Unevaluated(FOO, [], None)
// mir::Constant
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
_1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref.rs:5:6: 5:10
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref.rs:5:6: 5:10
-+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
_1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/ref_deref_project.rs:5:6: 5:17
- // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
+ // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19
- // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
// + val: Unevaluated(bar, [], Some(promoted[1]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:7: 12:9
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
_4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
// + val: Unevaluated(bar, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/inline-retag.rs:12:11: 12:14
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
_7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + val: Unevaluated(discriminant, [T], Some(promoted[2]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:70:42: 70:44
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
- _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45
// + val: Unevaluated(discriminant, [T], Some(promoted[1]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:71:42: 71:45
- // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
+ // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
- _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46
// + val: Unevaluated(discriminant, [T], Some(promoted[0]))
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:72:42: 72:47
- // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
- _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48
// + val: Unevaluated(full_tested_match, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/match_false_edges.rs:16:14: 16:15
- // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[4011]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
_6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
_4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
// + val: Unevaluated(array_casts, [], Some(promoted[0]))
// mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[13e7]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[317d]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6
_14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6
// closure
- // + def_id: DefId(0:14 ~ retag[13e7]::main::{closure#0})
+ // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0})
// + substs: [
// i8,
// for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
// + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant
// + span: $DIR/retag.rs:47:21: 47:23
- // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[13e7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
_23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23
Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23
12| 1| if b {
13| 1| println!("non_async_func println in block");
14| 1| }
+ ^0
15| 1|}
16| |
17| |
5| 1| if true {
6| 1| countdown = 10;
7| 1| }
+ ^0
8| |
9| | const B: u32 = 100;
10| 1| let x = if countdown > 7 {
24| 1| if true {
25| 1| countdown = 10;
26| 1| }
+ ^0
27| |
28| 1| if countdown > 7 {
29| 1| countdown -= 4;
41| 1| if true {
42| 1| countdown = 10;
43| 1| }
+ ^0
44| |
45| 1| if countdown > 7 {
46| 1| countdown -= 4;
53| | } else {
54| 0| return;
55| | }
- 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ 56| 0| }
+ 57| |
58| |
59| 1| let mut countdown = 0;
60| 1| if true {
61| 1| countdown = 1;
62| 1| }
+ ^0
63| |
64| 1| let z = if countdown > 7 {
^0
8| 1|//! assert_eq!(1, 1);
9| |//! } else {
10| |//! // this is not!
- 11| |//! assert_eq!(1, 2);
+ 11| 0|//! assert_eq!(1, 2);
12| |//! }
13| 1|//! ```
14| |//!
74| 1| if true {
75| 1| assert_eq!(1, 1);
76| | } else {
- 77| | assert_eq!(1, 2);
+ 77| 0| assert_eq!(1, 2);
78| | }
79| 1|}
80| |
19| 1| if true {
20| 1| println!("Exiting with error...");
21| 1| return Err(1);
- 22| | }
- 23| |
- 24| | let _ = Firework { strength: 1000 };
- 25| |
- 26| | Ok(())
+ 22| 0| }
+ 23| 0|
+ 24| 0| let _ = Firework { strength: 1000 };
+ 25| 0|
+ 26| 0| Ok(())
27| 1|}
28| |
29| |// Expected program output:
--- /dev/null
+ 1| |#![feature(generators, generator_trait)]
+ 2| |
+ 3| |use std::ops::{Generator, GeneratorState};
+ 4| |use std::pin::Pin;
+ 5| |
+ 6| |// The following implementation of a function called from a `yield` statement
+ 7| |// (apparently requiring the Result and the `String` type or constructor)
+ 8| |// creates conditions where the `generator::StateTransform` MIR transform will
+ 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+ 10| |// to handle this condition, and still report dead block coverage.
+ 11| 1|fn get_u32(val: bool) -> Result<u32, String> {
+ 12| 1| if val { Ok(1) } else { Err(String::from("some error")) }
+ ^0
+ 13| 1|}
+ 14| |
+ 15| 1|fn main() {
+ 16| 1| let is_true = std::env::args().len() == 1;
+ 17| 1| let mut generator = || {
+ 18| 1| yield get_u32(is_true);
+ 19| 1| return "foo";
+ 20| 1| };
+ 21| |
+ 22| 1| match Pin::new(&mut generator).resume(()) {
+ 23| 1| GeneratorState::Yielded(Ok(1)) => {}
+ 24| 0| _ => panic!("unexpected return from resume"),
+ 25| | }
+ 26| 1| match Pin::new(&mut generator).resume(()) {
+ 27| 1| GeneratorState::Complete("foo") => {}
+ 28| 0| _ => panic!("unexpected return from resume"),
+ 29| | }
+ 30| 1|}
+
30| 1| if true {
31| 1| println!("Exiting with error...");
32| 1| return Err(1);
- 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal
- 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- 36| | // in other tests, the lines below would have coverage (which would show they had `0`
- 37| | // executions, assuming the condition still evaluated to `true`).
- 38| |
- 39| | let _ = Firework { strength: 1000 };
- 40| |
- 41| | Ok(())
+ 33| 0| }
+ 34| 0|
+ 35| 0|
+ 36| 0|
+ 37| 0|
+ 38| 0|
+ 39| 0| let _ = Firework { strength: 1000 };
+ 40| 0|
+ 41| 0| Ok(())
42| 1|}
43| |
44| |// Expected program output:
9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
10| 1| if true {
11| 1| if false {
- 12| | while true {
- 13| | }
+ 12| 0| while true {
+ 13| 0| }
14| 1| }
- 15| 1| write!(f, "error")?;
- ^0
- 16| | } else {
- 17| | }
+ 15| 1| write!(f, "cool")?;
+ ^0
+ 16| 0| } else {
+ 17| 0| }
18| |
19| 10| for i in 0..10 {
20| 10| if true {
21| 10| if false {
- 22| | while true {}
+ 22| 0| while true {}
23| 10| }
- 24| 10| write!(f, "error")?;
- ^0
- 25| | } else {
- 26| | }
+ 24| 10| write!(f, "cool")?;
+ ^0
+ 25| 0| } else {
+ 26| 0| }
27| | }
28| 1| Ok(())
29| 1| }
34| |impl std::fmt::Display for DisplayTest {
35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36| 1| if false {
- 37| | } else {
+ 37| 0| } else {
38| 1| if false {
- 39| | while true {}
+ 39| 0| while true {}
40| 1| }
- 41| 1| write!(f, "error")?;
- ^0
+ 41| 1| write!(f, "cool")?;
+ ^0
42| | }
43| 10| for i in 0..10 {
44| 10| if false {
- 45| | } else {
+ 45| 0| } else {
46| 10| if false {
- 47| | while true {}
+ 47| 0| while true {}
48| 10| }
- 49| 10| write!(f, "error")?;
- ^0
+ 49| 10| write!(f, "cool")?;
+ ^0
50| | }
51| | }
52| 1| Ok(())
1| 1|fn main() {
2| 1| if false {
- 3| | loop {}
+ 3| 0| loop {}
4| 1| }
5| 1|}
} else {
return;
}
- } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
- // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+ }
+
let mut countdown = 0;
if true {
--- /dev/null
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `generator::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+ if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+ let is_true = std::env::args().len() == 1;
+ let mut generator = || {
+ yield get_u32(is_true);
+ return "foo";
+ };
+
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Yielded(Ok(1)) => {}
+ _ => panic!("unexpected return from resume"),
+ }
+ match Pin::new(&mut generator).resume(()) {
+ GeneratorState::Complete("foo") => {}
+ _ => panic!("unexpected return from resume"),
+ }
+}
if true {
println!("Exiting with error...");
return Err(1);
- } // The remaining lines below have no coverage because `if true` (with the constant literal
- // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
- // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
- // in other tests, the lines below would have coverage (which would show they had `0`
- // executions, assuming the condition still evaluated to `true`).
+ }
+
+
+
+
let _ = Firework { strength: 1000 };
while true {
}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
} else {
}
}
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
for i in 0..10 {
if false {
if false {
while true {}
}
- write!(f, "error")?;
+ write!(f, "cool")?;
}
}
Ok(())
#![feature(rustc_private)]
+#![deny(warnings)]
extern crate rustc_codegen_ssa;
extern crate rustc_errors;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::MetadataRef;
use rustc_errors::ErrorReported;
-use rustc_middle::dep_graph::DepGraph;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;
-use rustc_target::spec::Target;
use std::any::Any;
-use std::path::Path;
struct TheBackend;
impl CodegenBackend for TheBackend {
- fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
- Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
- }
-
- fn provide(&self, providers: &mut Providers) {}
- fn provide_extern(&self, providers: &mut Providers) {}
-
fn codegen_crate<'a, 'tcx>(
&self,
tcx: TyCtxt<'tcx>,
metadata: EncodedMetadata,
_need_metadata_module: bool,
) -> Box<dyn Any> {
- use rustc_hir::def_id::LOCAL_CRATE;
-
Box::new(CodegenResults {
- crate_name: tcx.crate_name(LOCAL_CRATE),
modules: vec![],
allocator_module: None,
metadata_module: None,
metadata,
- windows_subsystem: None,
linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
crate_info: CrateInfo::new(tcx),
})
) -> Result<(), ErrorReported> {
use rustc_session::{config::CrateType, output::out_filename};
use std::io::Write;
- let crate_name = codegen_results.crate_name;
+ let crate_name = codegen_results.crate_info.local_crate_name;
for &crate_type in sess.opts.crate_types.iter() {
if crate_type != CrateType::Rlib {
sess.fatal(&format!("Crate type is {:?}", crate_type));
-#![feature(external_doc)]
-
-#[doc(include="input.md")]
+#[doc = include_str!("input.md")]
pub struct SomeStruct;
pub fn main() {
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(associated_type_defaults)]
-#![feature(external_doc)]
extern crate rustc_graphviz;
// A simple rust project
}
}
+#[doc = include_str!("extra-docs.md")]
+struct StructWithDocs;
+
trait Foo {
type Bar = FrameBuffer;
}
-
-#[doc(include = "extra-docs.md")]
-struct StructWithDocs;
--- /dev/null
+# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
+
+# only-windows
+# only-msvc
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
+ $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+ $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
+ $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+ $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+ $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+ "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/output.txt output.txt
+else
+ $(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
--- /dev/null
+extern crate raw_dylib_test;
+
+fn main() {
+ raw_dylib_test::library_function();
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_1() {
+ printf("extern_fn_1\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_2() {
+ printf("extern_fn_2; didn't get the rename\n");
+ fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_with_long_name() {
+ printf("extern_fn_with_long_name; got the rename\n");
+ fflush(stdout);
+}
--- /dev/null
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_3() {
+ printf("extern_fn_3\n");
+ fflush(stdout);
+}
--- /dev/null
+#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
+
+#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
+extern {
+ fn extern_fn_1();
+}
+
+#[link(name = "extern_2", kind = "raw-dylib")]
+extern {
+ fn extern_fn_3();
+}
+
+pub fn library_function() {
+ #[link(name = "extern_1", kind = "raw-dylib")]
+ extern { fn extern_fn_2(); }
+
+ unsafe {
+ extern_fn_1();
+ extern_fn_2();
+ extern_fn_3();
+ }
+}
--- /dev/null
+extern_fn_1
+extern_fn_2; didn't get the rename
+extern_fn_3
all:
$(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
+ $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
--- /dev/null
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
+
// check-pass
// compile-flags: -Z unstable-options --check
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![warn(missing_docs)]
//~^ WARN
warning: missing documentation for the crate
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:4:9
+ --> $DIR/check.rs:5:9
|
LL | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: missing documentation for a function
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^
warning: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
warning: missing code example in this documentation
- --> $DIR/check.rs:4:1
+ --> $DIR/check.rs:5:1
|
LL | / #![warn(missing_docs)]
LL | |
| |_______________^
|
note: the lint level is defined here
- --> $DIR/check.rs:7:9
+ --> $DIR/check.rs:8:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
warning: missing code example in this documentation
- --> $DIR/check.rs:9:1
+ --> $DIR/check.rs:10:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
--- /dev/null
+// check-pass
+
+#[doc(include = "external-cross-doc.md")]
+//~^ WARNING unknown `doc` attribute `include`
+//~| HELP use `doc = include_str!` instead
+// FIXME(#85497): make this a deny instead so it's more clear what's happening
+//~| NOTE on by default
+//~| WARNING previously accepted
+//~| NOTE see issue #82730
+pub struct NeedMoreDocs;
--- /dev/null
+warning: unknown `doc` attribute `include`
+ --> $DIR/doc-include-suggestion.rs:3:7
+ |
+LL | #[doc(include = "external-cross-doc.md")]
+ | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
+ |
+ = note: `#[warn(invalid_doc_attributes)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+warning: 1 warning emitted
+
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(notable_trait)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-// check-pass
// run-rustfix
-
+#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(spotlight)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}
-warning: unknown `doc` attribute `spotlight`
- --> $DIR/doc-spotlight.rs:6:7
+error: unknown `doc` attribute `spotlight`
+ --> $DIR/doc-spotlight.rs:5:7
|
LL | #[doc(spotlight)]
| ^^^^^^^^^ help: use `notable_trait` instead
|
- = note: `#[warn(invalid_doc_attributes)]` on by default
+note: the lint level is defined here
+ --> $DIR/doc-spotlight.rs:2:9
+ |
+LL | #![deny(warnings)]
+ | ^^^^^^^^
+ = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
-warning: 1 warning emitted
+error: aborting due to previous error
running 1 test
-test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED
failures:
running 1 test
-test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED
failures:
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Email me at <hello@localhost>.
error: unknown disambiguator `hello`
- --> $DIR/email-address-localhost.rs:3:18
+ --> $DIR/email-address-localhost.rs:4:18
|
LL | //! Email me at <hello@localhost>.
| ^^^^^
|
note: the lint level is defined here
- --> $DIR/email-address-localhost.rs:1:9
+ --> $DIR/email-address-localhost.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to previous error
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(warnings)]
//! Linking to [foo@banana] and [`bar@banana!()`].
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:3:17
+ --> $DIR/unknown-disambiguator.rs:4:17
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
note: the lint level is defined here
- --> $DIR/unknown-disambiguator.rs:1:9
+ --> $DIR/unknown-disambiguator.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `bar`
- --> $DIR/unknown-disambiguator.rs:3:35
+ --> $DIR/unknown-disambiguator.rs:4:35
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:34
+ --> $DIR/unknown-disambiguator.rs:10:34
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
- --> $DIR/unknown-disambiguator.rs:9:48
+ --> $DIR/unknown-disambiguator.rs:10:48
|
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:31
+ --> $DIR/unknown-disambiguator.rs:7:31
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
- --> $DIR/unknown-disambiguator.rs:6:57
+ --> $DIR/unknown-disambiguator.rs:7:57
|
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to 6 previous errors
running 1 test
-test $DIR/issue-80992.rs - test (line 7) ... ok
+test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
// error-pattern: no documentation found
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
#![deny(rustdoc::missing_crate_level_docs)]
//^~ NOTE defined here
error: no documentation found for this crate's top-level module
|
note: the lint level is defined here
- --> $DIR/no-crate-level-doc-lint.rs:2:9
+ --> $DIR/no-crate-level-doc-lint.rs:3:9
|
LL | #![deny(rustdoc::missing_crate_level_docs)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: The following guide may be of use:
- https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+ https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
error: aborting due to previous error
running 7 tests
-test $DIR/no-run-flag.rs - f (line 11) ... ok
+test $DIR/no-run-flag.rs - f (line 11) - compile ... ok
test $DIR/no-run-flag.rs - f (line 14) ... ignored
-test $DIR/no-run-flag.rs - f (line 17) ... ok
-test $DIR/no-run-flag.rs - f (line 23) ... ok
-test $DIR/no-run-flag.rs - f (line 28) ... ok
-test $DIR/no-run-flag.rs - f (line 32) ... ok
-test $DIR/no-run-flag.rs - f (line 8) ... ok
+test $DIR/no-run-flag.rs - f (line 17) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok
+test $DIR/no-run-flag.rs - f (line 28) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 32) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 8) - compile ... ok
test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
--- /dev/null
+// compile-flags: --test --test-args=--test-threads=1
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+/// println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+
+pub fn f() {}
--- /dev/null
+
+running 5 tests
+test $DIR/test-type.rs - f (line 12) ... ignored
+test $DIR/test-type.rs - f (line 15) - compile ... ok
+test $DIR/test-type.rs - f (line 21) - compile fail ... ok
+test $DIR/test-type.rs - f (line 6) ... ok
+test $DIR/test-type.rs - f (line 9) ... ok
+
+test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
# Cross-crate imported docs
-This file is to make sure `#[doc(include="file.md")]` works when you re-export an item with included
+This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included
docs.
-#![feature(external_doc)]
-#![deny(missing_doc)]
-
-#[doc(include="external-cross-doc.md")]
+#[deny(missing_docs)]
+#[doc = include_str!("external-cross-doc.md")]
pub struct NeedMoreDocs;
# External Docs
-This file is here to test the `#[doc(include="file")]` attribute.
+This file is here to test the `#[doc = include_str!("file")]` attribute.
-#![feature(external_doc)]
-
-// @has external_doc/struct.CanHasDocs.html
-// @has - '//h1' 'External Docs'
-// @has - '//h2' 'Inline Docs'
-#[doc(include = "auxiliary/external-doc.md")]
-/// ## Inline Docs
-pub struct CanHasDocs;
-
// @has external_doc/struct.IncludeStrDocs.html
// @has - '//h1' 'External Docs'
// @has - '//h2' 'Inline Docs'
/// [`std::collections::BTreeMap::into_iter`]
/// [`String::from`] is ambiguous as to which `From` impl
/// [Vec::into_iter()] uses a disambiguator
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
pub fn foo() {}
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
// @has builtin_macros/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html'
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
//! [cfg]
--- /dev/null
+// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
//! Here's a link to [`Iterator<Box<T>>::Item`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
//! And [`Result<T, !>`] and [`Result<!, E>`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
//! This is also pretty tricky: [`TypeId::of::<String>()`].
//! And this too: [`Vec::<std::error::Error>::len`].
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
//! [`Box::<T>new()`]. We may not support them in the future!
//!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
//! These will be resolved as regular links:
//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
#![feature(intra_doc_pointers)]
#![deny(rustdoc::broken_intra_doc_links)]
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
//! [slice::rotate_left]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
//! [array::map]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'owned str'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str ref'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.len"]' '&str::len'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
//! [owned str][str]
//! [str ref][&str]
//! [str::is_empty]
//! [&str::len]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
//! [pointer::is_null]
//! [*const::is_null]
//! [*mut::is_null]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
//! [unit]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
//! [tuple]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
//! [reference]
//! [&]
//! [&mut]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
//! [fn]
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
//! [never]
//! [!]
#![deny(broken_intra_doc_links)]
//! [i32::MAX]
-// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
#![crate_type = "rlib"]
// @has prim_methods_external_core/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods_local/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
// @has prim_methods/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
//! A [`char`] and its [`char::len_utf8`].
pub mod char {
/// [char]
- // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+ // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct Inner;
}
/// See [prim@char]
-// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
pub struct MyString;
/// See also [crate::char] and [mod@char]
#![deny(broken_intra_doc_links)]
// @has primitive_disambiguators/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim'
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
//! [str::trim()]
// @has primitive_non_default_impl/fn.str_methods.html
/// [`str::trim`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
/// [`str::to_lowercase`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
/// [`str::into_boxed_bytes`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
/// [`str::replace`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
pub fn str_methods() {}
// @has primitive_non_default_impl/fn.f32_methods.html
/// [f32::powi]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
/// [f32::sqrt]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
/// [f32::mul_add]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
pub fn f32_methods() {}
// @has primitive_non_default_impl/fn.f64_methods.html
/// [`f64::powi`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
/// [`f64::sqrt`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
/// [`f64::mul_add`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
pub fn f64_methods() {}
// documenting the re-export.
// @has outer/index.html
-// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
+// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
// @ has - '//a[@href="fn.f.html"]' "g"
pub use f as g;
// Make sure the documentation is actually correct by documenting an inlined re-export
/// [mod@std::env]
// @has outer/fn.f.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env"
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
pub use inner::f;
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
pub struct S;
impl S {
// @has foo/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
//! A `bool` is either [`true`] or [`false`].
-// ignore-tidy-linelength
#![deny(broken_intra_doc_links)]
#![feature(lang_items)]
#![feature(no_core)]
/// [Self::f]
/// [Self::MAX]
// @has intra_link_prim_self/primitive.usize.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.f"]' 'Self::f'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
impl usize {
/// Some docs
pub fn f() {}
pub const MAX: usize = 10;
// FIXME(#8995) uncomment this when associated types in inherent impls are supported
- // @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+ // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
// / [Self::ME]
//pub type ME = usize;
}
#![crate_name = "foo"]
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
/// It contains [`u32`] and [i64].
/// It also links to [std::primitive::i32], [std::primitive::str],
// @has bar/p/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub mod p {
pub use foo::bar::*;
}
// @has bar/baz/index.html
// @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
// @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
pub use foo::bar as baz;
// @has bar/index.html
// @has - '//code' 'pub use str;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str'
+// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str'
// @has - '//code' 'pub use i32 as my_i32;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'i32'
+// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32'
pub use str;
pub use i32 as my_i32;
-#![feature(external_doc)]
-
#![crate_name = "foo"]
// @has foo/struct.Example.html
// @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z'
///a
///no whitespace
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct J;
// @has foo/struct.K.html
///
/// 4 whitespaces!
///
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
pub struct K;
| has type `&mut VaListImpl<'1>`
LL | ap0 = &mut ap1;
| ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+ |
+ = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/variadic-ffi-4.rs:28:5
| has type `&mut VaListImpl<'1>`
LL | ap0 = &mut ap1;
| ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
+ |
+ = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error[E0597]: `ap1` does not live long enough
--> $DIR/variadic-ffi-4.rs:28:11
};
pub fn yes_iterator() -> impl Iterator<Item = i32> {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_fused_iterator() -> impl FusedIterator {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_trusted_len() -> impl TrustedLen {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_clone() -> impl Clone {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
pub fn yes_debug() -> impl Debug {
- IntoIter::new([0i32; 32])
+ IntoIterator::into_iter([0i32; 32])
}
};
pub fn yes_iterator() -> impl Iterator<Item = i32> {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_fused_iterator() -> impl FusedIterator {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_trusted_len() -> impl TrustedLen {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_clone() -> impl Clone {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
pub fn yes_debug() -> impl Debug {
- IntoIter::new([0i32; 33])
+ IntoIterator::into_iter([0i32; 33])
}
--> $DIR/tls.rs:12:25
|
LL | unsafe { let _val = A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
error[E0080]: could not evaluate static initializer
--> $DIR/tls.rs:19:26
|
LL | unsafe { let _val = &A; }
- | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
+ | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
warning: skipping const checks
|
// the patterns are all fine:
(..) = x;
}
+
+ #[derive(Debug)]
+ #[deprecated(note = "Use something else instead")]
+ enum DeprecatedDebugEnum {
+ Variant1 { value: Option<String> },
+ }
+
+ #[allow(deprecated)]
+ impl DeprecatedDebugEnum {
+ fn new() -> Self {
+ DeprecatedDebugEnum::Variant1 { value: None }
+ }
+ }
+
+ #[allow(deprecated)]
+ pub fn allow_dep() {
+ let _ = DeprecatedDebugEnum::new();
+ }
}
fn main() {}
| ^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:21:16
+ --> $DIR/deprecation-lint.rs:21:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:23:25
+ --> $DIR/deprecation-lint.rs:23:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `deprecation_lint::deprecated_text`: text
--> $DIR/deprecation-lint.rs:25:9
| ^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:30:16
+ --> $DIR/deprecation-lint.rs:30:9
|
LL | ... Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:32:25
+ --> $DIR/deprecation-lint.rs:32:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `deprecation_lint::DeprecatedStruct`: text
--> $DIR/deprecation-lint.rs:34:17
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated variant `deprecation_lint::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:40:23
+ --> $DIR/deprecation-lint.rs:40:17
|
LL | let _ = Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `deprecation_lint::DeprecatedTupleStruct`: text
--> $DIR/deprecation-lint.rs:42:17
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `deprecation_lint::nested::DeprecatedStruct`: text
- --> $DIR/deprecation-lint.rs:44:25
+ --> $DIR/deprecation-lint.rs:44:17
|
LL | let _ = nested::DeprecatedStruct {
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `deprecation_lint::nested::DeprecatedUnitStruct`: text
- --> $DIR/deprecation-lint.rs:48:25
+ --> $DIR/deprecation-lint.rs:48:17
|
LL | let _ = nested::DeprecatedUnitStruct;
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated variant `deprecation_lint::nested::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:50:31
+ --> $DIR/deprecation-lint.rs:50:17
|
LL | ... let _ = nested::Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `deprecation_lint::nested::DeprecatedTupleStruct`: text
- --> $DIR/deprecation-lint.rs:52:25
+ --> $DIR/deprecation-lint.rs:52:17
|
LL | ... let _ = nested::DeprecatedTupleStruct (1);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `deprecation_lint::deprecated_text`: text
--> $DIR/deprecation-lint.rs:59:25
| ^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:65:16
+ --> $DIR/deprecation-lint.rs:65:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:67:25
+ --> $DIR/deprecation-lint.rs:67:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:69:16
+ --> $DIR/deprecation-lint.rs:69:9
|
LL | ... Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:71:25
+ --> $DIR/deprecation-lint.rs:71:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated trait `deprecation_lint::DeprecatedTrait`: text
--> $DIR/deprecation-lint.rs:81:10
| ^^^^^^^^^^^
error: use of deprecated function `deprecation_lint::deprecated_mod::deprecated`: text
- --> $DIR/deprecation-lint.rs:162:25
+ --> $DIR/deprecation-lint.rs:162:9
|
LL | deprecated_mod::deprecated();
- | ^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::deprecated`: text
--> $DIR/deprecation-lint.rs:245:9
| ^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:250:16
+ --> $DIR/deprecation-lint.rs:250:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:252:25
+ --> $DIR/deprecation-lint.rs:252:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::deprecated_text`: text
--> $DIR/deprecation-lint.rs:254:9
| ^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:259:16
+ --> $DIR/deprecation-lint.rs:259:9
|
LL | Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:261:25
+ --> $DIR/deprecation-lint.rs:261:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::deprecated_future`: text
--> $DIR/deprecation-lint.rs:264:9
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:274:23
+ --> $DIR/deprecation-lint.rs:274:17
|
LL | let _ = Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text
--> $DIR/deprecation-lint.rs:276:17
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated struct `this_crate::nested::DeprecatedStruct`: text
- --> $DIR/deprecation-lint.rs:278:25
+ --> $DIR/deprecation-lint.rs:278:17
|
LL | let _ = nested::DeprecatedStruct {
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
- --> $DIR/deprecation-lint.rs:283:25
+ --> $DIR/deprecation-lint.rs:283:17
|
LL | let _ = nested::DeprecatedUnitStruct;
- | ^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:285:31
+ --> $DIR/deprecation-lint.rs:285:17
|
LL | ... let _ = nested::Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text
- --> $DIR/deprecation-lint.rs:287:25
+ --> $DIR/deprecation-lint.rs:287:17
|
LL | ... let _ = nested::DeprecatedTupleStruct (1);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:292:16
+ --> $DIR/deprecation-lint.rs:292:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:294:25
+ --> $DIR/deprecation-lint.rs:294:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:296:16
+ --> $DIR/deprecation-lint.rs:296:9
|
LL | Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:298:25
+ --> $DIR/deprecation-lint.rs:298:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar`
--> $DIR/deprecation-lint.rs:316:13
// run-rustfix
#![feature(staged_api)]
+
#![stable(since = "1.0.0", feature = "test")]
+
#![deny(deprecated)]
#![allow(dead_code)]
fn replacement(&self) {}
}
-mod bar {
- #[rustc_deprecated(
- since = "1.0.0",
- reason = "replaced by `replacement`",
- suggestion = "replacement",
- )]
- #[stable(since = "1.0.0", feature = "test")]
- pub fn deprecated() {}
-
- pub fn replacement() {}
-}
-
fn main() {
let foo = Foo;
- foo.replacement(); //~ ERROR use of deprecated
- bar::replacement(); //~ ERROR use of deprecated
+ foo.replacement(); //~ ERROR use of deprecated
}
// run-rustfix
#![feature(staged_api)]
+
#![stable(since = "1.0.0", feature = "test")]
+
#![deny(deprecated)]
#![allow(dead_code)]
fn replacement(&self) {}
}
-mod bar {
- #[rustc_deprecated(
- since = "1.0.0",
- reason = "replaced by `replacement`",
- suggestion = "replacement",
- )]
- #[stable(since = "1.0.0", feature = "test")]
- pub fn deprecated() {}
-
- pub fn replacement() {}
-}
-
fn main() {
let foo = Foo;
- foo.deprecated(); //~ ERROR use of deprecated
- bar::deprecated(); //~ ERROR use of deprecated
+ foo.deprecated(); //~ ERROR use of deprecated
}
-error: use of deprecated function `bar::deprecated`: replaced by `replacement`
- --> $DIR/suggestion.rs:38:10
+error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
+ --> $DIR/suggestion.rs:27:9
|
-LL | bar::deprecated();
- | ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement`
+LL | foo.deprecated();
+ | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
|
note: the lint level is defined here
- --> $DIR/suggestion.rs:5:9
+ --> $DIR/suggestion.rs:7:9
|
LL | #![deny(deprecated)]
| ^^^^^^^^^^
-error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
- --> $DIR/suggestion.rs:36:9
- |
-LL | foo.deprecated();
- | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error: aborting due to 2 previous errors
+++ /dev/null
-// normalize-stderr-test: "not-a-file.md:.*\(" -> "not-a-file.md: $$FILE_NOT_FOUND_MSG ("
-
-#![feature(external_doc)]
-
-#[doc(include = "not-a-file.md")]
-pub struct SomeStruct; //~^ ERROR couldn't read
-
-#[doc(include = "auxiliary/invalid-utf8.txt")]
-pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
-
-#[doc(include)]
-pub struct MissingPath; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include("../README.md"))]
-pub struct InvalidPathSyntax; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "../README.md"
-
-#[doc(include = 123)]
-pub struct InvalidPathType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-#[doc(include(123))]
-pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path
- //~| HELP provide a file path with `=`
- //~| SUGGESTION include = "<path>"
-
-fn main() {}
+++ /dev/null
-error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
- --> $DIR/external-doc-error.rs:5:17
- |
-LL | #[doc(include = "not-a-file.md")]
- | ^^^^^^^^^^^^^^^ couldn't read file
-
-error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
- --> $DIR/external-doc-error.rs:8:17
- |
-LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:11:7
- |
-LL | #[doc(include)]
- | ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:16:7
- |
-LL | #[doc(include("../README.md"))]
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:21:7
- |
-LL | #[doc(include = 123)]
- | ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
- --> $DIR/external-doc-error.rs:26:7
- |
-LL | #[doc(include(123))]
- | ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: aborting due to 6 previous errors
-
+++ /dev/null
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
- //~| ERROR: `#[doc(include)]` is experimental
-fn main() {}
+++ /dev/null
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error[E0658]: `#[doc(include)]` is experimental
- --> $DIR/feature-gate-external_doc.rs:1:1
- |
-LL | #[doc(include="asdf.md")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
- = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+#[link(name = "foo")]
+extern "C" {
+ #[link_ordinal(42)]
+ //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+ fn foo();
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+ --> $DIR/feature-gate-raw-dylib-2.rs:3:5
+ |
+LL | #[link_ordinal(42)]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// gate-test-raw_dylib
+// only-windows-gnu
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
+
+fn main() {}
--- /dev/null
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+ --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: kind="raw-dylib" is unstable
+ --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// gate-test-raw_dylib
+// only-windows-msvc
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+extern "C" {}
+
+fn main() {}
--- /dev/null
+error[E0658]: kind="raw-dylib" is unstable
+ --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--> $DIR/generator-print-verbose-1.rs:35:9
|
LL | let _non_send_gen = make_non_send_generator();
- | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[70c9]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+ | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
LL | yield;
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
LL | };
= help: the trait `Sync` is not implemented for `RefCell<i32>`
= note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
= note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
- = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[70c9]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
- = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), [])`
- = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}`
- = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}]`
+ = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+ = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
+ = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
+ = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
error: aborting due to 2 previous errors
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `bool`
+ | help: replace with the correct type: `bool`
...
LL | / suite! {
LL | | len;
--- /dev/null
+// See issue #84108 -- this is a test to ensure we do not ICE
+// on this invalid code.
+
+#![crate_type = "lib"]
+
+static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+//~^ ERROR cannot find type `OsStr` in this scope
+
+const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+//~^ ERROR cannot find type `Path` in this scope
+//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+static BAZ: ([u8], usize) = ([], 0);
+//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
--- /dev/null
+error[E0412]: cannot find type `OsStr` in this scope
+ --> $DIR/issue-84108.rs:6:24
+ |
+LL | static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+ | ^^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::ffi::OsStr;
+ |
+
+error[E0412]: cannot find type `Path` in this scope
+ --> $DIR/issue-84108.rs:9:14
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^ not found in this scope
+ |
+help: consider importing this struct
+ |
+LL | use std::path::Path;
+ |
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:9:12
+ |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+ | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-84108.rs:13:13
+ |
+LL | static BAZ: ([u8], usize) = ([], 0);
+ | ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: only the last element of a tuple may have a dynamically sized type
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0412.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// compile-flags: --force-warns elided_lifetimes_in_paths
+// check-pass
+
+struct Foo<'a> {
+ x: &'a u32,
+}
+
+fn foo(x: &Foo) {}
+//~^ WARN hidden lifetime parameters in types are deprecated
+
+fn main() {}
--- /dev/null
+warning: hidden lifetime parameters in types are deprecated
+ --> $DIR/force-allowed-by-default-lint.rs:8:12
+ |
+LL | fn foo(x: &Foo) {}
+ | ^^^- help: indicate the anonymous lifetime: `<'_>`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err
+// check-pass
+
+#![allow(const_err)]
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(dead_code)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-allowed-warning.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns const_err
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: any use of this value will cause an error
+ --> $DIR/force-deny-by-default-lint.rs:4:16
+ |
+LL | const C: i32 = 1 / 0;
+ | ---------------^^^^^-
+ | |
+ | attempt to divide `1_i32` by zero
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(warnings)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
--- /dev/null
+warning: function is never used: `dead_function`
+ --> $DIR/force-lint-allow-all-warnings.rs:6:4
+ |
+LL | fn dead_function() {}
+ | ^^^^^^^^^^^^^
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns nonstandard_style
+// check-pass
+
+#![allow(warnings)]
+
+pub fn FUNCTION() {}
+//~^ WARN function `FUNCTION` should have a snake case name
+
+fn main() {}
--- /dev/null
+warning: function `FUNCTION` should have a snake case name
+ --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+ |
+LL | pub fn FUNCTION() {}
+ | ^^^^^^^^ help: convert the identifier to snake case: `function`
+ |
+ = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns bare_trait_objects
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-lint-in-allowed-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(bare_trait_objects)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group-allow-warning.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
--- /dev/null
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/force-warn-group.rs:8:25
+ |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+ | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ |
+ = note: warning forced by `force-warns` commandline option
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+ = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
use std::default::Default;
use std::marker::PhantomData;
+trait Trait {}
+
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
+pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+//~^ ERROR: uses type `Box<[u8]>`
+
+pub extern "C" fn boxed_string(p: Box<str>) { }
+//~^ ERROR: uses type `Box<str>`
+
+pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+//~^ ERROR: uses type `Box<dyn Trait>`
+
pub extern "C" fn char_type(p: char) { }
//~^ ERROR uses type `char`
error: `extern` fn uses type `[u32]`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:67:33
+ --> $DIR/lint-ctypes-fn.rs:69:33
|
LL | pub extern "C" fn slice_type(p: &[u32]) { }
| ^^^^^^ not FFI-safe
= note: slices have no C equivalent
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:70:31
+ --> $DIR/lint-ctypes-fn.rs:72:31
|
LL | pub extern "C" fn str_type(p: &str) { }
| ^^^^ not FFI-safe
= help: consider using `*const u8` and a length instead
= note: string slices have no C equivalent
+error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:79:34
+ |
+LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+ | ^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<str>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:82:35
+ |
+LL | pub extern "C" fn boxed_string(p: Box<str>) { }
+ | ^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
+ --> $DIR/lint-ctypes-fn.rs:85:34
+ |
+LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+ | ^^^^^^^^^^^^^^ not FFI-safe
+ |
+ = note: box cannot be represented as a single pointer
+
error: `extern` fn uses type `char`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:77:32
+ --> $DIR/lint-ctypes-fn.rs:88:32
|
LL | pub extern "C" fn char_type(p: char) { }
| ^^^^ not FFI-safe
= note: the `char` type has no C equivalent
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:80:32
+ --> $DIR/lint-ctypes-fn.rs:91:32
|
LL | pub extern "C" fn i128_type(p: i128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:83:32
+ --> $DIR/lint-ctypes-fn.rs:94:32
|
LL | pub extern "C" fn u128_type(p: u128) { }
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:86:33
+ --> $DIR/lint-ctypes-fn.rs:97:33
|
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
| ^^^^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:89:34
+ --> $DIR/lint-ctypes-fn.rs:100:34
|
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
| ^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:92:32
+ --> $DIR/lint-ctypes-fn.rs:103:32
|
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
| ^^^^^^^^ not FFI-safe
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:26:1
+ --> $DIR/lint-ctypes-fn.rs:28:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:95:40
+ --> $DIR/lint-ctypes-fn.rs:106:40
|
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
- --> $DIR/lint-ctypes-fn.rs:61:1
+ --> $DIR/lint-ctypes-fn.rs:63:1
|
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:98:51
+ --> $DIR/lint-ctypes-fn.rs:109:51
|
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:103:30
+ --> $DIR/lint-ctypes-fn.rs:114:30
|
LL | pub extern "C" fn fn_type(p: RustFn) { }
| ^^^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:106:31
+ --> $DIR/lint-ctypes-fn.rs:117:31
|
LL | pub extern "C" fn fn_type2(p: fn()) { }
| ^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:111:39
+ --> $DIR/lint-ctypes-fn.rs:122:39
|
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
| ^^^^^^^^^^^^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:114:38
+ --> $DIR/lint-ctypes-fn.rs:125:38
|
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
| ^^^^^^^^^^^^^^ not FFI-safe
= note: string slices have no C equivalent
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:160:43
+ --> $DIR/lint-ctypes-fn.rs:171:43
|
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:173:39
+ --> $DIR/lint-ctypes-fn.rs:184:39
|
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
| ^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
- --> $DIR/lint-ctypes-fn.rs:176:41
+ --> $DIR/lint-ctypes-fn.rs:187:41
|
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
| ^^^^^^ not FFI-safe
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
| ^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:29:16
+ --> $DIR/lint-stability-deprecated.rs:29:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:31:25
+ --> $DIR/lint-stability-deprecated.rs:31:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `lint_stability::deprecated_text`: text
--> $DIR/lint-stability-deprecated.rs:33:9
| ^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:38:16
+ --> $DIR/lint-stability-deprecated.rs:38:9
|
LL | ... Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:40:25
+ --> $DIR/lint-stability-deprecated.rs:40:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `lint_stability::deprecated_unstable`: text
--> $DIR/lint-stability-deprecated.rs:42:9
| ^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
- --> $DIR/lint-stability-deprecated.rs:47:16
+ --> $DIR/lint-stability-deprecated.rs:47:9
|
LL | ... Trait::trait_deprecated_unstable(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
- --> $DIR/lint-stability-deprecated.rs:49:25
+ --> $DIR/lint-stability-deprecated.rs:49:9
|
LL | ... <Foo as Trait>::trait_deprecated_unstable(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `lint_stability::deprecated_unstable_text`: text
--> $DIR/lint-stability-deprecated.rs:51:9
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
- --> $DIR/lint-stability-deprecated.rs:56:16
+ --> $DIR/lint-stability-deprecated.rs:56:9
|
LL | ... Trait::trait_deprecated_unstable_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
- --> $DIR/lint-stability-deprecated.rs:58:25
+ --> $DIR/lint-stability-deprecated.rs:58:9
|
LL | ... <Foo as Trait>::trait_deprecated_unstable_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated struct `lint_stability::DeprecatedStruct`: text
--> $DIR/lint-stability-deprecated.rs:108:17
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated variant `lint_stability::Enum::DeprecatedVariant`: text
- --> $DIR/lint-stability-deprecated.rs:123:23
+ --> $DIR/lint-stability-deprecated.rs:123:17
|
LL | let _ = Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated variant `lint_stability::Enum::DeprecatedUnstableVariant`: text
- --> $DIR/lint-stability-deprecated.rs:124:23
+ --> $DIR/lint-stability-deprecated.rs:124:17
|
LL | let _ = Enum::DeprecatedUnstableVariant;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated struct `lint_stability::DeprecatedTupleStruct`: text
--> $DIR/lint-stability-deprecated.rs:128:17
| ^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:145:16
+ --> $DIR/lint-stability-deprecated.rs:145:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:147:25
+ --> $DIR/lint-stability-deprecated.rs:147:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:149:16
+ --> $DIR/lint-stability-deprecated.rs:149:9
|
LL | ... Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:151:25
+ --> $DIR/lint-stability-deprecated.rs:151:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
- --> $DIR/lint-stability-deprecated.rs:153:16
+ --> $DIR/lint-stability-deprecated.rs:153:9
|
LL | ... Trait::trait_deprecated_unstable(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
- --> $DIR/lint-stability-deprecated.rs:155:25
+ --> $DIR/lint-stability-deprecated.rs:155:9
|
LL | ... <Foo as Trait>::trait_deprecated_unstable(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
- --> $DIR/lint-stability-deprecated.rs:157:16
+ --> $DIR/lint-stability-deprecated.rs:157:9
|
LL | ... Trait::trait_deprecated_unstable_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
- --> $DIR/lint-stability-deprecated.rs:159:25
+ --> $DIR/lint-stability-deprecated.rs:159:9
|
LL | ... <Foo as Trait>::trait_deprecated_unstable_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated trait `lint_stability::DeprecatedTrait`: text
--> $DIR/lint-stability-deprecated.rs:187:10
| ^^^^^^^^^^^^^^^
warning: use of deprecated function `inheritance::inherited_stability::unstable_mod::deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:208:23
+ --> $DIR/lint-stability-deprecated.rs:208:9
|
LL | unstable_mod::deprecated();
- | ^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `this_crate::deprecated`: text
--> $DIR/lint-stability-deprecated.rs:330:9
| ^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:335:16
+ --> $DIR/lint-stability-deprecated.rs:335:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:337:25
+ --> $DIR/lint-stability-deprecated.rs:337:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `this_crate::deprecated_text`: text
--> $DIR/lint-stability-deprecated.rs:339:9
| ^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:344:16
+ --> $DIR/lint-stability-deprecated.rs:344:9
|
LL | Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:346:25
+ --> $DIR/lint-stability-deprecated.rs:346:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated struct `this_crate::DeprecatedStruct`: text
--> $DIR/lint-stability-deprecated.rs:384:17
| ^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text
- --> $DIR/lint-stability-deprecated.rs:395:23
+ --> $DIR/lint-stability-deprecated.rs:395:17
|
LL | let _ = Enum::DeprecatedVariant;
- | ^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text
--> $DIR/lint-stability-deprecated.rs:399:17
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:406:16
+ --> $DIR/lint-stability-deprecated.rs:406:9
|
LL | Trait::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/lint-stability-deprecated.rs:408:25
+ --> $DIR/lint-stability-deprecated.rs:408:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:410:16
+ --> $DIR/lint-stability-deprecated.rs:410:9
|
LL | Trait::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/lint-stability-deprecated.rs:412:25
+ --> $DIR/lint-stability-deprecated.rs:412:9
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated function `this_crate::test_fn_body::fn_in_body`: text
--> $DIR/lint-stability-deprecated.rs:439:9
warning: Linking globals named 'foo': symbol multiply defined!
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.288b404e693a75b4-cgu.0.rcgu.o":
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.3a1fbbbh-cgu.0.rcgu.o":
error: aborting due to previous error; 1 warning emitted
--- /dev/null
+// compile-flags:-l raw-dylib=foo
+// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
+fn main() {
+}
--- /dev/null
+error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to previous error
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to previous error
| ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-coercions.rs:13:5
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'b` and `'a` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:6:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:12:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable pointer to &i32
+ = note: mutable pointers are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
| ^ requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/type-check-pointer-comparisons.rs:18:10
| ^ requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &i32
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected one of
+#[i=i::<ښܖ<
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-84104.rs:3:13
+ |
+LL | #[i=i::<ښܖ<
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: expected one of `>`, a const expression, lifetime, or type, found `]`
+ --> $DIR/issue-84104.rs:3:13
+ |
+LL | #[i=i::<ښܖ<
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+fn f(t:for<>t?)
+//~^ ERROR: expected parameter name
+//~| ERROR: expected one of
+//~| ERROR: expected one of
--- /dev/null
+error: expected parameter name, found `?`
+ --> $DIR/issue-84148-1.rs:1:14
+ |
+LL | fn f(t:for<>t?)
+ | ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+ --> $DIR/issue-84148-1.rs:1:14
+ |
+LL | fn f(t:for<>t?)
+ | ^
+ | |
+ | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+ | help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+ --> $DIR/issue-84148-1.rs:1:15
+ |
+LL | fn f(t:for<>t?)
+ | ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected parameter name
+// error-pattern: expected one of
+fn f(t:for<>t?
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-84148-2.rs:4:16
+ |
+LL | fn f(t:for<>t?
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: expected parameter name, found `?`
+ --> $DIR/issue-84148-2.rs:4:14
+ |
+LL | fn f(t:for<>t?
+ | ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+ --> $DIR/issue-84148-2.rs:4:14
+ |
+LL | fn f(t:for<>t?
+ | ^
+ | |
+ | expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+ | help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+ --> $DIR/issue-84148-2.rs:4:16
+ |
+LL | fn f(t:for<>t?
+ | ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// Check that a suggestion is issued if there are too many `<`s in a
+// generic argument list, and that the parser recovers properly.
+
+fn main() {
+ foo::<<<<Ty<i32>>();
+ //~^ ERROR: unmatched angle brackets
+ //~| ERROR: cannot find function `foo` in this scope [E0425]
+ //~| ERROR: cannot find type `Ty` in this scope [E0412]
+}
--- /dev/null
+error: unmatched angle brackets
+ --> $DIR/unmatched-langle-1.rs:5:10
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^^ help: remove extra angle brackets
+
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/unmatched-langle-1.rs:5:5
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^^ not found in this scope
+
+error[E0412]: cannot find type `Ty` in this scope
+ --> $DIR/unmatched-langle-1.rs:5:14
+ |
+LL | foo::<<<<Ty<i32>>();
+ | ^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0412, E0425.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+// When there are too many opening `<`s, the compiler would previously
+// suggest nonsense if the `<`s were interspersed with other tokens:
+//
+// error: unmatched angle brackets
+// --> unmatched-langle.rs:2:10
+// |
+// 2 | foo::<Ty<<<i32>();
+// | ^^^ help: remove extra angle brackets
+//
+// This test makes sure that this is no longer happening.
+
+fn main() {
+ foo::<Ty<<<i32>();
+ //~^ ERROR: expected `::`, found `(`
+}
--- /dev/null
+error: expected `::`, found `(`
+ --> $DIR/unmatched-langle-2.rs:13:20
+ |
+LL | foo::<Ty<<<i32>();
+ | ^ expected `::`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+// aux-build:test-macros.rs
+
+#![feature(decl_macro)]
+#![feature(stmt_expr_attributes)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro mac {
+ (expr $expr:expr) => {
+ #[derive(Print)]
+ enum E {
+ V = { let _ = $expr; 0 },
+ }
+ },
+ (stmt $stmt:stmt) => {
+ #[derive(Print)]
+ enum E {
+ V = { let _ = { $stmt }; 0 },
+ }
+ },
+}
+
+const PATH: u8 = 2;
+
+fn main() {
+ mac!(expr #[allow(warnings)] 0);
+ mac!(stmt 0);
+ mac!(stmt {});
+ mac!(stmt PATH);
+ mac!(stmt 0 + 1);
+ mac!(stmt PATH + 1);
+}
--- /dev/null
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #4 bytes(299..303),
+ },
+ Ident {
+ ident: "E",
+ span: #4 bytes(304..305),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #4 bytes(320..321),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #4 bytes(322..323),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #4 bytes(326..329),
+ },
+ Ident {
+ ident: "_",
+ span: #4 bytes(330..331),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #4 bytes(332..333),
+ },
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: #0 bytes(541..542),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: #0 bytes(543..548),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "warnings",
+ span: #0 bytes(549..557),
+ },
+ ],
+ span: #0 bytes(548..558),
+ },
+ ],
+ span: #0 bytes(542..559),
+ },
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: #0 bytes(541..542),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "allow",
+ span: #0 bytes(543..548),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "warnings",
+ span: #0 bytes(549..557),
+ },
+ ],
+ span: #0 bytes(548..558),
+ },
+ ],
+ span: #0 bytes(542..559),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(560..561),
+ },
+ ],
+ span: #4 bytes(334..339),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #4 bytes(339..340),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #4 bytes(341..342),
+ },
+ ],
+ span: #4 bytes(324..344),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #4 bytes(344..345),
+ },
+ ],
+ span: #4 bytes(306..355),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #8 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #8 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #8 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #8 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #8 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #8 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #8 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(578..579),
+ },
+ ],
+ span: #8 bytes(460..465),
+ },
+ ],
+ span: #8 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #8 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #8 bytes(469..470),
+ },
+ ],
+ span: #8 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #8 bytes(472..473),
+ },
+ ],
+ span: #8 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #12 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #12 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #12 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #12 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #12 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #12 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #12 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [],
+ span: #0 bytes(596..598),
+ },
+ ],
+ span: #12 bytes(460..465),
+ },
+ ],
+ span: #12 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #12 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #12 bytes(469..470),
+ },
+ ],
+ span: #12 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #12 bytes(472..473),
+ },
+ ],
+ span: #12 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #16 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #16 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #16 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #16 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #16 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #16 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #16 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Ident {
+ ident: "PATH",
+ span: #0 bytes(615..619),
+ },
+ ],
+ span: #16 bytes(460..465),
+ },
+ ],
+ span: #16 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #16 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #16 bytes(469..470),
+ },
+ ],
+ span: #16 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #16 bytes(472..473),
+ },
+ ],
+ span: #16 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #20 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #20 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #20 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #20 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #20 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #20 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #20 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #0 bytes(636..637),
+ },
+ Punct {
+ ch: '+',
+ spacing: Alone,
+ span: #0 bytes(638..639),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: #0 bytes(640..641),
+ },
+ ],
+ span: #20 bytes(460..465),
+ },
+ ],
+ span: #20 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #20 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #20 bytes(469..470),
+ },
+ ],
+ span: #20 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #20 bytes(472..473),
+ },
+ ],
+ span: #20 bytes(430..483),
+ },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "enum",
+ span: #24 bytes(423..427),
+ },
+ Ident {
+ ident: "E",
+ span: #24 bytes(428..429),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "V",
+ span: #24 bytes(444..445),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #24 bytes(446..447),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Ident {
+ ident: "let",
+ span: #24 bytes(450..453),
+ },
+ Ident {
+ ident: "_",
+ span: #24 bytes(454..455),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: #24 bytes(456..457),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Group {
+ delimiter: None,
+ stream: TokenStream [
+ Ident {
+ ident: "PATH",
+ span: #0 bytes(658..662),
+ },
+ Punct {
+ ch: '+',
+ spacing: Alone,
+ span: #0 bytes(663..664),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "1",
+ suffix: None,
+ span: #0 bytes(665..666),
+ },
+ ],
+ span: #24 bytes(460..465),
+ },
+ ],
+ span: #24 bytes(458..467),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: #24 bytes(467..468),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "0",
+ suffix: None,
+ span: #24 bytes(469..470),
+ },
+ ],
+ span: #24 bytes(448..472),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: #24 bytes(472..473),
+ },
+ ],
+ span: #24 bytes(430..483),
+ },
+]
| ^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
| ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
| ^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to &isize
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: higher-ranked subtype error
--> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
| ^ returning this value requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
+ = note: requirement occurs because of a mutable reference to dyn Dummy
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> $DIR/regions-trait-object-subtyping.rs:22:5
| ^ returning this value requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a mutable reference to dyn Dummy
+ = note: mutable references are invariant over their type parameter
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: aborting due to 2 previous errors
+++ /dev/null
-#[link(name = "foo")]
-extern "C" {
- #[link_ordinal(42)]
- //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
- fn foo();
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
- --> $DIR/feature-gate-raw-dylib-2.rs:3:5
- |
-LL | #[link_ordinal(42)]
- | ^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
- = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-extern "C" {}
-
-fn main() {}
+++ /dev/null
-error[E0658]: kind="raw-dylib" is unstable
- --> $DIR/feature-gate-raw-dylib.rs:1:1
- |
-LL | #[link(name = "foo", kind = "raw-dylib")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
- = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// only-windows-gnu
+// check-pass
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/raw-dylib-msvc-only.rs:4:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+ --> $DIR/raw-dylib-msvc-only.rs:6:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
--- /dev/null
+// ignore-windows
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+extern "C" {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/raw-dylib-windows-only.rs:3:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+ --> $DIR/raw-dylib-windows-only.rs:5:1
+ |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+#![deny(invalid_doc_attributes)]
+//~^ NOTE defined here
+#![doc(x)]
+//~^ ERROR unknown `doc` attribute `x`
+//~| WARNING will become a hard error
+//~| NOTE see issue #82730
+fn main() {}
--- /dev/null
+error: unknown `doc` attribute `x`
+ --> $DIR/deny-invalid-doc-attrs.rs:3:8
+ |
+LL | #![doc(x)]
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/deny-invalid-doc-attrs.rs:1:9
+ |
+LL | #![deny(invalid_doc_attributes)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: aborting due to previous error
+
--- /dev/null
+#[doc(inline)]
+//~^ ERROR conflicting
+#[doc(no_inline)]
+pub extern crate core;
+
+// no warning
+pub extern crate alloc;
+
+fn main() {}
--- /dev/null
+error: conflicting doc inlining attributes
+ --> $DIR/doc-inline-extern-crate.rs:1:7
+ |
+LL | #[doc(inline)]
+ | ^^^^^^ this attribute...
+LL |
+LL | #[doc(no_inline)]
+ | ^^^^^^^^^ ...conflicts with this attribute
+ |
+ = help: remove one of the conflicting attributes
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+// Short form of the generic gather/scatter tests,
+// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work.
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct cptrx4<T>([*const T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct mptrx4<T>([*mut T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct i32x4([i32; 4]);
+
+extern "platform-intrinsic" {
+ fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T;
+ fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> ();
+}
+
+fn main() {
+ let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
+
+ let default = f32x4([-3_f32, -3., -3., -3.]);
+ let s_strided = f32x4([0_f32, 2., -3., 6.]);
+ let mask = i32x4([-1_i32, -1, 0, -1]);
+
+ // reading from *const
+ unsafe {
+ let pointer = &x as *const f32;
+ let pointers = cptrx4([
+ pointer.offset(0) as *const f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let r_strided = simd_gather(default, pointers, mask);
+
+ assert_eq!(r_strided, s_strided);
+ }
+
+ // writing to *mut
+ unsafe {
+ let pointer = &mut x as *mut f32;
+ let pointers = mptrx4([
+ pointer.offset(0) as *mut f32,
+ pointer.offset(2),
+ pointer.offset(4),
+ pointer.offset(6)
+ ]);
+
+ let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]);
+ simd_scatter(values, pointers, mask);
+
+ assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
+ }
+}
--- /dev/null
+// run-pass
+// ignore-emscripten
+
+#![feature(extern_types)]
+#![feature(repr_simd)]
+
+use std::ptr::NonNull;
+
+extern {
+ type Extern;
+}
+
+#[repr(simd)]
+struct S<T>(T);
+
+#[inline(never)]
+fn identity<T>(v: T) -> T {
+ v
+}
+
+fn main() {
+ let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4]));
+}
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S<T>(T);
+
+fn main() {
+ let _v: Option<S<[*mut [u8]; 4]>> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S([*mut [u8]; 4]);
+
+fn main() {
+ let _v: Option<S> = None;
+}
--- /dev/null
+error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
--- /dev/null
+// build-pass
+
+#![cfg_attr(target_arch = "wasm32", feature(wasm_simd, wasm_target_feature))]
+
+#[cfg(target_arch = "wasm32")]
+fn main() {
+ unsafe {
+ a::api_with_simd_feature();
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod a {
+ use std::arch::wasm32::*;
+
+ #[target_feature(enable = "simd128")]
+ pub unsafe fn api_with_simd_feature() {
+ crate::b::api_takes_v128(u64x2(0, 1));
+ }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod b {
+ use std::arch::wasm32::*;
+
+ #[inline(never)]
+ pub fn api_takes_v128(a: v128) -> v128 {
+ a
+ }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn main() {}
-error: lifetime parameter `'a` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
+error: lifetime parameter `'b` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^-
- | |
- | this lifetime is only used here
- | help: elide the single-use lifetime
+ | ^^-
+ | |
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
|
note: the lint level is defined here
--> $DIR/one-use-in-fn-argument-in-band.rs:4:9
LL | #![deny(single_use_lifetimes)]
| ^^^^^^^^^^^^^^^^^^^^
-error: lifetime parameter `'b` only used once
- --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
|
LL | fn a(x: &'a u32, y: &'b u32) {
- | ^^-
- | |
- | this lifetime is only used here
- | help: elide the single-use lifetime
+ | ^^-
+ | |
+ | this lifetime is only used here
+ | help: elide the single-use lifetime
error: aborting due to 2 previous errors
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[b09c]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)), [])`
--> $DIR/repeated_projection_type.rs:19:1
|
LL | / impl<I, V: Id<This = (I,)>> X for V {
| ^^^^^^^^^^^^^
warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
- --> $DIR/generics-default-stability.rs:231:34
+ --> $DIR/generics-default-stability.rs:231:27
|
LL | let _: Enum4<isize> = Enum4::Some(1);
- | ^^^^
+ | ^^^^^^^^^^^
warning: use of deprecated enum `unstable_generic_param::Enum4`: test
--> $DIR/generics-default-stability.rs:231:12
| ^^^^^^^^^^^^
warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
- --> $DIR/generics-default-stability.rs:237:34
+ --> $DIR/generics-default-stability.rs:237:27
|
LL | let _: Enum4<isize> = Enum4::Some(0);
- | ^^^^
+ | ^^^^^^^^^^^
warning: use of deprecated enum `unstable_generic_param::Enum4`: test
--> $DIR/generics-default-stability.rs:237:12
| ^^^^^^^^^^^^
warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
- --> $DIR/generics-default-stability.rs:242:34
+ --> $DIR/generics-default-stability.rs:242:27
|
LL | let _: Enum5<isize> = Enum5::Some(1);
- | ^^^^
+ | ^^^^^^^^^^^
warning: use of deprecated enum `unstable_generic_param::Enum5`: test
--> $DIR/generics-default-stability.rs:242:12
| ^^^^^^^^^^^^
warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
- --> $DIR/generics-default-stability.rs:249:34
+ --> $DIR/generics-default-stability.rs:249:27
|
LL | let _: Enum5<isize> = Enum5::Some(0);
- | ^^^^
+ | ^^^^^^^^^^^
warning: use of deprecated enum `unstable_generic_param::Enum5`: test
--> $DIR/generics-default-stability.rs:249:12
//~^ ERROR mismatched types
let b: String = &format!("b");
//~^ ERROR mismatched types
+ let c: String = &mut format!("c");
+ //~^ ERROR mismatched types
+ let d: String = &mut (format!("d"));
+ //~^ ERROR mismatched types
}
| | help: consider removing the borrow: `format!("b")`
| expected due to this
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:6:21
+ |
+LL | let c: String = &mut format!("c");
+ | ------ ^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("c")`
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/format-borrow.rs:8:21
+ |
+LL | let d: String = &mut (format!("d"));
+ | ------ ^^^^^^^^^^^^^^^^^^^
+ | | |
+ | | expected struct `String`, found `&mut String`
+ | | help: consider removing the borrow: `format!("d")`
+ | expected due to this
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for #85943: should not emit suggestions for adding
+// indirection to type parameters in where-clauses when suggesting
+// adding `?Sized`.
+struct A<T>(T) where T: Send;
+struct B(A<[u8]>);
+//~^ ERROR the size for values of type
+
+pub fn main() {
+}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:5:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | - required by this bound in `A`
+LL | struct B(A<[u8]>);
+ | ^^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+ --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10
+ |
+LL | struct A<T>(T) where T: Send;
+ | ^ - ...if indirection were used here: `Box<T>`
+ | |
+ | this could be changed to `T: ?Sized`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-error: symbol-name(_ZN5basic4main17hd75b915511563828E)
+error: symbol-name(_ZN5basic4main17h6c535bbea2051f85E)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic::main::hd75b915511563828)
+error: demangling(basic::main::h6c535bbea2051f85)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN5basic4main
//[legacy]~| ERROR demangling(basic::main
//[legacy]~| ERROR demangling-alt(basic::main)
- //[v0]~^^^^ ERROR symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
- //[v0]~| ERROR demangling(basic[de7d5b6b69c71f37]::main)
+ //[v0]~^^^^ ERROR symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
+ //[v0]~| ERROR demangling(basic[17891616a171812d]::main)
//[v0]~| ERROR demangling-alt(basic::main)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(main)
-error: symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
+error: symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(basic[de7d5b6b69c71f37]::main)
+error: demangling(basic[17891616a171812d]::main)
--> $DIR/basic.rs:8:1
|
LL | #[rustc_symbol_name]
pub struct Unsigned<const F: u8>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
-//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
+//~^ ERROR symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
//~| ERROR demangling-alt(<const_generics_demangling::Unsigned<11>>)
impl Unsigned<11> {}
pub struct Signed<const F: i16>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
-//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
+//~^ ERROR symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
+//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
//~| ERROR demangling-alt(<const_generics_demangling::Signed<-152>>)
impl Signed<-152> {}
pub struct Bool<const F: bool>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
-//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
+//~^ ERROR symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
+//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
//~| ERROR demangling-alt(<const_generics_demangling::Bool<true>>)
impl Bool<true> {}
pub struct Char<const F: char>;
#[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
-//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
+//~^ ERROR symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
+//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
//~| ERROR demangling-alt(<const_generics_demangling::Char<'∂'>>)
impl Char<'∂'> {}
-error: symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+error: symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
--> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
+error: demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
--> $DIR/const-generics-demangling.rs:7:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
+error: symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
--> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
+error: demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
--> $DIR/const-generics-demangling.rs:15:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
+error: symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
--> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
+error: demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
--> $DIR/const-generics-demangling.rs:23:1
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
+error: symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
--> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
+error: demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
--> $DIR/const-generics-demangling.rs:31:1
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
//[legacy]~| ERROR demangling(impl1::foo::Foo::bar
//[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
- //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
+ //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(foo::Foo::bar)
//[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
//[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
//[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
- //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
+ //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
//[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
//[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
//[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
//[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
- //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
- //[v0]~| ERROR demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+ //[v0]~| ERROR demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
//[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
#[rustc_def_path]
//[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
-error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
+error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
+error: demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
--> $DIR/impl1.rs:14:9
|
LL | #[rustc_symbol_name]
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
+error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
+error: demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
--> $DIR/impl1.rs:32:9
|
LL | #[rustc_symbol_name]
LL | #[rustc_def_path]
| ^^^^^^^^^^^^^^^^^
-error: symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+error: symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
--> $DIR/impl1.rs:62:13
|
LL | #[rustc_symbol_name]
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h18eaa05e22e59176E)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h6244e5288326926aE)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h18eaa05e22e59176)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h6244e5288326926a)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
//[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
//[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
- //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
- //[v0]~| ERROR demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+ //[v0]~| ERROR demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
//[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
pub(crate) fn foo() {
for _ in 0..0 {
-error: symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+error: symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
+error: demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
//[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
//[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
//[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
- //[v0]~^^^^ ERROR symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
- //[v0]~| ERROR demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+ //[v0]~| ERROR demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
//[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
fn next(&mut self) -> Option<Self::Item> {
self.find(|_| true)
-error: symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+error: symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
+error: demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
--> $DIR/issue-75326.rs:41:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3f8b57f879016e18]::Bar>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[17891616a171812d]::Bar>::method)
--> $DIR/trait-objects.rs:16:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Foo>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Foo>::method)
--> $DIR/trait-objects.rs:28:5
|
LL | #[rustc_symbol_name]
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Baz>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[17891616a171812d]::Baz>::method)
--> $DIR/trait-objects.rs:40:5
|
LL | #[rustc_symbol_name]
// gate-test-f16c_target_feature
// gate-test-riscv_target_feature
// gate-test-ermsb_target_feature
+// gate-test-bpf_target_feature
#[target_feature(enable = "avx512bw")]
//~^ ERROR: currently unstable
error[E0658]: the target feature `avx512bw` is currently unstable
- --> $DIR/gate.rs:31:18
+ --> $DIR/gate.rs:32:18
|
LL | #[target_feature(enable = "avx512bw")]
| ^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// compile-flags: --test
+// run-flags: --test-threads=1
+// check-run-results
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// ignore-emscripten no threads support
+// run-pass
+
+
+#[test]
+fn test_ok() {
+ let _a = true;
+}
+
+#[test]
+#[should_panic]
+fn test_panic() {
+ panic!();
+}
+
+#[test]
+#[ignore]
+fn test_no_run() {
+ loop{
+ println!("Hello, world");
+ }
+}
+
+fn main() {}
--- /dev/null
+
+running 3 tests
+test test_no_run ... ignored
+test test_ok ... ok
+test test_panic - should panic ... ok
+
+test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
running 4 tests
test it_fails ... about to fail
FAILED
-test it_panics ... about to panic
+test it_panics - should panic ... about to panic
ok
test it_works ... about to succeed
ok
running 5 tests
test it_exits ... FAILED
test it_fails ... FAILED
-test it_panics ... ok
+test it_panics - should panic ... ok
test it_works ... ok
test no_residual_environment ... ok
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:19:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:22:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:80:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:92:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:95:22
| ^^^^^^^^^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<u8>`
+ | help: replace with the correct type: `Option<u8>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:144:31
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:201:26
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 69 previous errors; 1 warning emitted
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:19:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:22:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:80:15
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `&str`
+ | help: replace with the correct type: `&str`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:92:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:95:22
| ^^^^^^^^^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<u8>`
+ | help: replace with the correct type: `Option<u8>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:144:31
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:201:26
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 69 previous errors
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `u32`
+ | help: replace with the correct type: `u32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:10:14
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `Option<i32>`
+ | help: replace with the correct type: `Option<i32>`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:13:22
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item_help.rs:24:18
| ^
| |
| not allowed in type signatures
- | help: replace `_` with the correct type: `i32`
+ | help: replace with the correct type: `i32`
error: aborting due to 6 previous errors
"armv7r-none-eabihf",
"armv7s-apple-ios",
"asmjs-unknown-emscripten",
+ "bpfeb-unknown-none",
+ "bpfel-unknown-none",
"i386-apple-ios",
"i586-pc-windows-msvc",
"i586-unknown-linux-gnu",
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
-use rustc_ast::ast::{self, MetaItem, MetaItemKind};
+use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
- fn has_include(meta: Option<MetaItem>) -> bool {
- if_chain! {
- if let Some(meta) = meta;
- if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.get(0);
- if let Some(name) = meta.ident();
- then {
- name.name == sym::include
- } else {
- false
- }
- }
- }
-
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
let has_doc = attrs
.iter()
- .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
+ .any(|a| a.doc_str().is_some());
if !has_doc {
span_lint(
cx,
#![warn(clippy::missing_docs_in_private_items)]
-#![feature(external_doc)]
-#![doc(include = "../../README.md")]
+#![doc = include_str!("../../README.md")]
fn main() {}
ignore,
should_panic,
allow_fail: false,
+ #[cfg(not(bootstrap))]
+ compile_fail: false,
+ #[cfg(not(bootstrap))]
+ no_run: false,
test_type: test::TestType::Unknown,
},
testfn: make_test_closure(config, testpaths, revision),
|| self.config.target.contains("nvptx")
|| self.is_vxworks_pure_static()
|| self.config.target.contains("sgx")
+ || self.config.target.contains("bpf")
{
// We primarily compile all auxiliary libraries as dynamic libraries
// to avoid code size bloat and large binaries as much as possible
let mut tested = 0;
for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
- let tmp: Vec<&str> = s.split(" - ").collect();
- if tmp.len() == 2 {
- let path = tmp[0].rsplit("test ").next().unwrap();
+ if let Some((left, right)) = s.split_once(" - ") {
+ let path = left.rsplit("test ").next().unwrap();
if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
tested += 1;
- let mut iter = tmp[1].split("(line ");
+ let mut iter = right.split("(line ");
iter.next();
let line = iter
.next()
("armv7s", "arm"),
("asmjs", "asmjs"),
("avr", "avr"),
+ ("bpfeb", "bpf"),
+ ("bpfel", "bpf"),
("hexagon", "hexagon"),
("i386", "x86"),
("i586", "x86"),