}
}
+impl rustc_errors::IntoDiagnosticArg for RegionName {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
pub(crate) fn mir_def_id(&self) -> hir::def_id::LocalDefId {
self.body.source.def_id().expect_local()
};
}
+#[allow(rustc::diagnostic_outside_of_impl)]
+#[allow(rustc::untranslatable_diagnostic)]
pub(super) fn dump_annotation<'tcx>(
infcx: &InferCtxt<'tcx>,
body: &Body<'tcx>,
-use rustc_errors::{IntoDiagnosticArg, MultiSpan};
+use rustc_errors::MultiSpan;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{GenericArg, Ty};
use rustc_span::Span;
},
}
-impl IntoDiagnosticArg for &RegionName {
- fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
- format!("{}", self).into_diagnostic_arg()
- }
-}
-
-impl IntoDiagnosticArg for RegionName {
- fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
- format!("{}", self).into_diagnostic_arg()
- }
-}
-
#[derive(Subdiagnostic)]
pub(crate) enum RequireStaticErr {
#[note(borrowck_used_impl_require_static)]
user_ty: ty::UserType<'tcx>,
span: Span,
) {
- // FIXME: Ideally MIR types are normalized, but this is not always true.
- let mir_ty = self.normalize(mir_ty, Locations::All(span));
-
self.fully_perform_op(
Locations::All(span),
ConstraintCategory::Boring,
return;
}
+ // FIXME: Ideally MIR types are normalized, but this is not always true.
let mir_ty = self.normalize(mir_ty, Locations::All(span));
+
let cause = ObligationCause::dummy_with_span(span);
let param_env = self.param_env;
let op = |infcx: &'_ _| {
impl WriteBackendMethods for GccCodegenBackend {
type Module = GccContext;
type TargetMachine = ();
+ type TargetMachineError = ();
type ModuleBuffer = ModuleBuffer;
type ThinData = ();
type ThinBuffer = ThinBuffer;
use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
-use crate::errors::DynamicLinkingWithLTO;
+use crate::errors::{
+ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
+};
use crate::llvm::{self, build_string};
use crate::{LlvmCodegenBackend, ModuleLlvm};
use object::read::archive::ArchiveFile;
// Make sure we actually can run LTO
for crate_type in cgcx.crate_types.iter() {
if !crate_type_allows_lto(*crate_type) {
- let e = diag_handler.fatal(
- "lto can only be run for executables, cdylibs and \
- static library outputs",
- );
- return Err(e);
+ diag_handler.emit_err(LtoDisallowed);
+ return Err(FatalError);
} else if *crate_type == CrateType::Dylib {
if !cgcx.opts.unstable_opts.dylib_lto {
- return Err(diag_handler
- .fatal("lto cannot be used for `dylib` crate type without `-Zdylib-lto`"));
+ diag_handler.emit_err(LtoDylib);
+ return Err(FatalError);
}
}
}
let module = SerializedModule::FromRlib(data.to_vec());
upstream_modules.push((module, CString::new(name).unwrap()));
}
- Err(msg) => return Err(diag_handler.fatal(&msg)),
+ Err(e) => {
+ diag_handler.emit_err(e);
+ return Err(FatalError);
+ }
}
}
}
Ok((symbols_below_threshold, upstream_modules))
}
-fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], String> {
+fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> {
let mut len = 0;
let data =
unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) };
Ok(bc)
} else {
assert!(len == 0);
- let msg = llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string());
- Err(format!("failed to get bitcode from object file for LTO ({})", msg))
+ Err(LtoBitcodeFromRlib {
+ llvm_err: llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string()),
+ })
}
}
});
info!("linking {:?}", name);
let data = bc_decoded.data();
- linker.add(data).map_err(|()| {
- let msg = format!("failed to load bitcode of module {:?}", name);
- write::llvm_err(diag_handler, &msg)
- })?;
+ linker
+ .add(data)
+ .map_err(|()| write::llvm_err(diag_handler, LlvmError::LoadBitcode { name }))?;
serialized_bitcode.push(bc_decoded);
}
drop(linker);
symbols_below_threshold.as_ptr(),
symbols_below_threshold.len() as u32,
)
- .ok_or_else(|| write::llvm_err(diag_handler, "failed to prepare thin LTO context"))?;
+ .ok_or_else(|| write::llvm_err(diag_handler, LlvmError::PrepareThinLtoContext))?;
let data = ThinData(data);
// session, overwriting the previous serialized data (if any).
if let Some(path) = key_map_path {
if let Err(err) = curr_key_map.save_to_file(&path) {
- let msg = format!("Error while writing ThinLTO key data: {}", err);
- return Err(write::llvm_err(diag_handler, &msg));
+ return Err(write::llvm_err(diag_handler, LlvmError::WriteThinLtoKey { err }));
}
}
let module_name = &thin_module.shared.module_names[thin_module.idx];
let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
- let tm =
- (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
+ let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, e))?;
// Right now the implementation we've got only works over serialized
// modules, so we create a fresh new LLVM context and parse the module
let mut cu2 = ptr::null_mut();
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
if !cu2.is_null() {
- let msg = "multiple source DICompileUnits found";
- return Err(write::llvm_err(&diag_handler, msg));
+ return Err(write::llvm_err(&diag_handler, LlvmError::MultipleSourceDiCompileUnit));
}
// Up next comes the per-module local analyses that we do for Thin LTO.
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
- let msg = "failed to prepare thin LTO module";
- return Err(write::llvm_err(&diag_handler, msg));
+ return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
}
.prof
.generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module";
- return Err(write::llvm_err(&diag_handler, msg));
+ return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
}
.prof
.generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module";
- return Err(write::llvm_err(&diag_handler, msg));
+ return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
}
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
- let msg = "failed to prepare thin LTO module";
- return Err(write::llvm_err(&diag_handler, msg));
+ return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
}
diag_handler: &Handler,
) -> Result<&'a llvm::Module, FatalError> {
unsafe {
- llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()).ok_or_else(
- || {
- let msg = "failed to parse bitcode for LTO module";
- write::llvm_err(diag_handler, msg)
- },
- )
+ llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr())
+ .ok_or_else(|| write::llvm_err(diag_handler, LlvmError::ParseBitcode))
}
}
use crate::base;
use crate::common;
use crate::consts;
+use crate::errors::{
+ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
+};
use crate::llvm::{self, DiagnosticInfo, PassManager};
use crate::llvm_util;
use crate::type_::Type;
use std::str;
use std::sync::Arc;
-pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError {
+pub fn llvm_err<'a>(handler: &rustc_errors::Handler, err: LlvmError<'a>) -> FatalError {
match llvm::last_error() {
- Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
- None => handler.fatal(msg),
+ Some(llvm_err) => handler.emit_almost_fatal(WithLlvmError(err, llvm_err)),
+ None => handler.emit_almost_fatal(err),
}
}
}
}
- result.into_result().map_err(|()| {
- let msg = format!("could not write output to {}", output.display());
- llvm_err(handler, &msg)
- })
+ result
+ .into_result()
+ .map_err(|()| llvm_err(handler, LlvmError::WriteOutput { path: output }))
}
}
// system/tcx is set up.
let features = llvm_util::global_llvm_features(sess, false);
target_machine_factory(sess, config::OptLevel::No, &features)(config)
- .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise())
+ .unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
}
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
tcx.backend_optimization_level(()),
tcx.global_backend_features(()),
)(config)
- .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
+ .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), err).raise())
}
pub fn to_llvm_opt_settings(
)
};
- tm.ok_or_else(|| {
- format!("Could not create LLVM TargetMachine for triple: {}", triple.to_str().unwrap())
- })
+ tm.ok_or_else(|| LlvmError::CreateTargetMachine { triple: triple.clone() })
})
}
};
if enabled {
- diag_handler.note_without_error(&format!(
- "{}:{}:{}: {}: {}",
- opt.filename, opt.line, opt.column, opt.pass_name, opt.message,
- ));
+ diag_handler.emit_note(FromLlvmOptimizationDiag {
+ filename: &opt.filename,
+ line: opt.line,
+ column: opt.column,
+ pass_name: &opt.pass_name,
+ message: &opt.message,
+ });
}
}
llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => {
- let msg = llvm::build_string(|s| {
+ let message = llvm::build_string(|s| {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
})
.expect("non-UTF8 diagnostic");
- diag_handler.warn(&msg);
+ diag_handler.emit_warning(FromLlvmDiag { message });
}
llvm::diagnostic::Unsupported(diagnostic_ref) => {
- let msg = llvm::build_string(|s| {
+ let message = llvm::build_string(|s| {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
})
.expect("non-UTF8 diagnostic");
- diag_handler.err(&msg);
+ diag_handler.emit_err(FromLlvmDiag { message });
}
llvm::diagnostic::UnknownDiagnostic(..) => {}
}
llvm_plugins.as_ptr().cast(),
llvm_plugins.len(),
);
- result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes"))
+ result.into_result().map_err(|()| llvm_err(diag_handler, LlvmError::RunLlvmPasses))
}
// Unsafe due to LLVM calls.
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", &*module.name);
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
linker.add(buffer.data()).map_err(|()| {
- let msg = format!("failed to serialize module {:?}", module.name);
- llvm_err(diag_handler, &msg)
+ llvm_err(diag_handler, LlvmError::SerializeModule { name: &module.name })
})?;
}
drop(linker);
let _timer = cgcx
.prof
.generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name);
- if let Err(e) = fs::write(&bc_out, data) {
- let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e);
- diag_handler.err(&msg);
+ if let Err(err) = fs::write(&bc_out, data) {
+ diag_handler.emit_err(WriteBytecode { path: &bc_out, err });
}
}
record_artifact_size(&cgcx.prof, "llvm_ir", &out);
}
- result.into_result().map_err(|()| {
- let msg = format!("failed to write LLVM IR to {}", out.display());
- llvm_err(diag_handler, &msg)
- })?;
+ result
+ .into_result()
+ .map_err(|()| llvm_err(diag_handler, LlvmError::WriteIr { path: &out }))?;
}
if config.emit_asm {
EmitObj::Bitcode => {
debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
- if let Err(e) = link_or_copy(&bc_out, &obj_out) {
- diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
+ if let Err(err) = link_or_copy(&bc_out, &obj_out) {
+ diag_handler.emit_err(CopyBitcode { err });
}
if !config.emit_bc {
use std::borrow::Cow;
+use std::ffi::CString;
+use std::path::Path;
-use rustc_errors::fluent;
-use rustc_errors::DiagnosticBuilder;
-use rustc_errors::ErrorGuaranteed;
-use rustc_errors::Handler;
-use rustc_errors::IntoDiagnostic;
+use rustc_data_structures::small_c_str::SmallCStr;
+use rustc_errors::{
+ fluent, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
+};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
#[note]
pub(crate) struct DynamicLinkingWithLTO;
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_fail_parsing_target_machine_config_to_target_machine)]
-pub(crate) struct FailParsingTargetMachineConfigToTargetMachine {
- pub error: String,
+pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
+
+impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> {
+ fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> {
+ let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(sess);
+ let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
+ let message = sess.eagerly_translate_to_string(message.clone(), diag.args());
+
+ let mut diag = sess.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config);
+ diag.set_arg("error", message);
+ diag
+ }
}
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
diag
}
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_lto_disallowed)]
+pub(crate) struct LtoDisallowed;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_lto_dylib)]
+pub(crate) struct LtoDylib;
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_lto_bitcode_from_rlib)]
+pub(crate) struct LtoBitcodeFromRlib {
+ pub llvm_err: String,
+}
+
+#[derive(Diagnostic)]
+pub enum LlvmError<'a> {
+ #[diag(codegen_llvm_write_output)]
+ WriteOutput { path: &'a Path },
+ #[diag(codegen_llvm_target_machine)]
+ CreateTargetMachine { triple: SmallCStr },
+ #[diag(codegen_llvm_run_passes)]
+ RunLlvmPasses,
+ #[diag(codegen_llvm_serialize_module)]
+ SerializeModule { name: &'a str },
+ #[diag(codegen_llvm_write_ir)]
+ WriteIr { path: &'a Path },
+ #[diag(codegen_llvm_prepare_thin_lto_context)]
+ PrepareThinLtoContext,
+ #[diag(codegen_llvm_load_bitcode)]
+ LoadBitcode { name: CString },
+ #[diag(codegen_llvm_write_thinlto_key)]
+ WriteThinLtoKey { err: std::io::Error },
+ #[diag(codegen_llvm_multiple_source_dicompileunit)]
+ MultipleSourceDiCompileUnit,
+ #[diag(codegen_llvm_prepare_thin_lto_module)]
+ PrepareThinLtoModule,
+ #[diag(codegen_llvm_parse_bitcode)]
+ ParseBitcode,
+}
+
+pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
+
+impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> {
+ fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> {
+ use LlvmError::*;
+ let msg_with_llvm_err = match &self.0 {
+ WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
+ CreateTargetMachine { .. } => fluent::codegen_llvm_target_machine_with_llvm_err,
+ RunLlvmPasses => fluent::codegen_llvm_run_passes_with_llvm_err,
+ SerializeModule { .. } => fluent::codegen_llvm_serialize_module_with_llvm_err,
+ WriteIr { .. } => fluent::codegen_llvm_write_ir_with_llvm_err,
+ PrepareThinLtoContext => fluent::codegen_llvm_prepare_thin_lto_context_with_llvm_err,
+ LoadBitcode { .. } => fluent::codegen_llvm_load_bitcode_with_llvm_err,
+ WriteThinLtoKey { .. } => fluent::codegen_llvm_write_thinlto_key_with_llvm_err,
+ MultipleSourceDiCompileUnit => {
+ fluent::codegen_llvm_multiple_source_dicompileunit_with_llvm_err
+ }
+ PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
+ ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
+ };
+ let mut diag = self.0.into_diagnostic(sess);
+ diag.set_primary_message(msg_with_llvm_err);
+ diag.set_arg("llvm_err", self.1);
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_from_llvm_optimization_diag)]
+pub(crate) struct FromLlvmOptimizationDiag<'a> {
+ pub filename: &'a str,
+ pub line: std::ffi::c_uint,
+ pub column: std::ffi::c_uint,
+ pub pass_name: &'a str,
+ pub message: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_from_llvm_diag)]
+pub(crate) struct FromLlvmDiag {
+ pub message: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_write_bytecode)]
+pub(crate) struct WriteBytecode<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_llvm_copy_bitcode)]
+pub(crate) struct CopyBitcode {
+ pub err: std::io::Error,
+}
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(extern_types)]
#![feature(hash_raw_entry)]
+#![feature(iter_intersperse)]
#![feature(let_chains)]
-#![feature(extern_types)]
+#![feature(never_type)]
#![feature(once_cell)]
-#![feature(iter_intersperse)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
use back::write::{create_informational_target_machine, create_target_machine};
-use errors::FailParsingTargetMachineConfigToTargetMachine;
+use errors::ParseTargetMachineConfig;
pub use llvm_util::target_features;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
type Module = ModuleLlvm;
type ModuleBuffer = back::lto::ModuleBuffer;
type TargetMachine = &'static mut llvm::TargetMachine;
+ type TargetMachineError = crate::errors::LlvmError<'static>;
type ThinData = back::lto::ThinData;
type ThinBuffer = back::lto::ThinBuffer;
fn print_pass_timings(&self) {
let tm = match (cgcx.tm_factory)(tm_factory_config) {
Ok(m) => m,
Err(e) => {
- handler.emit_err(FailParsingTargetMachineConfigToTargetMachine { error: e });
- return Err(FatalError);
+ return Err(handler.emit_almost_fatal(ParseTargetMachineConfig(e)));
}
};
}
pub type TargetMachineFactoryFn<B> = Arc<
- dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
- + Send
+ dyn Fn(
+ TargetMachineFactoryConfig,
+ ) -> Result<
+ <B as WriteBackendMethods>::TargetMachine,
+ <B as WriteBackendMethods>::TargetMachineError,
+ > + Send
+ Sync,
>;
pub trait WriteBackendMethods: 'static + Sized + Clone {
type Module: Send + Sync;
type TargetMachine;
+ type TargetMachineError;
type ModuleBuffer: ModuleBufferMethods;
type ThinData: Send + Sync;
type ThinBuffer: ThinBufferMethods;
use rustc_span::symbol::sym;
use rustc_target::json::ToJson;
-use std::borrow::Cow;
use std::cmp::max;
use std::env;
use std::ffi::OsString;
handler.emit_diagnostic(&mut d);
}
- let mut xs: Vec<Cow<'static, str>> = vec![
- "the compiler unexpectedly panicked. this is a bug.".into(),
- format!("we would appreciate a bug report: {bug_report_url}").into(),
- format!(
- "rustc {} running on {}",
- util::version_str!().unwrap_or("unknown_version"),
- config::host_triple()
- )
- .into(),
- ];
+ handler.emit_note(session_diagnostics::Ice);
+ handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+ handler.emit_note(session_diagnostics::IceVersion {
+ version: util::version_str!().unwrap_or("unknown_version"),
+ triple: config::host_triple(),
+ });
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
- xs.push(format!("compiler flags: {}", flags.join(" ")).into());
-
+ handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
if excluded_cargo_defaults {
- xs.push("some of the compiler flags provided by cargo are hidden".into());
+ handler.emit_note(session_diagnostics::IceExcludeCargoDefaults);
}
}
- for note in &xs {
- handler.note_without_error(note.as_ref());
- }
-
// If backtraces are enabled, also print the query stack
let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
pub path: String,
pub err: String,
}
+
+#[derive(Diagnostic)]
+#[diag(driver_ice)]
+pub(crate) struct Ice;
+
+#[derive(Diagnostic)]
+#[diag(driver_ice_bug_report)]
+pub(crate) struct IceBugReport<'a> {
+ pub bug_report_url: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_ice_version)]
+pub(crate) struct IceVersion<'a> {
+ pub version: &'a str,
+ pub triple: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_ice_flags)]
+pub(crate) struct IceFlags {
+ pub flags: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_ice_exclude_cargo_defaults)]
+pub(crate) struct IceExcludeCargoDefaults;
cannot prefer dynamic linking when performing LTO
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
-codegen_llvm_fail_parsing_target_machine_config_to_target_machine =
+codegen_llvm_parse_target_machine_config =
failed to parse target machine config to target machine: {$error}
+
+codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
+
+codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
+
+codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
+
+codegen_llvm_write_output = could not write output to {$path}
+codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
+
+codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
+codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
+
+codegen_llvm_run_passes = failed to run LLVM passes
+codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
+
+codegen_llvm_serialize_module = failed to serialize module {$name}
+codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err}
+
+codegen_llvm_write_ir = failed to write LLVM IR to {$path}
+codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err}
+
+codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
+codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
+
+codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
+codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
+
+codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err}
+codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err}
+
+codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
+codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
+
+codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module
+codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
+
+codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
+codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
+
+codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name}: {$message}
+codegen_llvm_from_llvm_diag = {$message}
+
+codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
+
+codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
driver_rlink_no_a_file = rlink must be a file
driver_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
+
+driver_ice = the compiler unexpectedly panicked. this is a bug.
+driver_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_ice_version = rustc {$version} running on {$triple}
+driver_ice_flags = compiler flags: {$flags}
+driver_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
expand_module_multiple_candidates =
file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}"
.help = delete or rename one of them to remove the ambiguity
+
+expand_trace_macro = trace_macro
--- /dev/null
+incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
+
+incremental_missing_depnode = missing `DepNode` variant
+
+incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
+
+incremental_no_path = no path from `{$source}` to `{$target}`
+
+incremental_ok = OK
+
+incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
+
+incremental_missing_query_depgraph =
+ found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
+
+incremental_malformed_cgu_name =
+ found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
+
+incremental_no_module_named =
+ no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
+
+incremental_field_associated_value_expected = associated value expected for `{$name}`
+
+incremental_no_field = no field `{$name}`
+
+incremental_assertion_auto =
+ `except` specified DepNodes that can not be affected for \"{$name}\": \"{$e}\"
+
+incremental_undefined_clean_dirty_assertions_item =
+ clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
+
+incremental_undefined_clean_dirty_assertions =
+ clean/dirty auto-assertions not yet defined for {$kind}
+
+incremental_repeated_depnode_label = dep-node label `{$label}` is repeated
+
+incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
+
+incremental_not_dirty = `{$dep_node_str}` should be dirty but is not
+
+incremental_not_clean = `{$dep_node_str}` should be clean but is not
+
+incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not
+
+incremental_unknown_item = unknown item `{$name}`
+
+incremental_no_cfg = no cfg attribute
+
+incremental_associated_value_expected_for = associated value expected for `{$ident}`
+
+incremental_associated_value_expected = expected an associated value
+
+incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute
+
+incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err}
+
+incremental_create_new = failed to create {$name} at `{$path}`: {$err}
+
+incremental_write_new = failed to write {$name} to `{$path}`: {$err}
+
+incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err}
+
+incremental_create_incr_comp_dir =
+ could not create incremental compilation {$tag} directory `{$path}`: {$err}
+
+incremental_create_lock =
+ incremental compilation: could not create session directory lock file: {$lock_err}
+incremental_lock_unsupported =
+ the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation
+incremental_cargo_help_1 =
+ incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)
+incremental_cargo_help_2 =
+ the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)
+
+incremental_delete_lock =
+ error deleting lock file for incremental compilation session directory `{$path}`: {$err}
+
+incremental_hard_link_failed =
+ hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}`
+
+incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err}
+
+incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err}
+
+incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
+
+incremental_invalid_gc_failed =
+ failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err}
+
+incremental_finalized_gc_failed =
+ failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err}
+
+incremental_session_gc_failed =
+ failed to garbage collect incremental compilation session directory `{$path}`: {$err}
+
+incremental_assert_not_loaded =
+ we asserted that the incremental cache should not be loaded, but it was loaded
+
+incremental_assert_loaded =
+ we asserted that an existing incremental cache directory should be successfully loaded, but it was not
+
+incremental_delete_incompatible =
+ failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err}
+
+incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err}
+
+incremental_decode_incr_cache = could not decode incremental cache: {$err}
+
+incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
+
+incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err}
+
+incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
+
+incremental_copy_workproduct_to_cache =
+ error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
+
+incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
interface_proc_macro_crate_panic_abort =
building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+
+interface_unsupported_crate_type_for_target =
+ dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
+
+interface_multiple_output_types_adaption =
+ due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
+
+interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag
+
+interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
monomorphize_couldnt_dump_mono_stats =
unexpected error occurred while dumping monomorphization stats: {$error}
+
+monomorphize_encountered_error_while_instantiating =
+ the above error was encountered while instantiating `{$formatted_item}`
+
+monomorphize_unknown_cgu_collection_mode =
+ unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"`
passes_proc_macro_unsafe = proc macro functions may not be `unsafe`
+
+passes_skipping_const_checks = skipping const checks
session_invalid_int_literal_width = invalid width `{$width}` for integer literal
.help = valid widths are 8, 16, 32, 64 and 128
+
+session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
expand => "../locales/en-US/expand.ftl",
hir_analysis => "../locales/en-US/hir_analysis.ftl",
hir_typeck => "../locales/en-US/hir_typeck.ftl",
+ incremental => "../locales/en-US/incremental.ftl",
infer => "../locales/en-US/infer.ftl",
interface => "../locales/en-US/interface.ftl",
lint => "../locales/en-US/lint.ftl",
) -> (
&Level,
&[(DiagnosticMessage, Style)],
+ Vec<(&Cow<'static, str>, &DiagnosticArgValue<'static>)>,
&Option<DiagnosticId>,
&MultiSpan,
&Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
(
&self.level,
&self.message,
+ self.args().collect(),
&self.code,
&self.span,
&self.suggestions,
}
}
+impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> {
+ /// Convenience function for internal use, clients should use one of the
+ /// `struct_*` methods on [`Handler`].
+ #[track_caller]
+ pub(crate) fn new_almost_fatal(
+ handler: &'a Handler,
+ message: impl Into<DiagnosticMessage>,
+ ) -> Self {
+ let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
+ Self::new_diagnostic_almost_fatal(handler, diagnostic)
+ }
+
+ /// Creates a new `DiagnosticBuilder` with an already constructed
+ /// diagnostic.
+ pub(crate) fn new_diagnostic_almost_fatal(
+ handler: &'a Handler,
+ diagnostic: Diagnostic,
+ ) -> Self {
+ debug!("Created new diagnostic");
+ Self {
+ inner: DiagnosticBuilderInner {
+ state: DiagnosticBuilderState::Emittable(handler),
+ diagnostic: Box::new(diagnostic),
+ },
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
+ fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
+ match db.inner.state {
+ // First `.emit()` call, the `&Handler` is still available.
+ DiagnosticBuilderState::Emittable(handler) => {
+ db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
+
+ handler.emit_diagnostic(&mut db.inner.diagnostic);
+ }
+ // `.emit()` was previously called, disallowed from repeating it.
+ DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
+ }
+ // Then fatally error..
+ rustc_span::fatal_error::FatalError
+ }
+
+ fn make_diagnostic_builder(
+ handler: &Handler,
+ msg: impl Into<DiagnosticMessage>,
+ ) -> DiagnosticBuilder<'_, Self> {
+ DiagnosticBuilder::new_almost_fatal(handler, msg)
+ }
+}
+
/// In general, the `DiagnosticBuilder` uses deref to allow access to
/// the fields and methods of the embedded `diagnostic` in a
/// transparent way. *However,* many of the methods are intended to
}
}
+impl<'a, T: Clone + IntoDiagnosticArg> IntoDiagnosticArg for &'a T {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.clone().into_diagnostic_arg()
+ }
+}
+
macro_rules! into_diagnostic_arg_using_display {
($( $ty:ty ),+ $(,)?) => {
$(
}
}
-impl IntoDiagnosticArg for &ast::Path {
- fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(self)))
- }
-}
-
impl IntoDiagnosticArg for ast::token::Token {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(pprust::token_to_string(&self))
}
}
+impl IntoDiagnosticArg for std::ffi::CString {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
+ }
+}
+
+impl IntoDiagnosticArg for rustc_data_structures::small_c_str::SmallCStr {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned()))
+ }
+}
+
impl IntoDiagnosticArg for Level {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(self.to_cmd_flag()))
}
}
- /// Translate `message` eagerly with `args`.
+ /// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
pub fn eagerly_translate<'a>(
&self,
message: DiagnosticMessage,
args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
) -> SubdiagnosticMessage {
+ SubdiagnosticMessage::Eager(self.eagerly_translate_to_string(message, args))
+ }
+
+ /// Translate `message` eagerly with `args` to `String`.
+ pub fn eagerly_translate_to_string<'a>(
+ &self,
+ message: DiagnosticMessage,
+ args: impl Iterator<Item = DiagnosticArg<'a, 'static>>,
+ ) -> String {
let inner = self.inner.borrow();
let args = crate::translation::to_fluent_args(args);
- SubdiagnosticMessage::Eager(
- inner
- .emitter
- .translate_message(&message, &args)
- .map_err(Report::new)
- .unwrap()
- .to_string(),
- )
+ inner.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
}
// This is here to not allow mutation of flags;
}
#[track_caller]
+ #[rustc_lint_diagnostics]
pub fn span_note_without_error(
&self,
span: impl Into<MultiSpan>,
}
#[track_caller]
+ #[rustc_lint_diagnostics]
pub fn span_note_diag(
&self,
span: Span,
}
// NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
+ #[rustc_lint_diagnostics]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError {
self.inner.borrow_mut().fatal(msg)
}
+ #[rustc_lint_diagnostics]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.inner.borrow_mut().err(msg)
}
+ #[rustc_lint_diagnostics]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
let mut db = DiagnosticBuilder::new(self, Warning(None), msg);
db.emit();
}
+ #[rustc_lint_diagnostics]
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
DiagnosticBuilder::new(self, Note, msg).emit();
}
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
if self.inner.borrow().has_errors() { Some(ErrorGuaranteed(())) } else { None }
}
+
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
if self.inner.borrow().has_errors_or_lint_errors() {
Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
self.create_warning(warning).emit()
}
+ pub fn create_almost_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, FatalError>,
+ ) -> DiagnosticBuilder<'a, FatalError> {
+ fatal.into_diagnostic(self)
+ }
+
+ pub fn emit_almost_fatal<'a>(
+ &'a self,
+ fatal: impl IntoDiagnostic<'a, FatalError>,
+ ) -> FatalError {
+ self.create_almost_fatal(fatal).emit()
+ }
+
pub fn create_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, !>,
self.create_bug(bug).emit()
}
+ pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
+ self.create_note(note).emit()
+ }
+
+ pub fn create_note<'a>(
+ &'a self,
+ note: impl IntoDiagnostic<'a, Noted>,
+ ) -> DiagnosticBuilder<'a, Noted> {
+ note.into_diagnostic(self)
+ }
+
fn emit_diag_at_span(
&self,
mut diag: Diagnostic,
ArgumentNotAttributes, AttrNoArguments, AttributeMetaItem, AttributeSingleWord,
AttributesWrongForm, CannotBeNameOfMacro, ExpectedCommaInList, HelperAttributeNameInvalid,
MacroBodyStability, MacroConstStability, NotAMetaItem, OnlyOneArgument, OnlyOneWord,
- ResolveRelativePath, TakesNoArguments,
+ ResolveRelativePath, TakesNoArguments, TraceMacro,
};
use crate::expand::{self, AstFragment, Invocation};
use crate::module::DirOwnership;
self.sess.parse_sess.span_diagnostic.span_bug(sp, msg);
}
pub fn trace_macros_diag(&mut self) {
- for (sp, notes) in self.expansions.iter() {
- let mut db = self.sess.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
+ for (span, notes) in self.expansions.iter() {
+ let mut db = self.sess.parse_sess.create_note(TraceMacro { span: *span });
for note in notes {
db.note(note);
}
pub default_path: String,
pub secondary_path: String,
}
+
+#[derive(Diagnostic)]
+#[diag(expand_trace_macro)]
+pub struct TraceMacro {
+ #[primary_span]
+ pub span: Span,
+}
pub defaultness: Defaultness,
}
-impl TraitItem<'_> {
+impl<'hir> TraitItem<'hir> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
pub fn trait_item_id(&self) -> TraitItemId {
TraitItemId { owner_id: self.owner_id }
}
+
+ /// Expect an [`TraitItemKind::Const`] or panic.
+ #[track_caller]
+ pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option<BodyId>) {
+ let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
+ (ty, body)
+ }
+
+ /// Expect an [`TraitItemKind::Fn`] or panic.
+ #[track_caller]
+ pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) {
+ let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") };
+ (ty, trfn)
+ }
+
+ /// Expect an [`TraitItemKind::Type`] or panic.
+ #[track_caller]
+ pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) {
+ let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") };
+ (bounds, ty)
+ }
+
+ #[track_caller]
+ fn expect_failed(&self, expected: &'static str) -> ! {
+ panic!("expected {expected} item, found {self:?}")
+ }
}
/// Represents a trait method's body (or just argument names).
pub vis_span: Span,
}
-impl ImplItem<'_> {
+impl<'hir> ImplItem<'hir> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
pub fn impl_item_id(&self) -> ImplItemId {
ImplItemId { owner_id: self.owner_id }
}
+
+ /// Expect an [`ImplItemKind::Const`] or panic.
+ #[track_caller]
+ pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) {
+ let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
+ (ty, body)
+ }
+
+ /// Expect an [`ImplItemKind::Fn`] or panic.
+ #[track_caller]
+ pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) {
+ let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") };
+ (ty, *body)
+ }
+
+ /// Expect an [`ImplItemKind::Type`] or panic.
+ #[track_caller]
+ pub fn expect_type(&self) -> &'hir Ty<'hir> {
+ let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") };
+ ty
+ }
+
+ #[track_caller]
+ fn expect_failed(&self, expected: &'static str) -> ! {
+ panic!("expected {expected} item, found {self:?}")
+ }
}
/// Represents various kinds of content within an `impl`.
pub vis_span: Span,
}
-impl Item<'_> {
+impl<'hir> Item<'hir> {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
pub fn item_id(&self) -> ItemId {
ItemId { owner_id: self.owner_id }
}
+
+ /// Expect an [`ItemKind::ExternCrate`] or panic.
+ #[track_caller]
+ pub fn expect_extern_crate(&self) -> Option<Symbol> {
+ let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") };
+ s
+ }
+
+ /// Expect an [`ItemKind::Use`] or panic.
+ #[track_caller]
+ pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) {
+ let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") };
+ (p, uk)
+ }
+
+ /// Expect an [`ItemKind::Static`] or panic.
+ #[track_caller]
+ pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) {
+ let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") };
+ (ty, mutbl, body)
+ }
+ /// Expect an [`ItemKind::Const`] or panic.
+ #[track_caller]
+ pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) {
+ let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
+ (ty, body)
+ }
+ /// Expect an [`ItemKind::Fn`] or panic.
+ #[track_caller]
+ pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) {
+ let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") };
+ (sig, gen, *body)
+ }
+
+ /// Expect an [`ItemKind::Macro`] or panic.
+ #[track_caller]
+ pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) {
+ let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") };
+ (def, *mk)
+ }
+
+ /// Expect an [`ItemKind::Mod`] or panic.
+ #[track_caller]
+ pub fn expect_mod(&self) -> &'hir Mod<'hir> {
+ let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") };
+ m
+ }
+
+ /// Expect an [`ItemKind::ForeignMod`] or panic.
+ #[track_caller]
+ pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) {
+ let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") };
+ (abi, items)
+ }
+
+ /// Expect an [`ItemKind::GlobalAsm`] or panic.
+ #[track_caller]
+ pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> {
+ let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") };
+ asm
+ }
+
+ /// Expect an [`ItemKind::TyAlias`] or panic.
+ #[track_caller]
+ pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) {
+ let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") };
+ (ty, gen)
+ }
+
+ /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
+ /// Expect an [`ItemKind::OpaqueTy`] or panic.
+ #[track_caller]
+ pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> {
+ let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") };
+ ty
+ }
+
+ /// Expect an [`ItemKind::Enum`] or panic.
+ #[track_caller]
+ pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) {
+ let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") };
+ (def, gen)
+ }
+
+ /// Expect an [`ItemKind::Struct`] or panic.
+ #[track_caller]
+ pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) {
+ let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") };
+ (data, gen)
+ }
+
+ /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
+ /// Expect an [`ItemKind::Union`] or panic.
+ #[track_caller]
+ pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) {
+ let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") };
+ (data, gen)
+ }
+
+ /// Expect an [`ItemKind::Trait`] or panic.
+ #[track_caller]
+ pub fn expect_trait(
+ self,
+ ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) {
+ let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") };
+ (is_auto, unsafety, gen, bounds, items)
+ }
+
+ /// Expect an [`ItemKind::TraitAlias`] or panic.
+ #[track_caller]
+ pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) {
+ let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") };
+ (gen, bounds)
+ }
+
+ /// Expect an [`ItemKind::Impl`] or panic.
+ #[track_caller]
+ pub fn expect_impl(&self) -> &'hir Impl<'hir> {
+ let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") };
+ imp
+ }
+
+ #[track_caller]
+ fn expect_failed(&self, expected: &'static str) -> ! {
+ panic!("expected {expected} item, found {self:?}")
+ }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None }
}
+
+ /// Expect a [`Node::Param`] or panic.
+ #[track_caller]
+ pub fn expect_param(self) -> &'hir Param<'hir> {
+ let Node::Param(this) = self else { self.expect_failed("a parameter") };
+ this
+ }
+
+ /// Expect a [`Node::Item`] or panic.
+ #[track_caller]
+ pub fn expect_item(self) -> &'hir Item<'hir> {
+ let Node::Item(this) = self else { self.expect_failed("a item") };
+ this
+ }
+
+ /// Expect a [`Node::ForeignItem`] or panic.
+ #[track_caller]
+ pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> {
+ let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") };
+ this
+ }
+
+ /// Expect a [`Node::TraitItem`] or panic.
+ #[track_caller]
+ pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> {
+ let Node::TraitItem(this) = self else { self.expect_failed("a trait item") };
+ this
+ }
+
+ /// Expect a [`Node::ImplItem`] or panic.
+ #[track_caller]
+ pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> {
+ let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") };
+ this
+ }
+
+ /// Expect a [`Node::Variant`] or panic.
+ #[track_caller]
+ pub fn expect_variant(self) -> &'hir Variant<'hir> {
+ let Node::Variant(this) = self else { self.expect_failed("a variant") };
+ this
+ }
+
+ /// Expect a [`Node::Field`] or panic.
+ #[track_caller]
+ pub fn expect_field(self) -> &'hir FieldDef<'hir> {
+ let Node::Field(this) = self else { self.expect_failed("a field definition") };
+ this
+ }
+
+ /// Expect a [`Node::AnonConst`] or panic.
+ #[track_caller]
+ pub fn expect_anon_const(self) -> &'hir AnonConst {
+ let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") };
+ this
+ }
+
+ /// Expect a [`Node::Expr`] or panic.
+ #[track_caller]
+ pub fn expect_expr(self) -> &'hir Expr<'hir> {
+ let Node::Expr(this) = self else { self.expect_failed("an expression") };
+ this
+ }
+ /// Expect a [`Node::ExprField`] or panic.
+ #[track_caller]
+ pub fn expect_expr_field(self) -> &'hir ExprField<'hir> {
+ let Node::ExprField(this) = self else { self.expect_failed("an expression field") };
+ this
+ }
+
+ /// Expect a [`Node::Stmt`] or panic.
+ #[track_caller]
+ pub fn expect_stmt(self) -> &'hir Stmt<'hir> {
+ let Node::Stmt(this) = self else { self.expect_failed("a statement") };
+ this
+ }
+
+ /// Expect a [`Node::PathSegment`] or panic.
+ #[track_caller]
+ pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> {
+ let Node::PathSegment(this) = self else { self.expect_failed("a path segment") };
+ this
+ }
+
+ /// Expect a [`Node::Ty`] or panic.
+ #[track_caller]
+ pub fn expect_ty(self) -> &'hir Ty<'hir> {
+ let Node::Ty(this) = self else { self.expect_failed("a type") };
+ this
+ }
+
+ /// Expect a [`Node::TypeBinding`] or panic.
+ #[track_caller]
+ pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> {
+ let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") };
+ this
+ }
+
+ /// Expect a [`Node::TraitRef`] or panic.
+ #[track_caller]
+ pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> {
+ let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") };
+ this
+ }
+
+ /// Expect a [`Node::Pat`] or panic.
+ #[track_caller]
+ pub fn expect_pat(self) -> &'hir Pat<'hir> {
+ let Node::Pat(this) = self else { self.expect_failed("a pattern") };
+ this
+ }
+
+ /// Expect a [`Node::PatField`] or panic.
+ #[track_caller]
+ pub fn expect_pat_field(self) -> &'hir PatField<'hir> {
+ let Node::PatField(this) = self else { self.expect_failed("a pattern field") };
+ this
+ }
+
+ /// Expect a [`Node::Arm`] or panic.
+ #[track_caller]
+ pub fn expect_arm(self) -> &'hir Arm<'hir> {
+ let Node::Arm(this) = self else { self.expect_failed("an arm") };
+ this
+ }
+
+ /// Expect a [`Node::Block`] or panic.
+ #[track_caller]
+ pub fn expect_block(self) -> &'hir Block<'hir> {
+ let Node::Block(this) = self else { self.expect_failed("a block") };
+ this
+ }
+
+ /// Expect a [`Node::Local`] or panic.
+ #[track_caller]
+ pub fn expect_local(self) -> &'hir Local<'hir> {
+ let Node::Local(this) = self else { self.expect_failed("a local") };
+ this
+ }
+
+ /// Expect a [`Node::Ctor`] or panic.
+ #[track_caller]
+ pub fn expect_ctor(self) -> &'hir VariantData<'hir> {
+ let Node::Ctor(this) = self else { self.expect_failed("a constructor") };
+ this
+ }
+
+ /// Expect a [`Node::Lifetime`] or panic.
+ #[track_caller]
+ pub fn expect_lifetime(self) -> &'hir Lifetime {
+ let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") };
+ this
+ }
+
+ /// Expect a [`Node::GenericParam`] or panic.
+ #[track_caller]
+ pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> {
+ let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") };
+ this
+ }
+
+ /// Expect a [`Node::Crate`] or panic.
+ #[track_caller]
+ pub fn expect_crate(self) -> &'hir Mod<'hir> {
+ let Node::Crate(this) = self else { self.expect_failed("a crate") };
+ this
+ }
+
+ /// Expect a [`Node::Infer`] or panic.
+ #[track_caller]
+ pub fn expect_infer(self) -> &'hir InferArg {
+ let Node::Infer(this) = self else { self.expect_failed("an infer") };
+ this
+ }
+
+ #[track_caller]
+ fn expect_failed(&self, expected: &'static str) -> ! {
+ panic!("expected {expected} node, found {self:?}")
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
hir.get(fn_hir_id) else { return None };
- let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
- hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") };
+ let i = hir.get_parent(fn_hir_id).expect_item().expect_impl();
let trait_ref = self.instantiate_mono_trait_ref(
i.of_trait.as_ref()?,
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
-use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
+use rustc_hir::{GenericParamKind, ImplItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
// span points only at the type `Box<Self`>, but we want to cover the whole
// argument pattern and type.
- let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") };
+ let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
let span = tcx
.hir()
.body_param_names(body)
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
let mut impl_args = {
- let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+ let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
};
let trait_args = trait_m.def_id.as_local().map(|def_id| {
- let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) };
+ let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn();
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
});
.def_id
.as_local()
.and_then(|def_id| {
- let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) };
+ let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn();
let pos = trait_number_args.saturating_sub(1);
trait_m_sig.decl.inputs.get(pos).map(|arg| {
if pos == 0 {
})
.or(trait_item_span);
- let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) };
+ let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn();
let pos = impl_number_args.saturating_sub(1);
let impl_span = impl_m_sig
.decl
let _: Option<_> = try {
let impl_m = impl_m.def_id.as_local()?;
let impl_m = tcx.hir().expect_impl_item(impl_m);
- let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() };
+ let (sig, _) = impl_m.expect_fn();
let input_tys = sig.decl.inputs;
struct Visitor(Option<Span>, hir::def_id::LocalDefId);
);
// Locate the Span containing just the type of the offending impl
- let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") };
+ let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const();
cause.span = ty.span;
let mut diag = struct_span_err!(
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
// Add a label to the Span containing just the type of the const
- let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") };
+ let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const();
ty.span
});
// All field types must be well-formed.
for field in &variant.fields {
let field_id = field.did.expect_local();
- let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
- else { bug!() };
+ let hir::FieldDef { ty: hir_ty, .. } =
+ tcx.hir().get_by_def_id(field_id).expect_field();
let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_wf_obligation(
hir_ty.span,
{
let last = idx == variant.fields.len() - 1;
let field_id = field.did.expect_local();
- let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
- else { bug!() };
+ let hir::FieldDef { ty: hir_ty, .. } =
+ tcx.hir().get_by_def_id(field_id).expect_field();
let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_bound(
traits::ObligationCause::new(
if item.span.is_dummy() {
continue;
}
- let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
+ let (path, _) = item.expect_use();
let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
format!("unused import: `{}`", snippet)
} else {
_ => {}
}
- let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") };
+ let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
}
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_hir::def::DefKind;
use rustc_hir::Unsafety;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::LocalDefId;
pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl));
let item = tcx.hir().expect_item(def_id);
- let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
+ let impl_ = item.expect_impl();
if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_ref = trait_ref.subst_identity();
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::EarlyBinder<ty::TraitRef<'_>>> {
let icx = ItemCtxt::new(tcx, def_id);
- let item = tcx.hir().expect_item(def_id.expect_local());
- let hir::ItemKind::Impl(impl_) = item.kind else { bug!() };
+ let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl();
impl_
.of_trait
.as_ref()
//! fn baz() { foo(); }
//! ```
+use crate::errors;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING};
Some(n) => {
match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
- }
+ Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode {
+ span: attr.span,
+ name: n,
+ }),
}
}
};
Some(n) => {
match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
Ok(n) => n,
- Err(()) => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unrecognized DepNode variant {:?}", n),
- );
- }
+ Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode {
+ span: attr.span,
+ name: n,
+ }),
}
}
None => {
- self.tcx.sess.span_fatal(attr.span, "missing DepNode variant");
+ self.tcx.sess.emit_fatal(errors::MissingDepNode { span: attr.span });
}
};
self.then_this_would_need.push((
// Return early here so as not to construct the query, which is not cheap.
if if_this_changed.is_empty() {
for &(target_span, _, _, _) in then_this_would_need {
- tcx.sess.span_err(target_span, "no `#[rustc_if_this_changed]` annotation detected");
+ tcx.sess.emit_err(errors::MissingIfThisChanged { span: target_span });
}
return;
}
let dependents = query.transitive_predecessors(source_dep_node);
for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
if !dependents.contains(&target_dep_node) {
- tcx.sess.span_err(
- target_span,
- &format!(
- "no path from `{}` to `{}`",
- tcx.def_path_str(source_def_id),
- target_pass
- ),
- );
+ tcx.sess.emit_err(errors::NoPath {
+ span: target_span,
+ source: tcx.def_path_str(source_def_id),
+ target: *target_pass,
+ });
} else {
- tcx.sess.span_err(target_span, "OK");
+ tcx.sess.emit_err(errors::Ok { span: target_span });
}
}
}
//! allows for doing a more fine-grained check to see if pre- or post-lto data
//! was re-used.
+use crate::errors;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::LOCAL_CRATE;
sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
other => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unknown cgu-reuse-kind `{}` specified", other),
- );
+ self.tcx
+ .sess
+ .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other });
}
}
} else {
};
if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
- self.tcx.sess.span_fatal(
- attr.span,
- "found CGU-reuse attribute but `-Zquery-dep-graph` was not specified",
- );
+ self.tcx.sess.emit_fatal(errors::MissingQueryDepGraph { span: attr.span });
}
if !self.check_config(attr) {
let crate_name = self.tcx.crate_name(LOCAL_CRATE).to_string();
if !user_path.starts_with(&crate_name) {
- let msg = format!(
- "Found malformed codegen unit name `{}`. \
- Codegen units names must always start with the name of the \
- crate (`{}` in this case).",
- user_path, crate_name
- );
- self.tcx.sess.span_fatal(attr.span, &msg);
+ self.tcx.sess.emit_fatal(errors::MalformedCguName {
+ span: attr.span,
+ user_path,
+ crate_name,
+ });
}
// Split of the "special suffix" if there is one.
let mut cgu_names: Vec<&str> =
self.available_cgus.iter().map(|cgu| cgu.as_str()).collect();
cgu_names.sort();
- self.tcx.sess.span_err(
- attr.span,
- &format!(
- "no module named `{}` (mangled: {}). Available modules: {}",
- user_path,
- cgu_name,
- cgu_names.join(", ")
- ),
- );
+ self.tcx.sess.emit_err(errors::NoModuleNamed {
+ span: attr.span,
+ user_path,
+ cgu_name,
+ cgu_names: cgu_names.join(", "),
+ });
}
self.tcx.sess.cgu_reuse_tracker.set_expectation(
if let Some(value) = item.value_str() {
return value;
} else {
- self.tcx.sess.span_fatal(
- item.span(),
- &format!("associated value expected for `{}`", name),
- );
+ self.tcx.sess.emit_fatal(errors::FieldAssociatedValueExpected {
+ span: item.span(),
+ name,
+ });
}
}
}
- self.tcx.sess.span_fatal(attr.span, &format!("no field `{}`", name));
+ self.tcx.sess.emit_fatal(errors::NoField { span: attr.span, name });
}
/// Scan for a `cfg="foo"` attribute and check whether we have a
--- /dev/null
+use rustc_macros::Diagnostic;
+use rustc_span::{symbol::Ident, Span, Symbol};
+use std::path::{Path, PathBuf};
+
+#[derive(Diagnostic)]
+#[diag(incremental_unrecognized_depnode)]
+pub struct UnrecognizedDepNode {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_missing_depnode)]
+pub struct MissingDepNode {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_missing_if_this_changed)]
+pub struct MissingIfThisChanged {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_ok)]
+pub struct Ok {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_no_path)]
+pub struct NoPath {
+ #[primary_span]
+ pub span: Span,
+ pub target: Symbol,
+ pub source: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_unknown_reuse_kind)]
+pub struct UnknownReuseKind {
+ #[primary_span]
+ pub span: Span,
+ pub kind: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_missing_query_depgraph)]
+pub struct MissingQueryDepGraph {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_malformed_cgu_name)]
+pub struct MalformedCguName {
+ #[primary_span]
+ pub span: Span,
+ pub user_path: String,
+ pub crate_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_no_module_named)]
+pub struct NoModuleNamed<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub user_path: &'a str,
+ pub cgu_name: Symbol,
+ pub cgu_names: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_field_associated_value_expected)]
+pub struct FieldAssociatedValueExpected {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_no_field)]
+pub struct NoField {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_assertion_auto)]
+pub struct AssertionAuto<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub name: &'a str,
+ pub e: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_undefined_clean_dirty_assertions_item)]
+pub struct UndefinedCleanDirtyItem {
+ #[primary_span]
+ pub span: Span,
+ pub kind: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_undefined_clean_dirty_assertions)]
+pub struct UndefinedCleanDirty {
+ #[primary_span]
+ pub span: Span,
+ pub kind: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_repeated_depnode_label)]
+pub struct RepeatedDepNodeLabel<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub label: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_unrecognized_depnode_label)]
+pub struct UnrecognizedDepNodeLabel<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub label: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_not_dirty)]
+pub struct NotDirty<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub dep_node_str: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_not_clean)]
+pub struct NotClean<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub dep_node_str: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_not_loaded)]
+pub struct NotLoaded<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub dep_node_str: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_unknown_item)]
+pub struct UnknownItem {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_no_cfg)]
+pub struct NoCfg {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_associated_value_expected_for)]
+pub struct AssociatedValueExpectedFor {
+ #[primary_span]
+ pub span: Span,
+ pub ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_associated_value_expected)]
+pub struct AssociatedValueExpected {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_unchecked_clean)]
+pub struct UncheckedClean {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_old)]
+pub struct DeleteOld<'a> {
+ pub name: &'a str,
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_create_new)]
+pub struct CreateNew<'a> {
+ pub name: &'a str,
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_write_new)]
+pub struct WriteNew<'a> {
+ pub name: &'a str,
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_canonicalize_path)]
+pub struct CanonicalizePath {
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_create_incr_comp_dir)]
+pub struct CreateIncrCompDir<'a> {
+ pub tag: &'a str,
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_create_lock)]
+pub struct CreateLock<'a> {
+ pub lock_err: std::io::Error,
+ pub session_dir: &'a Path,
+ #[note(incremental_lock_unsupported)]
+ pub is_unsupported_lock: Option<()>,
+ #[help(incremental_cargo_help_1)]
+ #[help(incremental_cargo_help_2)]
+ pub is_cargo: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_lock)]
+pub struct DeleteLock<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_hard_link_failed)]
+pub struct HardLinkFailed<'a> {
+ pub path: &'a Path,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_partial)]
+pub struct DeletePartial<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_full)]
+pub struct DeleteFull<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_finalize)]
+pub struct Finalize<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_invalid_gc_failed)]
+pub struct InvalidGcFailed<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_finalized_gc_failed)]
+pub struct FinalizedGcFailed<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_session_gc_failed)]
+pub struct SessionGcFailed<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_assert_not_loaded)]
+pub struct AssertNotLoaded;
+
+#[derive(Diagnostic)]
+#[diag(incremental_assert_loaded)]
+pub struct AssertLoaded;
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_incompatible)]
+pub struct DeleteIncompatible {
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_load_dep_graph)]
+pub struct LoadDepGraph {
+ pub path: PathBuf,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_decode_incr_cache)]
+pub struct DecodeIncrCache {
+ pub err: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_write_dep_graph)]
+pub struct WriteDepGraph<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_move_dep_graph)]
+pub struct MoveDepGraph<'a> {
+ pub from: &'a Path,
+ pub to: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_create_dep_graph)]
+pub struct CreateDepGraph<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_copy_workproduct_to_cache)]
+pub struct CopyWorkProductToCache<'a> {
+ pub from: &'a Path,
+ pub to: &'a Path,
+ pub err: std::io::Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(incremental_delete_workproduct)]
+pub struct DeleteWorkProduct<'a> {
+ pub path: &'a Path,
+ pub err: std::io::Error,
+}
#![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
extern crate rustc_middle;
mod assert_dep_graph;
pub mod assert_module_sources;
+mod errors;
mod persist;
use assert_dep_graph::assert_dep_graph;
//! Errors are reported if we are in the suitable configuration but
//! the required condition is not met.
+use crate::errors;
use rustc_ast::{self as ast, Attribute, NestedMetaItem};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::LocalDefId;
let loaded_from_disk = self.loaded_from_disk(attr);
for e in except.iter() {
if !auto.remove(e) {
- let msg = format!(
- "`except` specified DepNodes that can not be affected for \"{}\": \"{}\"",
- name, e
- );
- self.tcx.sess.span_fatal(attr.span, &msg);
+ self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
}
}
Assertion { clean: auto, dirty: except, loaded_from_disk }
// An implementation, eg `impl<A> Trait for Foo { .. }`
HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
- _ => self.tcx.sess.span_fatal(
- attr.span,
- &format!(
- "clean/dirty auto-assertions not yet defined \
- for Node::Item.node={:?}",
- item.kind
- ),
- ),
+ _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirtyItem {
+ span: attr.span,
+ kind: format!("{:?}", item.kind),
+ }),
}
}
HirNode::TraitItem(item) => match item.kind {
ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
},
- _ => self.tcx.sess.span_fatal(
- attr.span,
- &format!("clean/dirty auto-assertions not yet defined for {:?}", node),
- ),
+ _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirty {
+ span: attr.span,
+ kind: format!("{:?}", node),
+ }),
};
let labels =
Labels::from_iter(labels.iter().flat_map(|s| s.iter().map(|l| (*l).to_string())));
let label = label.trim();
if DepNode::has_label_string(label) {
if out.contains(label) {
- self.tcx.sess.span_fatal(
- item.span(),
- &format!("dep-node label `{}` is repeated", label),
- );
+ self.tcx
+ .sess
+ .emit_fatal(errors::RepeatedDepNodeLabel { span: item.span(), label });
}
out.insert(label.to_string());
} else {
self.tcx
.sess
- .span_fatal(item.span(), &format!("dep-node label `{}` not recognized", label));
+ .emit_fatal(errors::UnrecognizedDepNodeLabel { span: item.span(), label });
}
}
out
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx
.sess
- .span_err(item_span, &format!("`{}` should be dirty but is not", dep_node_str));
+ .emit_err(errors::NotDirty { span: item_span, dep_node_str: &dep_node_str });
}
}
let dep_node_str = self.dep_node_str(&dep_node);
self.tcx
.sess
- .span_err(item_span, &format!("`{}` should be clean but is not", dep_node_str));
+ .emit_err(errors::NotClean { span: item_span, dep_node_str: &dep_node_str });
}
}
if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
let dep_node_str = self.dep_node_str(&dep_node);
- self.tcx.sess.span_err(
- item_span,
- &format!("`{}` should have been loaded from disk but it was not", dep_node_str),
- );
+ self.tcx
+ .sess
+ .emit_err(errors::NotLoaded { span: item_span, dep_node_str: &dep_node_str });
}
}
debug!("check_config: searching for cfg {:?}", value);
cfg = Some(config.contains(&(value, None)));
} else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
- tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
+ tcx.sess.emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() });
}
}
match cfg {
- None => tcx.sess.span_fatal(attr.span, "no cfg attribute"),
+ None => tcx.sess.emit_fatal(errors::NoCfg { span: attr.span }),
Some(c) => c,
}
}
if let Some(value) = item.value_str() {
value
} else {
- let msg = if let Some(ident) = item.ident() {
- format!("associated value expected for `{}`", ident)
+ if let Some(ident) = item.ident() {
+ tcx.sess.emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident });
} else {
- "expected an associated value".to_string()
- };
-
- tcx.sess.span_fatal(item.span(), &msg);
+ tcx.sess.emit_fatal(errors::AssociatedValueExpected { span: item.span() });
+ }
}
}
fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
for attr in &self.found_attrs {
if !checked_attrs.contains(&attr.id) {
- self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
+ self.tcx.sess.emit_err(errors::UncheckedClean { span: attr.span });
checked_attrs.insert(attr.id);
}
}
//! compiler versions don't change frequently for the typical user, being
//! conservative here practically has no downside.
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
+use crate::errors;
use rustc_data_structures::memmap::Mmap;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encoder;
use rustc_session::Session;
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
/// The first few bytes of files generated by incremental compilation.
const FILE_MAGIC: &[u8] = b"RSIC";
}
Err(err) if err.kind() == io::ErrorKind::NotFound => (),
Err(err) => {
- sess.err(&format!(
- "unable to delete old {} at `{}`: {}",
- name,
- path_buf.display(),
- err
- ));
+ sess.emit_err(errors::DeleteOld { name, path: path_buf, err });
return;
}
}
let mut encoder = match FileEncoder::new(&path_buf) {
Ok(encoder) => encoder,
Err(err) => {
- sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
+ sess.emit_err(errors::CreateNew { name, path: path_buf, err });
return;
}
};
debug!("save: data written to disk successfully");
}
Err(err) => {
- sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
+ sess.emit_err(errors::WriteNew { name, path: path_buf, err });
}
}
}
//! unsupported file system and emit a warning in that case. This is not yet
//! implemented.
+use crate::errors;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::{base_n, flock};
let crate_dir = match crate_dir.canonicalize() {
Ok(v) => v,
Err(err) => {
- let reported = sess.err(&format!(
- "incremental compilation: error canonicalizing path `{}`: {}",
- crate_dir.display(),
- err
- ));
- return Err(reported);
+ return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
}
};
debug!("successfully copied data from: {}", source_directory.display());
if !allows_links {
- sess.warn(&format!(
- "Hard linking files in the incremental \
- compilation cache failed. Copying files \
- instead. Consider moving the cache \
- directory to a file system which supports \
- hard linking in session dir `{}`",
- session_dir.display()
- ));
+ sess.emit_warning(errors::HardLinkFailed { path: &session_dir });
}
sess.init_incr_comp_session(session_dir, directory_lock, true);
// Try to remove the session directory we just allocated. We don't
// know if there's any garbage in it from the failed copy action.
if let Err(err) = safe_remove_dir_all(&session_dir) {
- sess.warn(&format!(
- "Failed to delete partly initialized \
- session dir `{}`: {}",
- session_dir.display(),
- err
- ));
+ sess.emit_warning(errors::DeletePartial { path: &session_dir, err });
}
delete_session_dir_lock_file(sess, &lock_file_path);
);
if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) {
- sess.warn(&format!(
- "Error deleting incremental compilation \
- session directory `{}`: {}",
- incr_comp_session_dir.display(),
- err
- ));
+ sess.emit_warning(errors::DeleteFull { path: &incr_comp_session_dir, err });
}
let lock_file_path = lock_file_path(&*incr_comp_session_dir);
}
Err(e) => {
// Warn about the error. However, no need to abort compilation now.
- sess.warn(&format!(
- "Error finalizing incremental compilation \
- session directory `{}`: {}",
- incr_comp_session_dir.display(),
- e
- ));
+ sess.emit_warning(errors::Finalize { path: &incr_comp_session_dir, err: e });
debug!("finalize_session_directory() - error, marking as invalid");
// Drop the file lock, so we can garage collect
debug!("{} directory created successfully", dir_tag);
Ok(())
}
- Err(err) => {
- let reported = sess.err(&format!(
- "Could not create incremental compilation {} \
- directory `{}`: {}",
- dir_tag,
- path.display(),
- err
- ));
- Err(reported)
- }
+ Err(err) => Err(sess.emit_err(errors::CreateIncrCompDir { tag: dir_tag, path, err })),
}
}
// the lock should be exclusive
Ok(lock) => Ok((lock, lock_file_path)),
Err(lock_err) => {
- let mut err = sess.struct_err(&format!(
- "incremental compilation: could not create \
- session directory lock file: {}",
- lock_err
- ));
- if flock::Lock::error_unsupported(&lock_err) {
- err.note(&format!(
- "the filesystem for the incremental path at {} \
- does not appear to support locking, consider changing the \
- incremental path to a filesystem that supports locking \
- or disable incremental compilation",
- session_dir.display()
- ));
- if std::env::var_os("CARGO").is_some() {
- err.help(
- "incremental compilation can be disabled by setting the \
- environment variable CARGO_INCREMENTAL=0 (see \
- https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)",
- );
- err.help(
- "the entire build directory can be changed to a different \
- filesystem by setting the environment variable CARGO_TARGET_DIR \
- to a different path (see \
- https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)",
- );
- }
- }
- Err(err.emit())
+ let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err).then_some(());
+ Err(sess.emit_err(errors::CreateLock {
+ lock_err,
+ session_dir,
+ is_unsupported_lock,
+ is_cargo: std::env::var_os("CARGO").map(|_| ()),
+ }))
}
}
}
fn delete_session_dir_lock_file(sess: &Session, lock_file_path: &Path) {
if let Err(err) = safe_remove_file(&lock_file_path) {
- sess.warn(&format!(
- "Error deleting lock file for incremental \
- compilation session directory `{}`: {}",
- lock_file_path.display(),
- err
- ));
+ sess.emit_warning(errors::DeleteLock { path: lock_file_path, err });
}
}
if !lock_file_to_session_dir.values().any(|dir| *dir == directory_name) {
let path = crate_directory.join(directory_name);
if let Err(err) = safe_remove_dir_all(&path) {
- sess.warn(&format!(
- "Failed to garbage collect invalid incremental \
- compilation session directory `{}`: {}",
- path.display(),
- err
- ));
+ sess.emit_warning(errors::InvalidGcFailed { path: &path, err });
}
}
}
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
if let Err(err) = safe_remove_dir_all(&path) {
- sess.warn(&format!(
- "Failed to garbage collect finalized incremental \
- compilation session directory `{}`: {}",
- path.display(),
- err
- ));
+ sess.emit_warning(errors::FinalizedGcFailed { path: &path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(&path));
}
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
if let Err(err) = safe_remove_dir_all(&path) {
- sess.warn(&format!(
- "Failed to garbage collect incremental compilation session directory `{}`: {}",
- path.display(),
- err
- ));
+ sess.emit_warning(errors::SessionGcFailed { path: &path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(&path));
}
//! Code to save/load the dep-graph from files.
+use crate::errors;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_serialize::Decodable;
use rustc_session::config::IncrementalStateAssertion;
use rustc_session::Session;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use super::data::*;
use super::file_format;
},
/// The file either didn't exist or was produced by an incompatible compiler version.
DataOutOfDate,
- /// An error occurred.
- Error {
- #[allow(missing_docs)]
- message: String,
- },
+ /// Loading the dep graph failed.
+ LoadDepGraph(PathBuf, std::io::Error),
+ /// Decoding loaded incremental cache failed.
+ DecodeIncrCache(Box<dyn std::any::Any + Send>),
}
impl<T: Default> LoadResult<T> {
// Check for errors when using `-Zassert-incremental-state`
match (sess.opts.assert_incr_state, &self) {
(Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
- sess.fatal(
- "We asserted that the incremental cache should not be loaded, \
- but it was loaded.",
- );
+ sess.emit_fatal(errors::AssertNotLoaded);
}
(
Some(IncrementalStateAssertion::Loaded),
- LoadResult::Error { .. } | LoadResult::DataOutOfDate,
+ LoadResult::LoadDepGraph(..)
+ | LoadResult::DecodeIncrCache(..)
+ | LoadResult::DataOutOfDate,
) => {
- sess.fatal(
- "We asserted that an existing incremental cache directory should \
- be successfully loaded, but it was not.",
- );
+ sess.emit_fatal(errors::AssertLoaded);
}
_ => {}
};
match self {
- LoadResult::Error { message } => {
- sess.warn(&message);
+ LoadResult::LoadDepGraph(path, err) => {
+ sess.emit_warning(errors::LoadDepGraph { path, err });
+ Default::default()
+ }
+ LoadResult::DecodeIncrCache(err) => {
+ sess.emit_warning(errors::DecodeIncrCache { err: format!("{err:?}") });
Default::default()
}
LoadResult::DataOutOfDate => {
if let Err(err) = delete_all_session_dir_contents(sess) {
- sess.err(&format!(
- "Failed to delete invalidated or incompatible \
- incremental compilation session directory contents `{}`: {}.",
- dep_graph_path(sess).display(),
- err
- ));
+ sess.emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
}
Default::default()
}
// compiler version. Neither is an error.
LoadResult::DataOutOfDate
}
- Err(err) => LoadResult::Error {
- message: format!("could not load dep-graph from `{}`: {}", path.display(), err),
- },
+ Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err),
}
}
pub fn open(self) -> LoadResult<T> {
match self {
MaybeAsync::Sync(result) => result,
- MaybeAsync::Async(handle) => handle.join().unwrap_or_else(|e| LoadResult::Error {
- message: format!("could not decode incremental cache: {:?}", e),
- }),
+ MaybeAsync::Async(handle) => {
+ handle.join().unwrap_or_else(|e| LoadResult::DecodeIncrCache(e))
+ }
}
}
}
match load_data(report_incremental_info, &path, nightly_build) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
- LoadResult::Error { message } => LoadResult::Error { message },
+ LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
+ LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err),
LoadResult::Ok { data: (bytes, start_pos) } => {
let mut decoder = MemDecoder::new(&bytes, start_pos);
let prev_commandline_args_hash = u64::decode(&mut decoder);
+use crate::errors;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::join;
use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
move || {
sess.time("incr_comp_persist_dep_graph", || {
if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
- sess.err(&format!(
- "failed to write dependency graph to `{}`: {}",
- staging_dep_graph_path.display(),
- err
- ));
+ sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
}
if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
- sess.err(&format!(
- "failed to move dependency graph from `{}` to `{}`: {}",
- staging_dep_graph_path.display(),
- dep_graph_path.display(),
- err
- ));
+ sess.emit_err(errors::MoveDepGraph {
+ from: &staging_dep_graph_path,
+ to: &dep_graph_path,
+ err,
+ });
}
});
},
let mut encoder = match FileEncoder::new(&path_buf) {
Ok(encoder) => encoder,
Err(err) => {
- sess.err(&format!(
- "failed to create dependency graph at `{}`: {}",
- path_buf.display(),
- err
- ));
+ sess.emit_err(errors::CreateDepGraph { path: &path_buf, err });
return None;
}
};
//!
//! [work products]: WorkProduct
+use crate::errors;
use crate::persist::fs::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_fs_util::link_or_copy;
let _ = saved_files.insert(ext.to_string(), file_name);
}
Err(err) => {
- sess.warn(&format!(
- "error copying object file `{}` to incremental directory as `{}`: {}",
- path.display(),
- path_in_incr_dir.display(),
- err
- ));
+ sess.emit_warning(errors::CopyWorkProductToCache {
+ from: &path,
+ to: &path_in_incr_dir,
+ err,
+ });
}
}
}
for (_, path) in &work_product.saved_files {
let path = in_incr_comp_dir_sess(sess, path);
if let Err(err) = std_fs::remove_file(&path) {
- sess.warn(&format!(
- "file-system error deleting outdated file `{}`: {}",
- path.display(),
- err
- ));
+ sess.emit_warning(errors::DeleteWorkProduct { path: &path, err });
}
}
}
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
-[dev-dependencies]
-rustc_target = { path = "../rustc_target" }
-
[features]
llvm = ['rustc_codegen_llvm']
rustc_use_parallel_compiler = ['rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler']
use rustc_macros::Diagnostic;
+use rustc_session::config::CrateType;
use rustc_span::{Span, Symbol};
+use rustc_target::spec::TargetTriple;
use std::io;
use std::path::Path;
#[derive(Diagnostic)]
#[diag(interface_proc_macro_crate_panic_abort)]
pub struct ProcMacroCratePanicAbort;
+
+#[derive(Diagnostic)]
+#[diag(interface_unsupported_crate_type_for_target)]
+pub struct UnsupportedCrateTypeForTarget<'a> {
+ pub crate_type: CrateType,
+ pub target_triple: &'a TargetTriple,
+}
+
+#[derive(Diagnostic)]
+#[diag(interface_multiple_output_types_adaption)]
+pub struct MultipleOutputTypesAdaption;
+
+#[derive(Diagnostic)]
+#[diag(interface_ignoring_extra_filename)]
+pub struct IgnoringExtraFilename;
+
+#[derive(Diagnostic)]
+#[diag(interface_ignoring_out_dir)]
+pub struct IgnoringOutDir;
+use crate::errors;
use info;
use libloading::Library;
use rustc_ast as ast;
}
base.retain(|crate_type| {
- let res = !output::invalid_output_for_target(session, *crate_type);
-
- if !res {
- session.warn(&format!(
- "dropping unsupported crate type `{}` for target `{}`",
- *crate_type, session.opts.target_triple
- ));
+ if output::invalid_output_for_target(session, *crate_type) {
+ session.emit_warning(errors::UnsupportedCrateTypeForTarget {
+ crate_type: *crate_type,
+ target_triple: &session.opts.target_triple,
+ });
+ false
+ } else {
+ true
}
-
- res
});
base
let unnamed_output_types =
sess.opts.output_types.values().filter(|a| a.is_none()).count();
let ofile = if unnamed_output_types > 1 {
- sess.warn(
- "due to multiple output types requested, the explicitly specified \
- output file name will be adapted for each output type",
- );
+ sess.emit_warning(errors::MultipleOutputTypesAdaption);
None
} else {
if !sess.opts.cg.extra_filename.is_empty() {
- sess.warn("ignoring -C extra-filename flag due to -o flag");
+ sess.emit_warning(errors::IgnoringExtraFilename);
}
Some(out_file.clone())
};
if sess.io.output_dir != None {
- sess.warn("ignoring --out-dir flag due to -o flag");
+ sess.emit_warning(errors::IgnoringOutDir);
}
OutputFilenames::new(
if encode_opt {
record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
- if let DefKind::Generator = self.tcx.def_kind(def_id) && tcx.sess.opts.unstable_opts.drop_tracking_mir {
+ if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) {
record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
}
}
base_n::encode(hash, base_n::CASE_INSENSITIVE)
}
- pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) {
+ pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) {
// Estimate the size of a codegen unit as (approximately) the number of MIR
// statements it corresponds to.
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
}
#[inline]
+ /// Should only be called if [`create_size_estimate`] has previously been called.
+ ///
+ /// [`create_size_estimate`]: Self::create_size_estimate
pub fn size_estimate(&self) -> usize {
- // Should only be called if `estimate_size` has previously been called.
- self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
+ self.size_estimate
+ .expect("create_size_estimate must be called before getting a size_estimate")
}
pub fn modify_size_estimate(&mut self, delta: usize) {
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::steal::Steal;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_index::vec::IndexVec;
return tcx.mir_drops_elaborated_and_const_checked(def);
}
- if tcx.generator_kind(def.did).is_some() && tcx.sess.opts.unstable_opts.drop_tracking_mir {
+ if tcx.sess.opts.unstable_opts.drop_tracking_mir
+ && let DefKind::Generator = tcx.def_kind(def.did)
+ {
tcx.ensure().mir_generator_witnesses(def.did);
}
let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
&[
&reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
&lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
- &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&unreachable_prop::UnreachablePropagation,
&uninhabited_enum_branching::UninhabitedEnumBranching,
&o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
&inline::Inline,
&remove_storage_markers::RemoveStorageMarkers,
&remove_zsts::RemoveZsts,
+ &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&const_goto::ConstGoto,
&remove_unneeded_drops::RemoveUnneededDrops,
&sroa::ScalarReplacementOfAggregates,
//! This pass eliminates casting of arrays into slices when their length
//! is taken using `.len()` method. Handy to preserve information in MIR for const prop
+use crate::ssa::SsaLocals;
use crate::MirPass;
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_data_structures::intern::Interned;
-use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
+use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, ReErased, Region, TyCtxt};
-
-const MAX_NUM_BLOCKS: usize = 800;
-const MAX_NUM_LOCALS: usize = 3000;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_mir_dataflow::impls::borrowed_locals;
pub struct NormalizeArrayLen;
impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- // See #105929
- sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts
+ sess.mir_opt_level() >= 3
}
+ #[instrument(level = "trace", skip(self, tcx, body))]
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // early returns for edge cases of highly unrolled functions
- if body.basic_blocks.len() > MAX_NUM_BLOCKS {
- return;
- }
- if body.local_decls.len() > MAX_NUM_LOCALS {
- return;
- }
+ debug!(def_id = ?body.source.def_id());
normalize_array_len_calls(tcx, body)
}
}
-pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // We don't ever touch terminators, so no need to invalidate the CFG cache
- let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
- let local_decls = &mut body.local_decls;
+fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let borrowed_locals = borrowed_locals(body);
+ let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
- // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
- let mut interesting_locals = BitSet::new_empty(local_decls.len());
- for (local, decl) in local_decls.iter_enumerated() {
- match decl.ty.kind() {
- ty::Array(..) => {
- interesting_locals.insert(local);
- }
- ty::Ref(.., ty, Mutability::Not) => match ty.kind() {
- ty::Array(..) => {
- interesting_locals.insert(local);
- }
- _ => {}
- },
- _ => {}
- }
- }
- if interesting_locals.is_empty() {
- // we have found nothing to analyze
- return;
- }
- let num_intesting_locals = interesting_locals.count();
- let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
- let mut patches_scratchpad =
- FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
- let mut replacements_scratchpad =
- FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default());
- for block in basic_blocks {
- // make length calls for arrays [T; N] not to decay into length calls for &[T]
- // that forbids constant propagation
- normalize_array_len_call(
- tcx,
- block,
- local_decls,
- &interesting_locals,
- &mut state,
- &mut patches_scratchpad,
- &mut replacements_scratchpad,
- );
- state.clear();
- patches_scratchpad.clear();
- replacements_scratchpad.clear();
- }
-}
+ let slice_lengths = compute_slice_length(tcx, &ssa, body);
+ debug!(?slice_lengths);
-struct Patcher<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
- patches_scratchpad: &'a FxIndexMap<usize, usize>,
- replacements_scratchpad: &'a mut FxIndexMap<usize, Local>,
- local_decls: &'a mut IndexVec<Local, LocalDecl<'tcx>>,
- statement_idx: usize,
+ Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body);
}
-impl<'tcx> Patcher<'_, 'tcx> {
- fn patch_expand_statement(
- &mut self,
- statement: &mut Statement<'tcx>,
- ) -> Option<std::vec::IntoIter<Statement<'tcx>>> {
- let idx = self.statement_idx;
- if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() {
- let mut statements = Vec::with_capacity(2);
-
- // we are at statement that performs a cast. The only sound way is
- // to create another local that performs a similar copy without a cast and then
- // use this copy in the Len operation
-
- match &statement.kind {
- StatementKind::Assign(box (
- ..,
- Rvalue::Cast(
- CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
- operand,
- _,
- ),
- )) => {
- match operand {
- Operand::Copy(place) | Operand::Move(place) => {
- // create new local
- let ty = operand.ty(self.local_decls, self.tcx);
- let local_decl = LocalDecl::with_source_info(ty, statement.source_info);
- let local = self.local_decls.push(local_decl);
- // make it live
- let mut make_live_statement = statement.clone();
- make_live_statement.kind = StatementKind::StorageLive(local);
- statements.push(make_live_statement);
- // copy into it
-
- let operand = Operand::Copy(*place);
- let mut make_copy_statement = statement.clone();
- let assign_to = Place::from(local);
- let rvalue = Rvalue::Use(operand);
- make_copy_statement.kind =
- StatementKind::Assign(Box::new((assign_to, rvalue)));
- statements.push(make_copy_statement);
-
- // to reorder we have to copy and make NOP
- statements.push(statement.clone());
- statement.make_nop();
-
- self.replacements_scratchpad.insert(len_statemnt_idx, local);
- }
- _ => {
- unreachable!("it's a bug in the implementation")
- }
- }
- }
- _ => {
- unreachable!("it's a bug in the implementation")
+fn compute_slice_length<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ssa: &SsaLocals,
+ body: &Body<'tcx>,
+) -> IndexVec<Local, Option<ty::Const<'tcx>>> {
+ let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls);
+
+ for (local, rvalue) in ssa.assignments(body) {
+ match rvalue {
+ Rvalue::Cast(
+ CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
+ operand,
+ cast_ty,
+ ) => {
+ let operand_ty = operand.ty(body, tcx);
+ debug!(?operand_ty);
+ if let Some(operand_ty) = operand_ty.builtin_deref(true)
+ && let ty::Array(_, len) = operand_ty.ty.kind()
+ && let Some(cast_ty) = cast_ty.builtin_deref(true)
+ && let ty::Slice(..) = cast_ty.ty.kind()
+ {
+ slice_lengths[local] = Some(*len);
}
}
-
- self.statement_idx += 1;
-
- Some(statements.into_iter())
- } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() {
- let mut statements = Vec::with_capacity(2);
-
- match &statement.kind {
- StatementKind::Assign(box (into, Rvalue::Len(place))) => {
- let add_deref = if let Some(..) = place.as_local() {
- false
- } else if let Some(..) = place.local_or_deref_local() {
- true
- } else {
- unreachable!("it's a bug in the implementation")
- };
- // replace len statement
- let mut len_statement = statement.clone();
- let mut place = Place::from(local);
- if add_deref {
- place = self.tcx.mk_place_deref(place);
- }
- len_statement.kind =
- StatementKind::Assign(Box::new((*into, Rvalue::Len(place))));
- statements.push(len_statement);
-
- // make temporary dead
- let mut make_dead_statement = statement.clone();
- make_dead_statement.kind = StatementKind::StorageDead(local);
- statements.push(make_dead_statement);
-
- // make original statement NOP
- statement.make_nop();
+ // The length information is stored in the fat pointer, so we treat `operand` as a value.
+ Rvalue::Use(operand) => {
+ if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() {
+ slice_lengths[local] = slice_lengths[rhs];
}
- _ => {
- unreachable!("it's a bug in the implementation")
+ }
+ // The length information is stored in the fat pointer.
+ // Reborrowing copies length information from one pointer to the other.
+ Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => {
+ if let [PlaceElem::Deref] = rhs.projection[..] {
+ slice_lengths[local] = slice_lengths[rhs.local];
}
}
-
- self.statement_idx += 1;
-
- Some(statements.into_iter())
- } else {
- self.statement_idx += 1;
- None
+ _ => {}
}
}
+
+ slice_lengths
}
-fn normalize_array_len_call<'tcx>(
+struct Replacer<'tcx> {
tcx: TyCtxt<'tcx>,
- block: &mut BasicBlockData<'tcx>,
- local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
- interesting_locals: &BitSet<Local>,
- state: &mut FxIndexMap<Local, usize>,
- patches_scratchpad: &mut FxIndexMap<usize, usize>,
- replacements_scratchpad: &mut FxIndexMap<usize, Local>,
-) {
- for (statement_idx, statement) in block.statements.iter_mut().enumerate() {
- match &mut statement.kind {
- StatementKind::Assign(box (place, rvalue)) => {
- match rvalue {
- Rvalue::Cast(
- CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
- operand,
- cast_ty,
- ) => {
- let Some(local) = place.as_local() else { return };
- match operand {
- Operand::Copy(place) | Operand::Move(place) => {
- let Some(operand_local) = place.local_or_deref_local() else { return; };
- if !interesting_locals.contains(operand_local) {
- return;
- }
- let operand_ty = local_decls[operand_local].ty;
- match (operand_ty.kind(), cast_ty.kind()) {
- (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => {
- if of_ty_src == of_ty_dst {
- // this is a cast from [T; N] into [T], so we are good
- state.insert(local, statement_idx);
- }
- }
- // current way of patching doesn't allow to work with `mut`
- (
- ty::Ref(
- Region(Interned(ReErased, _)),
- operand_ty,
- Mutability::Not,
- ),
- ty::Ref(
- Region(Interned(ReErased, _)),
- cast_ty,
- Mutability::Not,
- ),
- ) => {
- match (operand_ty.kind(), cast_ty.kind()) {
- // current way of patching doesn't allow to work with `mut`
- (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => {
- if of_ty_src == of_ty_dst {
- // this is a cast from [T; N] into [T], so we are good
- state.insert(local, statement_idx);
- }
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
- Rvalue::Len(place) => {
- let Some(local) = place.local_or_deref_local() else {
- return;
- };
- if let Some(cast_statement_idx) = state.get(&local).copied() {
- patches_scratchpad.insert(cast_statement_idx, statement_idx);
- }
- }
- _ => {
- // invalidate
- state.remove(&place.local);
- }
- }
- }
- _ => {}
- }
- }
+ slice_lengths: IndexVec<Local, Option<ty::Const<'tcx>>>,
+}
- let mut patcher = Patcher {
- tcx,
- patches_scratchpad: &*patches_scratchpad,
- replacements_scratchpad,
- local_decls,
- statement_idx: 0,
- };
+impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
- block.expand_statements(|st| patcher.patch_expand_statement(st));
+ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) {
+ if let Rvalue::Len(place) = rvalue
+ && let [PlaceElem::Deref] = &place.projection[..]
+ && let Some(len) = self.slice_lengths[place.local]
+ {
+ *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
+ span: rustc_span::DUMMY_SP,
+ user_ty: None,
+ literal: ConstantKind::from_const(len, self.tcx),
+ })));
+ }
+ self.super_rvalue(rvalue, loc);
+ }
}
use std::ops::Range;
use std::path::PathBuf;
-use crate::errors::{LargeAssignmentsLint, RecursionLimit, TypeLengthLimit};
+use crate::errors::{
+ EncounteredErrorWhileInstantiating, LargeAssignmentsLint, RecursionLimit, TypeLengthLimit,
+};
#[derive(PartialEq)]
pub enum MonoItemCollectionMode {
&& starting_point.node.is_user_defined()
{
let formatted_item = with_no_trimmed_paths!(starting_point.node.to_string());
- tcx.sess.span_note_without_error(
- starting_point.span,
- &format!("the above error was encountered while instantiating `{formatted_item}`"),
- );
+ tcx.sess.emit_note(EncounteredErrorWhileInstantiating {
+ span: starting_point.span,
+ formatted_item,
+ });
}
inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items);
pub struct CouldntDumpMonoStats {
pub error: String,
}
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_encountered_error_while_instantiating)]
+pub struct EncounteredErrorWhileInstantiating {
+ #[primary_span]
+ pub span: Span,
+ pub formatted_item: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_unknown_cgu_collection_mode)]
+pub struct UnknownCguCollectionMode<'a> {
+ pub mode: &'a str,
+}
use crate::collector::InliningMap;
use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{
+ CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy,
+};
pub struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
partitioner.place_root_mono_items(cx, mono_items)
};
- initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
+ initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx));
debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
partitioner.place_inlined_mono_items(cx, initial_partitioning)
};
- post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
+ post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx));
debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter());
fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[CodegenUnit<'_>]) {
let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items {
Some(ref s) => {
- let mode_string = s.to_lowercase();
- let mode_string = mode_string.trim();
- if mode_string == "eager" {
+ let mode = s.to_lowercase();
+ let mode = mode.trim();
+ if mode == "eager" {
MonoItemCollectionMode::Eager
} else {
- if mode_string != "lazy" {
- let message = format!(
- "Unknown codegen-item collection mode '{mode_string}'. \
- Falling back to 'lazy' mode."
- );
- tcx.sess.warn(&message);
+ if mode != "lazy" {
+ tcx.sess.emit_warning(UnknownCguCollectionMode { mode });
}
MonoItemCollectionMode::Lazy
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
next_token.kind
{
- if self.token.span.hi() == next_token.span.lo() {
+ // If this integer looks like a float, then recover as such.
+ //
+ // We will never encounter the exponent part of a floating
+ // point literal here, since there's no use of the exponent
+ // syntax that also constitutes a valid integer, so we need
+ // not check for that.
+ if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64)
+ && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
+ && self.token.span.hi() == next_token.span.lo()
+ {
let s = String::from("0.") + symbol.as_str();
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
return Some(Token::new(kind, self.token.span.to(next_token.span)));
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
-use crate::errors::ExprNotAllowedInContext;
+use crate::errors::{ExprNotAllowedInContext, SkippingConstChecks};
/// An expression that is not *always* legal in a const context.
#[derive(Clone, Copy)]
// corresponding feature gate. This encourages nightly users to use feature gates when
// possible.
None if tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you => {
- tcx.sess.span_warn(span, "skipping const checks");
+ tcx.sess.emit_warning(SkippingConstChecks { span });
return;
}
}
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
- if tcx.has_attr(def_id.to_def_id(), sym::lang) {
- return true;
+ fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ tcx.has_attr(def_id.to_def_id(), sym::lang)
+ // Stable attribute for #[lang = "panic_impl"]
+ || tcx.has_attr(def_id.to_def_id(), sym::panic_handler)
}
- // Stable attribute for #[lang = "panic_impl"]
- if tcx.has_attr(def_id.to_def_id(), sym::panic_handler) {
- return true;
+ fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow
}
- if tcx.def_kind(def_id).has_codegen_attrs() {
- let cg_attrs = tcx.codegen_fn_attrs(def_id);
+ fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+ tcx.def_kind(def_id).has_codegen_attrs() && {
+ let cg_attrs = tcx.codegen_fn_attrs(def_id);
- // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
- // forcefully, e.g., for placing it in a specific section.
- if cg_attrs.contains_extern_indicator()
- || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
- || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
- {
- return true;
+ // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
+ // forcefully, e.g., for placing it in a specific section.
+ cg_attrs.contains_extern_indicator()
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
+ || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
}
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow
+ has_allow_dead_code(tcx, def_id)
+ || has_used_like_attr(tcx, def_id)
+ || has_lang_attr(tcx, def_id)
}
// These check_* functions seeds items that
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(passes_skipping_const_checks)]
+pub struct SkippingConstChecks {
+ #[primary_span]
+ pub span: Span,
+}
use rustc_span::SourceFileHashAlgorithm;
use rustc_errors::emitter::HumanReadableErrorType;
-use rustc_errors::{ColorConfig, HandlerFlags};
+use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg};
use std::collections::btree_map::{
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
}
}
+impl IntoDiagnosticArg for CrateType {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpSourceMode {
/// `-Zunpretty=normal`
}
}
}
+
+#[derive(Diagnostic)]
+#[diag(session_optimization_fuel_exhausted)]
+pub struct OptimisationFuelExhausted {
+ pub msg: String,
+}
use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
use crate::errors::{
BranchProtectionRequiresAArch64, CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers,
- LinkerPluginToWindowsNotSupported, NotCircumventFeature, ProfileSampleUseFileDoesNotExist,
- ProfileUseFileDoesNotExist, SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
- SkippingConstChecks, SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
+ LinkerPluginToWindowsNotSupported, NotCircumventFeature, OptimisationFuelExhausted,
+ ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, SanitizerCfiEnabled,
+ SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks,
+ SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination,
UnsupportedDwarfVersion,
};
self.diagnostic().span_err_with_code(sp, msg, code)
}
#[rustc_lint_diagnostics]
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.diagnostic().err(msg)
}
))
}
}
+
+ #[rustc_lint_diagnostics]
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
#[track_caller]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().span_warn(sp, msg)
}
+
+ #[rustc_lint_diagnostics]
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_warn_with_code<S: Into<MultiSpan>>(
) {
self.diagnostic().span_warn_with_code(sp, msg, code)
}
+
+ #[rustc_lint_diagnostics]
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().warn(msg)
}
self.diagnostic().delay_good_path_bug(msg)
}
+ #[rustc_lint_diagnostics]
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().note_without_error(msg)
}
#[track_caller]
+ #[rustc_lint_diagnostics]
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
pub fn span_note_without_error<S: Into<MultiSpan>>(
&self,
sp: S,
) {
self.diagnostic().span_note_without_error(sp, msg)
}
+
+ #[rustc_lint_diagnostics]
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn struct_note_without_error(
// We only call `msg` in case we can actually emit warnings.
// Otherwise, this could cause a `delay_good_path_bug` to
// trigger (issue #79546).
- self.warn(&format!("optimization-fuel-exhausted: {}", msg()));
+ self.emit_warning(OptimisationFuelExhausted { msg: msg() });
}
fuel.out_of_fuel = true;
} else if fuel.remaining > 0 {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
+
+ // The most common forms of unsizing are array to slice, and concrete (Sized)
+ // type into a `dyn Trait`. ADTs and Tuples can also have their final field
+ // unsized if it's generic.
+ fn consider_builtin_unsize_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx>;
+
+ // `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
+ // if `Trait2` is a (transitive) supertrait of `Trait2`.
+ fn consider_builtin_dyn_upcast_candidates(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> Vec<CanonicalResponse<'tcx>>;
}
impl<'tcx> EvalCtxt<'_, 'tcx> {
G::consider_builtin_future_candidate(self, goal)
} else if lang_items.gen_trait() == Some(trait_def_id) {
G::consider_builtin_generator_candidate(self, goal)
+ } else if lang_items.unsize_trait() == Some(trait_def_id) {
+ G::consider_builtin_unsize_candidate(self, goal)
} else {
Err(NoSolution)
};
}
Err(NoSolution) => (),
}
+
+ // There may be multiple unsize candidates for a trait with several supertraits:
+ // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
+ if lang_items.unsize_trait() == Some(trait_def_id) {
+ for result in G::consider_builtin_dyn_upcast_candidates(self, goal) {
+ candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result });
+ }
+ }
}
fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
.to_predicate(tcx),
)
}
+
+ fn consider_builtin_unsize_candidate(
+ _ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ bug!("`Unsize` does not have an associated type: {:?}", goal);
+ }
+
+ fn consider_builtin_dyn_upcast_candidates(
+ _ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> Vec<super::CanonicalResponse<'tcx>> {
+ bug!("`Unsize` does not have an associated type: {:?}", goal);
+ }
}
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
use super::assembly::{self, Candidate, CandidateSource};
use super::infcx_ext::InferCtxtExt;
-use super::{Certainty, EvalCtxt, Goal, QueryResult};
+use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::util::supertraits;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_middle::ty::{TraitPredicate, TypeVisitable};
.to_predicate(tcx),
)
}
+
+ fn consider_builtin_unsize_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ let tcx = ecx.tcx();
+ let a_ty = goal.predicate.self_ty();
+ let b_ty = goal.predicate.trait_ref.substs.type_at(1);
+ if b_ty.is_ty_var() {
+ return ecx.make_canonical_response(Certainty::AMBIGUOUS);
+ }
+ ecx.infcx.probe(|_| {
+ match (a_ty.kind(), b_ty.kind()) {
+ // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
+ (&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
+ // Dyn upcasting is handled separately, since due to upcasting,
+ // when there are two supertraits that differ by substs, we
+ // may return more than one query response.
+ return Err(NoSolution);
+ }
+ // `T` -> `dyn Trait` unsizing
+ (_, &ty::Dynamic(data, region, ty::Dyn)) => {
+ // Can only unsize to an object-safe type
+ if data
+ .principal_def_id()
+ .map_or(false, |def_id| !tcx.check_is_object_safe(def_id))
+ {
+ return Err(NoSolution);
+ }
+
+ let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
+ return Err(NoSolution);
+ };
+ let nested_goals: Vec<_> = data
+ .iter()
+ // Check that the type implements all of the predicates of the def-id.
+ // (i.e. the principal, all of the associated types match, and any auto traits)
+ .map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty)))
+ .chain([
+ // The type must be Sized to be unsized.
+ goal.with(
+ tcx,
+ ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty])),
+ ),
+ // The type must outlive the lifetime of the `dyn` we're unsizing into.
+ goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
+ ])
+ .collect();
+
+ ecx.evaluate_all_and_make_canonical_response(nested_goals)
+ }
+ // `[T; n]` -> `[T]` unsizing
+ (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
+ // We just require that the element type stays the same
+ let nested_goals = ecx.infcx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
+ ecx.evaluate_all_and_make_canonical_response(nested_goals)
+ }
+ // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
+ (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
+ if a_def.is_struct() && a_def.did() == b_def.did() =>
+ {
+ let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
+ // We must be unsizing some type parameters. This also implies
+ // that the struct has a tail field.
+ if unsizing_params.is_empty() {
+ return Err(NoSolution);
+ }
+
+ let tail_field = a_def
+ .non_enum_variant()
+ .fields
+ .last()
+ .expect("expected unsized ADT to have a tail field");
+ let tail_field_ty = tcx.bound_type_of(tail_field.did);
+
+ let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
+ let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
+
+ // Substitute just the unsizing params from B into A. The type after
+ // this substitution must be equal to B. This is so we don't unsize
+ // unrelated type parameters.
+ let new_a_substs = tcx.mk_substs(a_substs.iter().enumerate().map(|(i, a)| {
+ if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
+ }));
+ let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
+
+ // Finally, we require that `TailA: Unsize<TailB>` for the tail field
+ // types.
+ let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+ nested_goals.push(goal.with(
+ tcx,
+ ty::Binder::dummy(
+ tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
+ ),
+ ));
+
+ ecx.evaluate_all_and_make_canonical_response(nested_goals)
+ }
+ // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
+ (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
+ if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
+ {
+ let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
+ let b_last_ty = b_tys.last().unwrap();
+
+ // Substitute just the tail field of B., and require that they're equal.
+ let unsized_a_ty = tcx.mk_tup(a_rest_tys.iter().chain([b_last_ty]));
+ let mut nested_goals = ecx.infcx.eq(goal.param_env, unsized_a_ty, b_ty)?;
+
+ // Similar to ADTs, require that the rest of the fields are equal.
+ nested_goals.push(goal.with(
+ tcx,
+ ty::Binder::dummy(
+ tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
+ ),
+ ));
+
+ ecx.evaluate_all_and_make_canonical_response(nested_goals)
+ }
+ _ => Err(NoSolution),
+ }
+ })
+ }
+
+ fn consider_builtin_dyn_upcast_candidates(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> Vec<CanonicalResponse<'tcx>> {
+ let tcx = ecx.tcx();
+
+ let a_ty = goal.predicate.self_ty();
+ let b_ty = goal.predicate.trait_ref.substs.type_at(1);
+ let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
+ return vec![];
+ };
+ let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
+ return vec![];
+ };
+
+ // All of a's auto traits need to be in b's auto traits.
+ let auto_traits_compatible =
+ b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b));
+ if !auto_traits_compatible {
+ return vec![];
+ }
+
+ let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
+ ecx.infcx.probe(|_| -> Result<_, NoSolution> {
+ // Require that all of the trait predicates from A match B, except for
+ // the auto traits. We do this by constructing a new A type with B's
+ // auto traits, and equating these types.
+ let new_a_data = principal
+ .into_iter()
+ .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
+ .chain(a_data.iter().filter(|a| {
+ matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
+ }))
+ .chain(
+ b_data
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait)
+ .map(ty::Binder::dummy),
+ );
+ let new_a_data = tcx.mk_poly_existential_predicates(new_a_data);
+ let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
+
+ // We also require that A's lifetime outlives B's lifetime.
+ let mut nested_obligations = ecx.infcx.eq(goal.param_env, new_a_ty, b_ty)?;
+ nested_obligations.push(
+ goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region))),
+ );
+
+ ecx.evaluate_all_and_make_canonical_response(nested_obligations)
+ })
+ };
+
+ let mut responses = vec![];
+ // If the principal def ids match (or are both none), then we're not doing
+ // trait upcasting. We're just removing auto traits (or shortening the lifetime).
+ if a_data.principal_def_id() == b_data.principal_def_id() {
+ if let Ok(response) = unsize_dyn_to_principal(a_data.principal()) {
+ responses.push(response);
+ }
+ } else if let Some(a_principal) = a_data.principal()
+ && let Some(b_principal) = b_data.principal()
+ {
+ for super_trait_ref in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)) {
+ if super_trait_ref.def_id() != b_principal.def_id() {
+ continue;
+ }
+ let erased_trait_ref = super_trait_ref
+ .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+ if let Ok(response) = unsize_dyn_to_principal(Some(erased_trait_ref)) {
+ responses.push(response);
+ }
+ }
+ }
+
+ responses
+ }
}
impl<'tcx> EvalCtxt<'_, 'tcx> {
}
if let Some(Ok(c)) = single_match {
- let ocx = ObligationCtxt::new(infcx);
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
assert!(ocx.select_all_or_error().is_empty());
},
};
- // FIXME(eddyb) cache this (including computing `unsizing_params`)
- // by putting it in a query; it would only need the `DefId` as it
- // looks at declared field types, not anything substituted.
-
// The last field of the structure has to exist and contain type/const parameters.
let Some((tail_field, prefix_fields)) =
def.non_enum_variant().fields.split_last() else
}
}
+// Specializable trait for implementing ToOwned::clone_into. This is
+// public in the crate and has the Allocator parameter so that
+// vec::clone_from use it too.
+#[cfg(not(no_global_oom_handling))]
+pub(crate) trait SpecCloneIntoVec<T, A: Allocator> {
+ fn clone_into(&self, target: &mut Vec<T, A>);
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Clone, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
+ default fn clone_into(&self, target: &mut Vec<T, A>) {
+ // drop anything in target that will not be overwritten
+ target.truncate(self.len());
+
+ // target.len <= self.len due to the truncate above, so the
+ // slices here are always in-bounds.
+ let (init, tail) = self.split_at(target.len());
+
+ // reuse the contained values' allocations/resources.
+ target.clone_from_slice(init);
+ target.extend_from_slice(tail);
+ }
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Copy, A: Allocator> SpecCloneIntoVec<T, A> for [T] {
+ fn clone_into(&self, target: &mut Vec<T, A>) {
+ target.clear();
+ target.extend_from_slice(self);
+ }
+}
+
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> ToOwned for [T] {
}
fn clone_into(&self, target: &mut Vec<T>) {
- // drop anything in target that will not be overwritten
- target.truncate(self.len());
-
- // target.len <= self.len due to the truncate above, so the
- // slices here are always in-bounds.
- let (init, tail) = self.split_at(target.len());
-
- // reuse the contained values' allocations/resources.
- target.clone_from_slice(init);
- target.extend_from_slice(tail);
+ SpecCloneIntoVec::clone_into(self, target);
}
}
}
}
-#[cfg(not(no_global_oom_handling))]
-trait SpecCloneFrom {
- fn clone_from(this: &mut Self, other: &Self);
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Clone, A: Allocator> SpecCloneFrom for Vec<T, A> {
- default fn clone_from(this: &mut Self, other: &Self) {
- // drop anything that will not be overwritten
- this.truncate(other.len());
-
- // self.len <= other.len due to the truncate above, so the
- // slices here are always in-bounds.
- let (init, tail) = other.split_at(this.len());
-
- // reuse the contained values' allocations/resources.
- this.clone_from_slice(init);
- this.extend_from_slice(tail);
- }
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Copy, A: Allocator> SpecCloneFrom for Vec<T, A> {
- fn clone_from(this: &mut Self, other: &Self) {
- this.clear();
- this.extend_from_slice(other);
- }
-}
-
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
}
fn clone_from(&mut self, other: &Self) {
- SpecCloneFrom::clone_from(self, other)
+ crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self);
}
}
#[unstable(feature = "gen_future", issue = "50547")]
unsafe impl Sync for ResumeTy {}
-/// Wrap a generator in a future.
-///
-/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
-/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
-// This is `const` to avoid extra errors after we recover from `const async fn`
-#[doc(hidden)]
-#[unstable(feature = "gen_future", issue = "50547")]
-#[rustc_const_unstable(feature = "gen_future", issue = "50547")]
-#[inline]
-pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
-where
- T: crate::ops::Generator<ResumeTy, Yield = ()>,
-{
- use crate::{
- ops::{Generator, GeneratorState},
- pin::Pin,
- task::Poll,
- };
-
- #[rustc_diagnostic_item = "gen_future"]
- struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
-
- // We rely on the fact that async/await futures are immovable in order to create
- // self-referential borrows in the underlying generator.
- impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
-
- impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
- type Output = T::Return;
- #[track_caller]
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection.
- let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
-
- // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
- // `.await` lowering will safely cast that back to a `&mut Context`.
- match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
- GeneratorState::Yielded(()) => Poll::Pending,
- GeneratorState::Complete(x) => Poll::Ready(x),
- }
- }
- }
-
- GenFuture(gen)
-}
-
#[lang = "get_context"]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
/// escapes the path please use [`Debug`] instead.
///
/// [`Display`]: fmt::Display
+ /// [`Debug`]: fmt::Debug
///
/// # Examples
///
-Subproject commit 2cd1b5593d26dc6a03c20f8619187ad4b2485552
+Subproject commit f2a78f64b668f63f581203c6bac509903f7c00ee
-Subproject commit 19f798d448835a4888e3b3eae7fe69f1d61d8681
+Subproject commit f1a4614aa41cc544b91b79760a709e113f3451d7
-Subproject commit 960d610e7f33889a2577f5f17c26f0d5c82b30df
+Subproject commit bd1829d235296952bf72ca55635e360584b8805e
-Subproject commit 2cb0ed9ba56360949f492f9866afe8c293f9f9da
+Subproject commit 22882fb3f7b4d69fdc0d1731e8b9cfcb6910537d
-Subproject commit a9fb7d13eadfcc5f457962731f105b97f9a7474a
+Subproject commit 134376872e8c387ef369507e0ee9b5a0e3272718
-Subproject commit 7352353ae91c48b136d2ca7d03822e1448165e1e
+Subproject commit e359ee27fc3da3356d71a732128c0a1abe02e53a
// these values up both in `dataset` and in the storage API, so it needs to be able
// to convert the names back and forth. Despite doing this kebab-case to
// StudlyCaps transformation automatically, the JS DOM API does not provide a
- // mechanism for doing the just transformation on a string. So we want to avoid
+ // mechanism for doing just the transformation on a string. So we want to avoid
// the StudlyCaps representation in the `dataset` property.
//
// We solve this by replacing all the `-`s with `_`s. We do that here, when we
write_footer(out, playground_button);
}
-/// Highlights `src` as a macro, returning the HTML output.
-pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
- write_header(out, "macro", None, Tooltip::None);
+/// Highlights `src` as an item-decl, returning the HTML output.
+pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
+ write!(out, "<pre class=\"rust item-decl\">");
write_code(out, src, None, None);
- write_footer(out, None);
+ write!(out, "</pre>");
}
/// Highlights `src` as a source code page, returning the HTML output.
pub(crate) root_path: &'a str,
pub(crate) static_root_path: Option<&'a str>,
pub(crate) description: &'a str,
- pub(crate) keywords: &'a str,
pub(crate) resource_suffix: &'a str,
}
use super::write_shared::write_shared;
use super::{
collect_spans_and_sources, print_sidebar, scrape_examples_help, sidebar_module_like, AllTypes,
- LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
+ LinkFromSrc, NameDoc, StylePath,
};
use crate::clean::{self, types::ExternalLocation, ExternalCrate};
self.shared.layout.krate
)
};
- let keywords = make_item_keywords(it);
let name;
let tyname_s = if it.is_crate() {
name = format!("{} crate", tyname);
static_root_path: clone_shared.static_root_path.as_deref(),
title: &title,
description: &desc,
- keywords: &keywords,
resource_suffix: &clone_shared.resource_suffix,
};
let mut page_buffer = Buffer::html();
root_path: "../",
static_root_path: shared.static_root_path.as_deref(),
description: "List of all items in this crate",
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
let all = shared.all.replace(AllTypes::new());
&self.shared.cache
}
}
-
-fn make_item_keywords(it: &clean::Item) -> String {
- format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
-}
}
}
-pub(crate) const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
-
/// Returns a list of all paths used in the type.
/// This is used to help deduplicate imported impls
/// for reexported types. If any of the contained
let notable_traits =
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- w.reserve(header_len);
- write!(
- w,
- "{vis}{constness}{asyncness}{unsafety}{abi}fn \
- {name}{generics}{decl}{notable_traits}{where_clause}",
- vis = visibility,
- constness = constness,
- asyncness = asyncness,
- unsafety = unsafety,
- abi = abi,
- name = name,
- generics = f.generics.print(cx),
- where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
- decl = f.decl.full_print(header_len, 0, cx),
- notable_traits = notable_traits.unwrap_or_default(),
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ w.reserve(header_len);
+ write!(
+ w,
+ "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+ {name}{generics}{decl}{notable_traits}{where_clause}",
+ vis = visibility,
+ constness = constness,
+ asyncness = asyncness,
+ unsafety = unsafety,
+ abi = abi,
+ name = name,
+ generics = f.generics.print(cx),
+ where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
+ decl = f.decl.full_print(header_len, 0, cx),
+ notable_traits = notable_traits.unwrap_or_default(),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
}
let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
// Output the trait definition
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "{}{}{}trait {}{}{}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- t.unsafety(tcx).print_with_space(),
- if t.is_auto(tcx) { "auto " } else { "" },
- it.name.unwrap(),
- t.generics.print(cx),
- bounds
- );
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "{}{}{}trait {}{}{}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ t.unsafety(tcx).print_with_space(),
+ if t.is_auto(tcx) { "auto " } else { "" },
+ it.name.unwrap(),
+ t.generics.print(cx),
+ bounds
+ );
- if !t.generics.where_predicates.is_empty() {
- write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
- } else {
- w.write_str(" ");
- }
+ if !t.generics.where_predicates.is_empty() {
+ write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
+ } else {
+ w.write_str(" ");
+ }
- if t.items.is_empty() {
- w.write_str("{ }");
- } else {
- // FIXME: we should be using a derived_id for the Anchors here
- w.write_str("{\n");
- let mut toggle = false;
-
- // If there are too many associated types, hide _everything_
- if should_hide_fields(count_types) {
- toggle = true;
- toggle_open(
- w,
- format_args!(
- "{} associated items",
- count_types + count_consts + count_methods
- ),
- );
- }
- for types in [&required_types, &provided_types] {
- for t in types {
- render_assoc_item(
- w,
- t,
- AssocItemLink::Anchor(None),
- ItemType::Trait,
- cx,
- RenderMode::Normal,
- );
- w.write_str(";\n");
- }
- }
- // If there are too many associated constants, hide everything after them
- // We also do this if the types + consts is large because otherwise we could
- // render a bunch of types and _then_ a bunch of consts just because both were
- // _just_ under the limit
- if !toggle && should_hide_fields(count_types + count_consts) {
- toggle = true;
- toggle_open(
- w,
- format_args!(
- "{} associated constant{} and {} method{}",
- count_consts,
- pluralize(count_consts),
- count_methods,
- pluralize(count_methods),
- ),
- );
- }
- if count_types != 0 && (count_consts != 0 || count_methods != 0) {
- w.write_str("\n");
- }
- for consts in [&required_consts, &provided_consts] {
- for c in consts {
- render_assoc_item(
- w,
- c,
- AssocItemLink::Anchor(None),
- ItemType::Trait,
- cx,
- RenderMode::Normal,
- );
- w.write_str(";\n");
- }
- }
- if !toggle && should_hide_fields(count_methods) {
- toggle = true;
- toggle_open(w, format_args!("{} methods", count_methods));
- }
- if count_consts != 0 && count_methods != 0 {
- w.write_str("\n");
- }
- for (pos, m) in required_methods.iter().enumerate() {
+ if t.items.is_empty() {
+ w.write_str("{ }");
+ } else {
+ // FIXME: we should be using a derived_id for the Anchors here
+ w.write_str("{\n");
+ let mut toggle = false;
+
+ // If there are too many associated types, hide _everything_
+ if should_hide_fields(count_types) {
+ toggle = true;
+ toggle_open(
+ w,
+ format_args!("{} associated items", count_types + count_consts + count_methods),
+ );
+ }
+ for types in [&required_types, &provided_types] {
+ for t in types {
render_assoc_item(
w,
- m,
+ t,
AssocItemLink::Anchor(None),
ItemType::Trait,
cx,
RenderMode::Normal,
);
w.write_str(";\n");
-
- if pos < required_methods.len() - 1 {
- w.write_str("<span class=\"item-spacer\"></span>");
- }
- }
- if !required_methods.is_empty() && !provided_methods.is_empty() {
- w.write_str("\n");
}
- for (pos, m) in provided_methods.iter().enumerate() {
+ }
+ // If there are too many associated constants, hide everything after them
+ // We also do this if the types + consts is large because otherwise we could
+ // render a bunch of types and _then_ a bunch of consts just because both were
+ // _just_ under the limit
+ if !toggle && should_hide_fields(count_types + count_consts) {
+ toggle = true;
+ toggle_open(
+ w,
+ format_args!(
+ "{} associated constant{} and {} method{}",
+ count_consts,
+ pluralize(count_consts),
+ count_methods,
+ pluralize(count_methods),
+ ),
+ );
+ }
+ if count_types != 0 && (count_consts != 0 || count_methods != 0) {
+ w.write_str("\n");
+ }
+ for consts in [&required_consts, &provided_consts] {
+ for c in consts {
render_assoc_item(
w,
- m,
+ c,
AssocItemLink::Anchor(None),
ItemType::Trait,
cx,
RenderMode::Normal,
);
- match *m.kind {
- clean::MethodItem(ref inner, _)
- if !inner.generics.where_predicates.is_empty() =>
- {
- w.write_str(",\n { ... }\n");
- }
- _ => {
- w.write_str(" { ... }\n");
- }
- }
+ w.write_str(";\n");
+ }
+ }
+ if !toggle && should_hide_fields(count_methods) {
+ toggle = true;
+ toggle_open(w, format_args!("{} methods", count_methods));
+ }
+ if count_consts != 0 && count_methods != 0 {
+ w.write_str("\n");
+ }
+ for (pos, m) in required_methods.iter().enumerate() {
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
+ w.write_str(";\n");
- if pos < provided_methods.len() - 1 {
- w.write_str("<span class=\"item-spacer\"></span>");
+ if pos < required_methods.len() - 1 {
+ w.write_str("<span class=\"item-spacer\"></span>");
+ }
+ }
+ if !required_methods.is_empty() && !provided_methods.is_empty() {
+ w.write_str("\n");
+ }
+ for (pos, m) in provided_methods.iter().enumerate() {
+ render_assoc_item(
+ w,
+ m,
+ AssocItemLink::Anchor(None),
+ ItemType::Trait,
+ cx,
+ RenderMode::Normal,
+ );
+ match *m.kind {
+ clean::MethodItem(ref inner, _)
+ if !inner.generics.where_predicates.is_empty() =>
+ {
+ w.write_str(",\n { ... }\n");
+ }
+ _ => {
+ w.write_str(" { ... }\n");
}
}
- if toggle {
- toggle_close(w);
+
+ if pos < provided_methods.len() - 1 {
+ w.write_str("<span class=\"item-spacer\"></span>");
}
- w.write_str("}");
}
- });
+ if toggle {
+ toggle_close(w);
+ }
+ w.write_str("}");
+ }
});
// Trait documentation
}
fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "trait {}{}{} = {};",
- it.name.unwrap(),
- t.generics.print(cx),
- print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds(&t.bounds, true, cx)
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "trait {}{}{} = {};",
+ it.name.unwrap(),
+ t.generics.print(cx),
+ print_where_clause(&t.generics, cx, 0, Ending::Newline),
+ bounds(&t.bounds, true, cx)
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
}
fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "type {}{}{where_clause} = impl {bounds};",
- it.name.unwrap(),
- t.generics.print(cx),
- where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds = bounds(&t.bounds, false, cx),
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "type {}{}{where_clause} = impl {bounds};",
+ it.name.unwrap(),
+ t.generics.print(cx),
+ where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
+ bounds = bounds(&t.bounds, false, cx),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
});
}
- wrap_into_item_decl(w, |w| write_content(w, cx, it, t));
+ write_content(w, cx, it, t);
document(w, cx, it, None, HeadingOffset::H2);
}
fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- render_union(w, it, Some(&s.generics), &s.fields, "", cx);
- });
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ render_union(w, it, Some(&s.generics), &s.fields, "", cx);
});
document(w, cx, it, None, HeadingOffset::H2);
fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
let tcx = cx.tcx();
let count_variants = e.variants().count();
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- write!(
- w,
- "{}enum {}{}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- it.name.unwrap(),
- e.generics.print(cx),
- );
- if !print_where_clause_and_check(w, &e.generics, cx) {
- // If there wasn't a `where` clause, we add a whitespace.
- w.write_str(" ");
- }
+ wrap_item(w, |w| {
+ render_attributes_in_pre(w, it, "");
+ write!(
+ w,
+ "{}enum {}{}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ it.name.unwrap(),
+ e.generics.print(cx),
+ );
+ if !print_where_clause_and_check(w, &e.generics, cx) {
+ // If there wasn't a `where` clause, we add a whitespace.
+ w.write_str(" ");
+ }
- let variants_stripped = e.has_stripped_entries();
- if count_variants == 0 && !variants_stripped {
- w.write_str("{}");
- } else {
- w.write_str("{\n");
- let toggle = should_hide_fields(count_variants);
- if toggle {
- toggle_open(w, format_args!("{} variants", count_variants));
- }
- for v in e.variants() {
- w.write_str(" ");
- let name = v.name.unwrap();
- match *v.kind {
- // FIXME(#101337): Show discriminant
- clean::VariantItem(ref var) => match var.kind {
- clean::VariantKind::CLike => write!(w, "{}", name),
- clean::VariantKind::Tuple(ref s) => {
- write!(w, "{}(", name);
- print_tuple_struct_fields(w, cx, s);
- w.write_str(")");
- }
- clean::VariantKind::Struct(ref s) => {
- render_struct(w, v, None, None, &s.fields, " ", false, cx);
- }
- },
- _ => unreachable!(),
- }
- w.write_str(",\n");
+ let variants_stripped = e.has_stripped_entries();
+ if count_variants == 0 && !variants_stripped {
+ w.write_str("{}");
+ } else {
+ w.write_str("{\n");
+ let toggle = should_hide_fields(count_variants);
+ if toggle {
+ toggle_open(w, format_args!("{} variants", count_variants));
+ }
+ for v in e.variants() {
+ w.write_str(" ");
+ let name = v.name.unwrap();
+ match *v.kind {
+ // FIXME(#101337): Show discriminant
+ clean::VariantItem(ref var) => match var.kind {
+ clean::VariantKind::CLike => write!(w, "{}", name),
+ clean::VariantKind::Tuple(ref s) => {
+ write!(w, "{}(", name);
+ print_tuple_struct_fields(w, cx, s);
+ w.write_str(")");
+ }
+ clean::VariantKind::Struct(ref s) => {
+ render_struct(w, v, None, None, &s.fields, " ", false, cx);
+ }
+ },
+ _ => unreachable!(),
}
+ w.write_str(",\n");
+ }
- if variants_stripped {
- w.write_str(" // some variants omitted\n");
- }
- if toggle {
- toggle_close(w);
- }
- w.write_str("}");
+ if variants_stripped {
+ w.write_str(" // some variants omitted\n");
}
- });
+ if toggle {
+ toggle_close(w);
+ }
+ w.write_str("}");
+ }
});
document(w, cx, it, None, HeadingOffset::H2);
}
fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
- wrap_into_item_decl(w, |w| {
- highlight::render_macro_with_highlighting(&t.source, w);
- });
+ highlight::render_item_decl_with_highlighting(&t.source, w);
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
- wrap_into_item_decl(w, |w| {
+ wrap_item(w, |w| {
let name = it.name.expect("proc-macros always have names");
match m.kind {
MacroKind::Bang => {
- wrap_item(w, |w| {
- write!(w, "{}!() {{ /* proc-macro */ }}", name);
- });
+ write!(w, "{}!() {{ /* proc-macro */ }}", name);
}
MacroKind::Attr => {
- wrap_item(w, |w| {
- write!(w, "#[{}]", name);
- });
+ write!(w, "#[{}]", name);
}
MacroKind::Derive => {
- wrap_item(w, |w| {
- write!(w, "#[derive({})]", name);
- if !m.helpers.is_empty() {
- w.push_str("\n{\n");
- w.push_str(" // Attributes available to this derive:\n");
- for attr in &m.helpers {
- writeln!(w, " #[{}]", attr);
- }
- w.push_str("}\n");
+ write!(w, "#[derive({})]", name);
+ if !m.helpers.is_empty() {
+ w.push_str("\n{\n");
+ w.push_str(" // Attributes available to this derive:\n");
+ for attr in &m.helpers {
+ writeln!(w, " #[{}]", attr);
}
- });
+ w.push_str("}\n");
+ }
}
}
});
}
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- let tcx = cx.tcx();
- render_attributes_in_code(w, it);
+ wrap_item(w, |w| {
+ let tcx = cx.tcx();
+ render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}const {name}: {typ}",
- vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- name = it.name.unwrap(),
- typ = c.type_.print(cx),
- );
+ write!(
+ w,
+ "{vis}const {name}: {typ}",
+ vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ name = it.name.unwrap(),
+ typ = c.type_.print(cx),
+ );
- // FIXME: The code below now prints
- // ` = _; // 100i32`
- // if the expression is
- // `50 + 50`
- // which looks just wrong.
- // Should we print
- // ` = 100i32;`
- // instead?
-
- let value = c.value(tcx);
- let is_literal = c.is_literal(tcx);
- let expr = c.expr(tcx);
- if value.is_some() || is_literal {
- write!(w, " = {expr};", expr = Escape(&expr));
- } else {
- w.write_str(";");
- }
+ // FIXME: The code below now prints
+ // ` = _; // 100i32`
+ // if the expression is
+ // `50 + 50`
+ // which looks just wrong.
+ // Should we print
+ // ` = 100i32;`
+ // instead?
+
+ let value = c.value(tcx);
+ let is_literal = c.is_literal(tcx);
+ let expr = c.expr(tcx);
+ if value.is_some() || is_literal {
+ write!(w, " = {expr};", expr = Escape(&expr));
+ } else {
+ w.write_str(";");
+ }
- if !is_literal {
- if let Some(value) = &value {
- let value_lowercase = value.to_lowercase();
- let expr_lowercase = expr.to_lowercase();
+ if !is_literal {
+ if let Some(value) = &value {
+ let value_lowercase = value.to_lowercase();
+ let expr_lowercase = expr.to_lowercase();
- if value_lowercase != expr_lowercase
- && value_lowercase.trim_end_matches("i32") != expr_lowercase
- {
- write!(w, " // {value}", value = Escape(value));
- }
+ if value_lowercase != expr_lowercase
+ && value_lowercase.trim_end_matches("i32") != expr_lowercase
+ {
+ write!(w, " // {value}", value = Escape(value));
}
}
- });
+ }
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_code(w, it);
- render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
- });
+ wrap_item(w, |w| {
+ render_attributes_in_code(w, it);
+ render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
});
document(w, cx, it, None, HeadingOffset::H2);
}
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- render_attributes_in_code(w, it);
- write!(
- w,
- "{vis}static {mutability}{name}: {typ}",
- vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
- mutability = s.mutability.print_with_space(),
- name = it.name.unwrap(),
- typ = s.type_.print(cx)
- );
- });
+ wrap_item(w, |w| {
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ "{vis}static {mutability}{name}: {typ}",
+ vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+ mutability = s.mutability.print_with_space(),
+ name = it.name.unwrap(),
+ typ = s.type_.print(cx)
+ );
});
document(w, cx, it, None, HeadingOffset::H2)
}
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
- wrap_into_item_decl(w, |w| {
- wrap_item(w, |w| {
- w.write_str("extern {\n");
- render_attributes_in_code(w, it);
- write!(
- w,
- " {}type {};\n}}",
- visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
- it.name.unwrap(),
- );
- });
+ wrap_item(w, |w| {
+ w.write_str("extern {\n");
+ render_attributes_in_code(w, it);
+ write!(
+ w,
+ " {}type {};\n}}",
+ visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
+ it.name.unwrap(),
+ );
});
document(w, cx, it, None, HeadingOffset::H2);
bounds
}
-fn wrap_into_item_decl<F>(w: &mut Buffer, f: F)
-where
- F: FnOnce(&mut Buffer),
-{
- w.write_str("<div class=\"item-decl\">");
- f(w);
- w.write_str("</div>")
-}
-
fn wrap_item<F>(w: &mut Buffer, f: F)
where
F: FnOnce(&mut Buffer),
{
- w.write_str(r#"<pre class="rust"><code>"#);
+ w.write_str(r#"<pre class="rust item-decl"><code>"#);
f(w);
w.write_str("</code></pre>");
}
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
+use super::{collect_paths_for_type, ensure_trailing_slash, Context};
use crate::clean::Crate;
use crate::config::{EmitType, RenderOptions};
use crate::docfs::PathError;
root_path: "./",
static_root_path: shared.static_root_path.as_deref(),
description: "List of crates",
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
-use crate::html::render::{Context, BASIC_KEYWORDS};
+use crate::html::render::Context;
use crate::visit::DocVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
root_path: &root_path,
static_root_path: shared.static_root_path.as_deref(),
description: &desc,
- keywords: BASIC_KEYWORDS,
resource_suffix: &shared.resource_suffix,
};
let v = layout::render(
padding: 14px;
line-height: 1.5; /* https://github.com/rust-lang/rust/issues/105906 */
}
-.item-decl pre {
+pre.item-decl {
overflow-x: auto;
}
/* This rule allows to have scrolling on the X axis. */
line-height: 1.5;
color: inherit;
}
+#search-tabs button:not(.selected) {
+ background-color: var(--search-tab-button-not-selected-background);
+ border-top-color: var(--search-tab-button-not-selected-border-top-color);
+}
+#search-tabs button:hover, #search-tabs button.selected {
+ background-color: var(--search-tab-button-selected-background);
+ border-top-color: var(--search-tab-button-selected-border-top-color);
+}
#search-tabs .count {
font-size: 1rem;
--search-results-alias-color: #c5c5c5;
--search-results-grey-color: #999;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: none;
+ --search-tab-button-not-selected-background: transparent !important;
+ --search-tab-button-selected-border-top-color: none;
+ --search-tab-button-selected-background: #141920 !important;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ff7733;
}
#search-tabs > button.selected {
- background-color: #141920 !important;
border-bottom: 1px solid #ffb44c !important;
border-top: none;
}
-
#search-tabs > button:not(.selected) {
- background-color: transparent !important;
border: none;
+ background-color: transparent !important;
}
-
#search-tabs > button:hover {
border-bottom: 1px solid rgba(242, 151, 24, 0.3);
}
-/* rules that this theme does not need to set, here to satisfy the rule checker */
-/* note that a lot of these are partially set in some way (meaning they are set
-individually rather than as a group) */
-/* FIXME: these rules should be at the bottom of the file but currently must be
-above the `@media (max-width: 700px)` rules due to a bug in the css checker */
-/* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-#search-tabs > button:hover, #search-tabs > button.selected {}
-
#settings-menu > a img {
filter: invert(100);
}
--search-results-alias-color: #fff;
--search-results-grey-color: #ccc;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #252525;
+ --search-tab-button-not-selected-background: #252525;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #353535;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;
--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
}
-
-#search-tabs > button:not(.selected) {
- background-color: #252525;
- border-top-color: #252525;
-}
-
-#search-tabs > button:hover, #search-tabs > button.selected {
- border-top-color: #0089ff;
- background-color: #353535;
-}
--search-results-alias-color: #000;
--search-results-grey-color: #999;
--search-tab-title-count-color: #888;
+ --search-tab-button-not-selected-border-top-color: #e6e6e6;
+ --search-tab-button-not-selected-background: #e6e6e6;
+ --search-tab-button-selected-border-top-color: #0089ff;
+ --search-tab-button-selected-background: #ffffff;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
}
-
-#search-tabs > button:not(.selected) {
- background-color: #e6e6e6;
- border-top-color: #e6e6e6;
-}
-
-#search-tabs > button:hover, #search-tabs > button.selected {
- background-color: #ffffff;
- border-top-color: #0089ff;
-}
// Local js definitions:
-/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */
+/* global getSettingValue, getVirtualKey, updateLocalStorage, updateTheme */
/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */
/* global MAIN_ID, getVar, getSettingsButton */
case "theme":
case "preferred-dark-theme":
case "preferred-light-theme":
- updateSystemTheme();
+ updateTheme();
updateLightAndDark();
break;
case "line-numbers":
}
}
-// This function is called from "main.js".
-// eslint-disable-next-line no-unused-vars
-function useSystemTheme(value) {
- if (value === undefined) {
- value = true;
- }
-
- updateLocalStorage("use-system-theme", value);
-
- // update the toggle if we're on the settings page
- const toggle = document.getElementById("use-system-theme");
- if (toggle && toggle instanceof HTMLInputElement) {
- toggle.checked = value;
- }
-}
-
-const updateSystemTheme = (function() {
- if (!window.matchMedia) {
- // fallback to the CSS computed value
- return () => {
- const cssTheme = getComputedStyle(document.documentElement)
- .getPropertyValue("content");
-
- switchTheme(
- window.currentTheme,
- window.mainTheme,
- JSON.parse(cssTheme) || "light",
- true
- );
+const updateTheme = (function() {
+ /**
+ * Update the current theme to match whatever the current combination of
+ * * the preference for using the system theme
+ * (if this is the case, the value of preferred-light-theme, if the
+ * system theme is light, otherwise if dark, the value of
+ * preferred-dark-theme.)
+ * * the preferred theme
+ * … dictates that it should be.
+ */
+ function updateTheme() {
+ const use = (theme, saveTheme) => {
+ switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme);
};
- }
-
- // only listen to (prefers-color-scheme: dark) because light is the default
- const mql = window.matchMedia("(prefers-color-scheme: dark)");
- function handlePreferenceChange(mql) {
- const use = theme => {
- switchTheme(window.currentTheme, window.mainTheme, theme, true);
- };
// maybe the user has disabled the setting in the meantime!
if (getSettingValue("use-system-theme") !== "false") {
const lightTheme = getSettingValue("preferred-light-theme") || "light";
const darkTheme = getSettingValue("preferred-dark-theme") || "dark";
- if (mql.matches) {
- use(darkTheme);
+ if (isDarkMode()) {
+ use(darkTheme, true);
} else {
// prefers a light theme, or has no preference
- use(lightTheme);
+ use(lightTheme, true);
}
// note: we save the theme so that it doesn't suddenly change when
// the user disables "use-system-theme" and reloads the page or
// navigates to another page
} else {
- use(getSettingValue("theme"));
+ use(getSettingValue("theme"), false);
}
}
- mql.addListener(handlePreferenceChange);
+ // This is always updated below to a function () => bool.
+ let isDarkMode;
- return () => {
- handlePreferenceChange(mql);
- };
-})();
+ // Determine the function for isDarkMode, and if we have
+ // `window.matchMedia`, set up an event listener on the preferred color
+ // scheme.
+ //
+ // Otherwise, fall back to the prefers-color-scheme value CSS captured in
+ // the "content" property.
+ if (window.matchMedia) {
+ // only listen to (prefers-color-scheme: dark) because light is the default
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
-function switchToSavedTheme() {
- switchTheme(
- window.currentTheme,
- window.mainTheme,
- getSettingValue("theme") || "light",
- false
- );
-}
+ isDarkMode = () => mql.matches;
+
+ if (mql.addEventListener) {
+ mql.addEventListener("change", updateTheme);
+ } else {
+ // This is deprecated, see:
+ // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener
+ mql.addListener(updateTheme);
+ }
+ } else {
+ // fallback to the CSS computed value
+ const cssContent = getComputedStyle(document.documentElement)
+ .getPropertyValue("content");
+ // (Note: the double-quotes come from that this is a CSS value, which
+ // might be a length, string, etc.)
+ const cssColorScheme = cssContent || "\"light\"";
+ isDarkMode = () => (cssColorScheme === "\"dark\"");
+ }
+
+ return updateTheme;
+})();
if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
// update the preferred dark theme if the user is already using a dark theme
&& darkThemes.indexOf(localStoredTheme) >= 0) {
updateLocalStorage("preferred-dark-theme", localStoredTheme);
}
-
- // call the function to initialize the theme at least once!
- updateSystemTheme();
-} else {
- switchToSavedTheme();
}
+updateTheme();
+
if (getSettingValue("source-sidebar-show") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `<html>` element instead.
// specifically when talking to a remote website with no caching.
window.addEventListener("pageshow", ev => {
if (ev.persisted) {
- setTimeout(switchToSavedTheme, 0);
+ setTimeout(updateTheme, 0);
}
});
<meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
<meta name="generator" content="rustdoc"> {#- -#}
<meta name="description" content="{{page.description}}"> {#- -#}
- <meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {#- -#}
StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
_5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
}
bb1: {
StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
_5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
- _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
}
bb1: {
+// compile-flags: -Zmir-enable-passes=-NormalizeArrayLen
// Check that we do not insert StorageDead at each target if StorageDead was never seen
// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff
let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20
let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21
-+ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
bb0: {
StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
_7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
_6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
}
let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16
let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17
-+ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
bb0: {
StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27
StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
_7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
_6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21
- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
-+ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27
}
let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57
let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
bb0: {
StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
_3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
_2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
}
let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65
let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
bb0: {
StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
_3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
_2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8
- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
-+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14
}
--- /dev/null
+- // MIR for `array_len_raw` before NormalizeArrayLen
++ // MIR for `array_len_raw` after NormalizeArrayLen
+
+ fn array_len_raw(_1: [u8; N]) -> usize {
+ debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:38: +0:41
+ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:55: +0:60
+ let _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12
+ let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ let _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:27
+ let _7: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:14: +3:19
+ scope 1 {
+ debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12
+ let _5: *const [u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12
+ scope 2 {
+ debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12
+ scope 3 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12
+ StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ _4 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ _3 = &(*_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25
+ StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:24: +1:25
+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:26
+ StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12
+ _5 = &raw const (*_2); // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27
+ StorageLive(_7); // scope 2 at $DIR/lower_array_len.rs:+3:14: +3:19
+ _7 = &(*_5); // scope 3 at $DIR/lower_array_len.rs:+3:14: +3:19
+ _6 = &(*_7); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27
+- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27
++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27
+ goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27
+ }
+
+ bb1: {
+ StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:26: +3:27
+ StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2
+ StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2
+ StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2
+ }
+ }
+
--- /dev/null
+- // MIR for `array_len_reborrow` before NormalizeArrayLen
++ // MIR for `array_len_reborrow` after NormalizeArrayLen
+
+ fn array_len_reborrow(_1: [u8; N]) -> usize {
+ debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:50
+ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:64: +0:69
+ let _2: &mut [u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12
+ let mut _3: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ let mut _4: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:14
+ scope 1 {
+ debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12
+ let _5: &[u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12
+ scope 2 {
+ debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12
+ StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ _4 = &mut _1; // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ _3 = &mut (*_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ _2 = move _3 as &mut [u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33
+ StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:32: +1:33
+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:33: +1:34
+ StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12
+ _5 = &(*_2); // scope 1 at $DIR/lower_array_len.rs:+2:15: +2:20
+ StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14
+ _6 = &(*_5); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14
+- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14
++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14
+ goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14
+ }
+
+ bb1: {
+ StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:13: +3:14
+ StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2
+ StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2
+ }
+ }
+
arr.len()
}
+// EMIT_MIR lower_array_len.array_len_reborrow.NormalizeArrayLen.diff
+pub fn array_len_reborrow<const N: usize>(mut arr: [u8; N]) -> usize {
+ let arr: &mut [_] = &mut arr;
+ let arr = &*arr;
+ arr.len()
+}
+
+// EMIT_MIR lower_array_len.array_len_raw.NormalizeArrayLen.diff
+pub fn array_len_raw<const N: usize>(arr: [u8; N]) -> usize {
+ let arr: &[_] = &arr;
+ let arr = std::ptr::addr_of!(*arr);
+ unsafe { &*arr }.len()
+}
+
fn main() {
let _ = array_bound(3, &[0, 1, 2, 3]);
let mut tmp = [0, 1, 2, 3, 4];
let _ = array_bound_mut(3, &mut [0, 1, 2, 3]);
let _ = array_len(&[0]);
let _ = array_len_by_value([0, 2]);
+ let _ = array_len_reborrow([0, 2]);
+ let _ = array_len_raw([0, 2]);
}
+++ /dev/null
-// MIR for `array_bound` after PreCodegen
-
-fn array_bound(_1: usize, _2: &[u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41
- debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
- switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- }
-
- bb1: {
- _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- }
-
- bb2: {
- _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
- }
-
- bb3: {
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11
- goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6
- }
-
- bb4: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6
- return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2
- }
-}
+++ /dev/null
-// MIR for `array_bound_mut` after PreCodegen
-
-fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 {
- debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45
- debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59
- let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80
- let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- let _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- let mut _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- let mut _9: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
-
- bb0: {
- StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27
- _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27
- switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27
- }
-
- bb1: {
- _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- }
-
- bb2: {
- _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21
- goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
- }
-
- bb3: {
- StorageLive(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- _7 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16
- _8 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- _9 = Lt(const 0_usize, _8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17
- }
-
- bb4: {
- (*_2)[_7] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22
- StorageDead(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23
- _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11
- goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6
- }
-
- bb5: {
- StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6
- return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2
- }
-}
+++ /dev/null
-// MIR for `array_len` after PreCodegen
-
-fn array_len(_1: &[u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57
-
- bb0: {
- _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
- return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// MIR for `array_len_by_value` after PreCodegen
-
-fn array_len_by_value(_1: [u8; N]) -> usize {
- debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46
- let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65
-
- bb0: {
- _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14
- return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
-
-// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir
-pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 {
- if index < slice.len() {
- slice[index]
- } else {
- 42
- }
-}
-
-// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir
-pub fn array_bound_mut<const N: usize>(index: usize, slice: &mut [u8; N]) -> u8 {
- if index < slice.len() {
- slice[index]
- } else {
- slice[0] = 42;
-
- 42
- }
-}
-
-// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir
-pub fn array_len<const N: usize>(arr: &[u8; N]) -> usize {
- arr.len()
-}
-
-// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir
-pub fn array_len_by_value<const N: usize>(arr: [u8; N]) -> usize {
- arr.len()
-}
-
-fn main() {
- let _ = array_bound(3, &[0, 1, 2, 3]);
- let mut tmp = [0, 1, 2, 3, 4];
- let _ = array_bound_mut(3, &mut [0, 1, 2, 3]);
- let _ = array_len(&[0]);
- let _ = array_len_by_value([0, 2]);
-}
touch $(SESSION_DIR)
# Check exit code is 1 for an error, and not 101 for ICE.
$(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ]
- $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)
+ $(CGREP) "could not create incremental compilation crate directory" < $(OUTPUT_FILE)
# -v tests are fragile, hopefully this text won't change
$(CGREP) -v "internal compiler error" < $(OUTPUT_FILE)
// Check that their content is inside <pre><code>
assert-count: (".example-wrap pre > code", 4)
// Check that function signature is inside <pre><code>
-assert: ".item-decl pre.rust > code"
+assert: "pre.rust.item-decl > code"
goto: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
-assert: ".item-decl pre.rust > code"
+assert: "pre.rust.item-decl > code"
goto: "file://" + |DOC_PATH| + "/test_docs/enum.AnEnum.html"
-assert: ".item-decl pre.rust > code"
+assert: "pre.rust.item-decl > code"
goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html"
-assert: ".item-decl pre.rust > code"
+assert: "pre.rust.item-decl > code"
goto: "file://" + |DOC_PATH| + "/test_docs/type.SomeType.html"
-assert: ".item-decl pre.rust > code"
+assert: "pre.rust.item-decl > code"
// This test checks that the font weight is correctly applied.
goto: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html"
-assert-css: ("//*[@class='item-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert-css: ("//*[@class='rust item-decl']//a[text()='Alias']", {"font-weight": "400"})
assert-css: (
"//*[@class='structfield small-section-header']//a[text()='Alias']",
{"font-weight": "400"},
// This is a complex selector, so here's how it works:
//
-// * //*[@class='item-decl'] — selects element of any tag with classes docblock and item-decl
-// * /pre[@class='rust'] — selects immediate child with tag pre and class rust
+// * //pre[@class='rust item-decl'] — selects item-decl code block
// * /code — selects immediate child with tag code
// * /a[@class='constant'] — selects immediate child with tag a and class constant
// * //text() — selects child that is text node
// This uses '/parent::*' as a proxy for the style of the text node.
// We can't just select the '<a>' because intermediate tags could be added.
assert-count: (
- "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
+ "//pre[@class='rust item-decl']/code/a[@class='constant']//text()/parent::*",
1,
)
assert-css: (
- "//*[@class='item-decl']/pre[@class='rust']/code/a[@class='constant']//text()/parent::*",
+ "//pre[@class='rust item-decl']/code/a[@class='constant']//text()/parent::*",
{"font-weight": "400"},
)
// This test checks that code blocks in list are supported.
goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
goto: "./fn.check_list_code_block.html"
-assert: (".item-decl pre.rust")
+assert: ("pre.rust.item-decl")
// Logically, the <body> scroll width should be the width of the window.
assert-property: ("body", {"scrollWidth": "1100"})
// However, since there is overflow in the type declaration, its scroll width is bigger.
-assert-property: (".item-decl pre", {"scrollWidth": "1324"})
+assert-property: ("pre.item-decl", {"scrollWidth": "1324"})
// In the table-ish view on the module index, the name should not be wrapped more than necessary.
goto: "file://" + |DOC_PATH| + "/lib2/too_long/index.html"
// We now check that the section width hasn't grown because of it.
assert-property: ("#main-content", {"scrollWidth": "840"})
// And now checking that it has scrollable content.
-assert-property: (".item-decl pre", {"scrollWidth": "1103"})
+assert-property: ("pre.item-decl", {"scrollWidth": "1103"})
// ... and constant.
// On a sidenote, it also checks that the (very) long title isn't changing the docblock width.
// We now check that the section width hasn't grown because of it.
assert-property: ("#main-content", {"scrollWidth": "840"})
// And now checking that it has scrollable content.
-assert-property: (".item-decl pre", {"scrollWidth": "950"})
+assert-property: ("pre.item-decl", {"scrollWidth": "950"})
// On mobile:
size: (600, 600)
goto: "file://" + |DOC_PATH| + "/lib2/scroll_traits/trait.Iterator.html"
click: ".item-decl .type-contents-toggle"
-assert-property: (".item-decl > pre", {"scrollLeft": 0})
-scroll-to: "//*[@class='item-decl']//details/a[text()='String']"
-assert-property-false: (".item-decl > pre", {"scrollLeft": 0})
+assert-property: ("pre.item-decl", {"scrollLeft": 0})
+scroll-to: "//*[@class='rust item-decl']//details/a[text()='String']"
+assert-property-false: ("pre.item-decl", {"scrollLeft": 0})
// Then on an item without "hidden methods".
goto: "file://" + |DOC_PATH| + "/lib2/scroll_traits/trait.TraitWithLongItemsName.html"
-assert-property: (".item-decl > pre", {"scrollLeft": 0})
-scroll-to: "//*[@class='item-decl']//code/a[text()='String']"
-assert-property-false: (".item-decl > pre", {"scrollLeft": 0})
+assert-property: ("pre.item-decl", {"scrollLeft": 0})
+scroll-to: "//*[@class='rust item-decl']//code/a[text()='String']"
+assert-property-false: ("pre.item-decl", {"scrollLeft": 0})
pub struct MyBox<T: ?Sized>(*const T);
// @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_slice_u32 - '//pre[@class="rust item-decl"]/code'
pub fn alpha() -> &'static [u32; 1] {
loop {}
}
// @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_slice_generic - '//pre[@class="rust item-decl"]/code'
pub fn beta<T>() -> &'static [T; 1] {
loop {}
}
// @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_box_u32 - '//pre[@class="rust item-decl"]/code'
pub fn gamma() -> MyBox<[u32; 1]> {
loop {}
}
// @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_box_generic - '//pre[@class="rust item-decl"]/code'
pub fn delta<T>() -> MyBox<[T; 1]> {
loop {}
}
pub trait Foo {
- // @has assoc_consts/trait.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has assoc_consts/trait.Foo.html '//pre[@class="rust item-decl"]' \
// 'const FOO: usize = 13usize;'
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
const FOO: usize = 12 + 1;
}
// @has foo/type.AsExprOf.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
+// @has - '//pre[@class="rust item-decl"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;
}
// @has assoc_types/fn.use_output.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' '-> &T::Output'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
+// @has - '//pre[@class="rust item-decl"]' '-> &T::Output'
+// @has - '//pre[@class="rust item-decl"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output {
obj.index(index)
}
}
// @has assoc_types/fn.use_input.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'T::Input'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//pre[@class="rust item-decl"]' 'T::Input'
+// @has - '//pre[@class="rust item-decl"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { }
// @has assoc_types/fn.cmp_input.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where T::Input: PartialEq<U::Input>'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
+// @has - '//pre[@class="rust item-decl"]' 'where T::Input: PartialEq<U::Input>'
+// @has - '//pre[@class="rust item-decl"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
where T::Input: PartialEq<U::Input>
{
// edition:2018
-// @has async_fn/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn foo() -> Option<Foo>'
+// @has async_fn/fn.foo.html '//pre[@class="rust item-decl"]' 'pub async fn foo() -> Option<Foo>'
pub async fn foo() -> Option<Foo> {
None
}
-// @has async_fn/fn.bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn bar(a: i32, b: i32) -> i32'
+// @has async_fn/fn.bar.html '//pre[@class="rust item-decl"]' 'pub async fn bar(a: i32, b: i32) -> i32'
pub async fn bar(a: i32, b: i32) -> i32 {
0
}
-// @has async_fn/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn baz<T>(a: T) -> T'
+// @has async_fn/fn.baz.html '//pre[@class="rust item-decl"]' 'pub async fn baz<T>(a: T) -> T'
pub async fn baz<T>(a: T) -> T {
a
}
-// @has async_fn/fn.qux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async unsafe fn qux() -> char'
+// @has async_fn/fn.qux.html '//pre[@class="rust item-decl"]' 'pub async unsafe fn qux() -> char'
pub async unsafe fn qux() -> char {
'âš '
}
-// @has async_fn/fn.mut_args.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_args(a: usize)'
+// @has async_fn/fn.mut_args.html '//pre[@class="rust item-decl"]' 'pub async fn mut_args(a: usize)'
pub async fn mut_args(mut a: usize) {}
-// @has async_fn/fn.mut_ref.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn mut_ref(x: i32)'
+// @has async_fn/fn.mut_ref.html '//pre[@class="rust item-decl"]' 'pub async fn mut_ref(x: i32)'
pub async fn mut_ref(ref mut x: i32) {}
trait Bar {}
impl Bar for () {}
-// @has async_fn/fn.quux.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn quux() -> impl Bar'
+// @has async_fn/fn.quux.html '//pre[@class="rust item-decl"]' 'pub async fn quux() -> impl Bar'
pub async fn quux() -> impl Bar {
()
}
pub trait Trait<const N: usize> {}
// @has async_fn/fn.const_generics.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
+// @has - '//pre[@class="rust item-decl"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}
// test that elided lifetimes are properly elided and not displayed as `'_`
// regression test for #63037
// @has async_fn/fn.elided.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn elided(foo: &str) -> &str'
+// @has - '//pre[@class="rust item-decl"]' 'pub async fn elided(foo: &str) -> &str'
pub async fn elided(foo: &str) -> &str {}
// This should really be shown as written, but for implementation reasons it's difficult.
// See `impl Clean for TyKind::Ref`.
// @has async_fn/fn.user_elided.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn user_elided(foo: &str) -> &str'
+// @has - '//pre[@class="rust item-decl"]' 'pub async fn user_elided(foo: &str) -> &str'
pub async fn user_elided(foo: &'_ str) -> &str {}
// @has async_fn/fn.static_trait.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
+// @has - '//pre[@class="rust item-decl"]' 'pub async fn static_trait(foo: &str) -> Box<dyn Bar>'
pub async fn static_trait(foo: &str) -> Box<dyn Bar> {}
// @has async_fn/fn.lifetime_for_trait.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
+// @has - '//pre[@class="rust item-decl"]' "pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_>"
pub async fn lifetime_for_trait(foo: &str) -> Box<dyn Bar + '_> {}
// @has async_fn/fn.elided_in_input_trait.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
+// @has - '//pre[@class="rust item-decl"]' "pub async fn elided_in_input_trait(t: impl Pattern<'_>)"
pub async fn elided_in_input_trait(t: impl Pattern<'_>) {}
struct AsyncFdReadyGuard<'a, T> { x: &'a T }
// test named lifetimes, just in case
// @has async_fn/fn.named.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
+// @has - '//pre[@class="rust item-decl"]' "pub async fn named<'a, 'b>(foo: &'a str) -> &'b str"
pub async fn named<'a, 'b>(foo: &'a str) -> &'b str {}
// @has async_fn/fn.named_trait.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
+// @has - '//pre[@class="rust item-decl"]' "pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b>"
pub async fn named_trait<'a, 'b>(foo: impl Pattern<'a>) -> impl Pattern<'b> {}
#![crate_name = "foo"]
// @has 'foo/fn.f.html'
-// @has - //*[@'class="item-decl"]' '#[export_name = "f"] pub fn f()'
+// @has - //*[@'class="rust item-decl"]' '#[export_name = "f"] pub fn f()'
#[export_name = "\
f"]
pub fn f() {}
#![crate_name = "foo"]
-// @has foo/fn.f.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[no_mangle]'
+// @has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[no_mangle]'
#[no_mangle]
pub extern "C" fn f() {}
-// @has foo/fn.g.html '//div[@class="item-decl"]/pre[@class="rust"]' '#[export_name = "bar"]'
+// @has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[export_name = "bar"]'
#[export_name = "bar"]
pub extern "C" fn g() {}
-// @has foo/struct.Repr.html '//div[@class="item-decl"]' '#[repr(C, align(8))]'
+// @has foo/struct.Repr.html '//pre[@class="rust item-decl"]' '#[repr(C, align(8))]'
#[repr(C, align(8))]
pub struct Repr;
// @has issue_85454/trait.FromResidual.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
pub trait FromResidual<R = <Self as Try>::Residual> {
fn from_residual(residual: R) -> Self;
}
#![crate_name = "foo"]
// @has foo/fn.bar.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const fn bar() -> '
+// @has - '//pre[@class="rust item-decl"]' 'pub const fn bar() -> '
/// foo
pub const fn bar() -> usize {
2
use std::ops::Add;
-// @has foo/struct.Simd.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Simd<T, const WIDTH: usize>'
+// @has foo/struct.Simd.html '//pre[@class="rust item-decl"]' 'pub struct Simd<T, const WIDTH: usize>'
pub struct Simd<T, const WIDTH: usize> {
inner: T,
}
#![crate_name = "foo"]
-// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
// 'pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(_);'
pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
#![crate_name = "foo"]
extern crate extern_crate;
-// @has foo/fn.extern_fn.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.extern_fn.html '//pre[@class="rust item-decl"]' \
// 'pub fn extern_fn<const N: usize>() -> impl Iterator<Item = [u8; N]>'
pub use extern_crate::extern_fn;
-// @has foo/struct.ExternTy.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/struct.ExternTy.html '//pre[@class="rust item-decl"]' \
// 'pub struct ExternTy<const N: usize> {'
pub use extern_crate::ExternTy;
-// @has foo/type.TyAlias.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/type.TyAlias.html '//pre[@class="rust item-decl"]' \
// 'type TyAlias<const N: usize> = ExternTy<N>;'
pub use extern_crate::TyAlias;
-// @has foo/trait.WTrait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/trait.WTrait.html '//pre[@class="rust item-decl"]' \
// 'pub trait WTrait<const N: usize, const M: usize>'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn hey<const P: usize>() -> usize'
+// @has - '//pre[@class="rust item-decl"]' 'fn hey<const P: usize>() -> usize'
pub use extern_crate::WTrait;
-// @has foo/trait.Trait.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/trait.Trait.html '//pre[@class="rust item-decl"]' \
// 'pub trait Trait<const N: usize>'
// @has - '//*[@id="impl-Trait%3C1%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<1> for u8'
// @has - '//*[@id="impl-Trait%3C2%3E-for-u8"]//h3[@class="code-header"]' 'impl Trait<2> for u8'
impl Trait<{1 + 2}> for u8 {}
impl<const N: usize> Trait<N> for [u8; N] {}
-// @has foo/struct.Foo.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
// 'pub struct Foo<const N: usize>where u8: Trait<N>'
pub struct Foo<const N: usize> where u8: Trait<N>;
-// @has foo/struct.Bar.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Bar<T, const N: usize>(_)'
+// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header"]' 'impl<const M: usize> Foo<M>where u8: Trait<M>'
}
}
-// @has foo/fn.test.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.test.html '//pre[@class="rust item-decl"]' \
// 'pub fn test<const N: usize>() -> impl Trait<N>where u8: Trait<N>'
pub fn test<const N: usize>() -> impl Trait<N> where u8: Trait<N> {
2u8
}
-// @has foo/fn.a_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.a_sink.html '//pre[@class="rust item-decl"]' \
// 'pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N>'
pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
v
}
-// @has foo/fn.b_sink.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.b_sink.html '//pre[@class="rust item-decl"]' \
// 'pub async fn b_sink<const N: usize>(_: impl Trait<N>)'
pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}
-// @has foo/fn.concrete.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.concrete.html '//pre[@class="rust item-decl"]' \
// 'pub fn concrete() -> [u8; 22]'
pub fn concrete() -> [u8; 3 + std::mem::size_of::<u64>() << 1] {
Default::default()
}
-// @has foo/type.Faz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/type.Faz.html '//pre[@class="rust item-decl"]' \
// 'type Faz<const N: usize> = [u8; N];'
pub type Faz<const N: usize> = [u8; N];
-// @has foo/type.Fiz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/type.Fiz.html '//pre[@class="rust item-decl"]' \
// 'type Fiz<const N: usize> = [[u8; N]; 48];'
pub type Fiz<const N: usize> = [[u8; N]; 3 << 4];
}
}
-// @has foo/struct.Foz.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/struct.Foz.html '//pre[@class="rust item-decl"]' \
// 'pub struct Foz<const N: usize>(_);'
define_me!(Foz<N>);
const ASSOC: usize = N;
}
-// @has foo/fn.q_user.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/fn.q_user.html '//pre[@class="rust item-decl"]' \
// 'pub fn q_user() -> [u8; 13]'
pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {
[0; <[u8; 13] as Q>::ASSOC]
}
-// @has foo/union.Union.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/union.Union.html '//pre[@class="rust item-decl"]' \
// 'pub union Union<const N: usize>'
pub union Union<const N: usize> {
// @has - //pre "pub arr: [u8; N]"
pub another_arr: [(); N],
}
-// @has foo/enum.Enum.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/enum.Enum.html '//pre[@class="rust item-decl"]' \
// 'pub enum Enum<const N: usize>'
pub enum Enum<const N: usize> {
// @has - //pre "Variant([u8; N])"
Unsorted,
}
-// @has foo/struct.VSet.html '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct VSet<T, const ORDER: Order>'
+// @has foo/struct.VSet.html '//pre[@class="rust item-decl"]' 'pub struct VSet<T, const ORDER: Order>'
// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
pub struct VSet<T, const ORDER: Order> {
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
-// @has foo/struct.Ice.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/struct.Ice.html '//pre[@class="rust item-decl"]' \
// 'pub struct Ice<const N: usize>;'
pub struct Ice<const N: usize> where [(); N + 1]:;
#![crate_name = "foo"]
-// @has foo/type.CellIndex.html '//div[@class="item-decl"]/pre[@class="rust"]' 'type CellIndex<const D: usize> = [i64; D];'
+// @has foo/type.CellIndex.html '//pre[@class="rust item-decl"]' 'type CellIndex<const D: usize> = [i64; D];'
pub type CellIndex<const D: usize> = [i64; D];
extern "rust-intrinsic" {
// @has 'foo/fn.transmute.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U'
+ // @has - '//pre[@class="rust item-decl"]' 'pub const unsafe extern "rust-intrinsic" fn transmute<T, U>(_: T) -> U'
#[stable(since="1.0.0", feature="rust1")]
#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
pub fn transmute<T, U>(_: T) -> U;
// @has 'foo/fn.unreachable.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+ // @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
#[stable(since="1.0.0", feature="rust1")]
pub fn unreachable() -> !;
}
extern "C" {
// @has 'foo/fn.needs_drop.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+ // @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn needs_drop() -> !'
#[stable(since="1.0.0", feature="rust1")]
pub fn needs_drop() -> !;
}
#![crate_name = "foo"]
// @has 'foo/constant.HOUR_IN_SECONDS.html'
-// @has - '//*[@class="item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64'
+// @has - '//*[@class="rust item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64'
pub const HOUR_IN_SECONDS: u64 = 60 * 60;
// @has 'foo/constant.NEGATIVE.html'
-// @has - '//*[@class="item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64'
+// @has - '//*[@class="rust item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64'
pub const NEGATIVE: i64 = -60 * 60;
// @has 'foo/trait.Write.html'
pub trait Write {
- // @snapshot 'declaration' - '//*[@class="item-decl"]//code'
+ // @snapshot 'declaration' - '//*[@class="rust item-decl"]//code'
fn poll_write(
self: Option<String>,
cx: &mut Option<String>,
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Enumerable {
+ const N: usize;
+}
+
+#[derive(Clone)]
+pub struct SymmetricGroup<S>
+where
+ S: Enumerable,
+ [(); S::N]: Sized,
+{
+ _phantom: std::marker::PhantomData<S>,
+}
+
+fn main() {}
#![crate_name = "foo"]
// @has foo/fn.f.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
+// @has - '//pre[@class="rust item-decl"]' 'pub fn f(callback: fn(len: usize, foo: u32))'
pub fn f(callback: fn(len: usize, foo: u32)) {}
// this test as long as one can ensure that private fields are not leaked!
//
// @has hide_complex_unevaluated_const_arguments/trait.Sub.html \
-// '//div[@class="item-decl"]/pre[@class="rust"]' \
+// '//pre[@class="rust item-decl"]' \
// 'pub trait Sub: Sup<{ _ }, { _ }> { }'
pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {}
extern crate inline_default_methods;
// @has inline_default_methods/trait.Foo.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(&self);'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(&mut self) { ... }'
+// @has - '//pre[@class="rust item-decl"]' 'fn bar(&self);'
+// @has - '//pre[@class="rust item-decl"]' 'fn foo(&mut self) { ... }'
pub use inline_default_methods::Foo;
// edition:2021
// @has user/type.Ty0.html
-// @has - '//*[@class="item-decl"]//code' "dyn for<'any> FnOnce(&'any str) -> bool + 'static"
+// @has - '//*[@class="rust item-decl"]//code' "dyn for<'any> FnOnce(&'any str) -> bool + 'static"
// FIXME(fmease): Hide default lifetime bound `'static`
pub use dyn_trait::Ty0;
// @has user/type.Ty1.html
-// @has - '//*[@class="item-decl"]//code' "dyn Display + 'obj"
+// @has - '//*[@class="rust item-decl"]//code' "dyn Display + 'obj"
pub use dyn_trait::Ty1;
// @has user/type.Ty2.html
-// @has - '//*[@class="item-decl"]//code' "dyn for<'a, 'r> Container<'r, Item<'a, 'static> = ()>"
+// @has - '//*[@class="rust item-decl"]//code' "dyn for<'a, 'r> Container<'r, Item<'a, 'static> = ()>"
pub use dyn_trait::Ty2;
// @has user/type.Ty3.html
-// @has - '//*[@class="item-decl"]//code' "&'s (dyn ToString + 's)"
+// @has - '//*[@class="rust item-decl"]//code' "&'s (dyn ToString + 's)"
// FIXME(fmease): Hide default lifetime bound, render "&'s dyn ToString"
pub use dyn_trait::Ty3;
// @has user/fn.func0.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func0(_: &dyn Fn())"
+// @has - '//pre[@class="rust item-decl"]' "func0(_: &dyn Fn())"
// FIXME(fmease): Show placeholder-lifetime bound, render "func0(_: &(dyn Fn() + '_))"
pub use dyn_trait::func0;
// @has user/fn.func1.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func1<'func>(_: &(dyn Fn() + 'func))"
+// @has - '//pre[@class="rust item-decl"]' "func1<'func>(_: &(dyn Fn() + 'func))"
pub use dyn_trait::func1;
extern crate impl_trait_aux;
// @has impl_trait/fn.func.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
+// @has - '//pre[@class="rust item-decl"]' "pub fn func<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
+// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func;
// @has impl_trait/fn.func2.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func2<T>("
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_y: impl Iterator<Item = u8>)"
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
+// @has - '//pre[@class="rust item-decl"]' "func2<T>("
+// @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
+// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>)"
+// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func2;
// @has impl_trait/fn.func3.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func3("
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
+// @has - '//pre[@class="rust item-decl"]' "func3("
+// @has - '//pre[@class="rust item-decl"]' "_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone)"
+// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func3;
// @has impl_trait/fn.func4.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func4<T>("
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "T: Iterator<Item = impl Clone>,"
+// @has - '//pre[@class="rust item-decl"]' "func4<T>("
+// @has - '//pre[@class="rust item-decl"]' "T: Iterator<Item = impl Clone>,"
pub use impl_trait_aux::func4;
// @has impl_trait/fn.func5.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "func5("
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where'
+// @has - '//pre[@class="rust item-decl"]' "func5("
+// @has - '//pre[@class="rust item-decl"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
+// @has - '//pre[@class="rust item-decl"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
+// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func5;
// @has impl_trait/fn.async_fn.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub async fn async_fn()"
+// @has - '//pre[@class="rust item-decl"]' "pub async fn async_fn()"
pub use impl_trait_aux::async_fn;
// @has impl_trait/struct.Foo.html
// edition: 2021
// @has usr/trait.U.html
-// @has - '//*[@class="item-decl"]' "pub trait U {"
+// @has - '//*[@class="rust item-decl"]' "pub trait U {"
// @has - '//*[@id="method.modified"]' \
// "fn modified(self) -> Self\
// where \
pub use issue_24183::U;
// @has usr/trait.S.html
-// @has - '//*[@class="item-decl"]' 'pub trait S: Sized {'
+// @has - '//*[@class="rust item-decl"]' 'pub trait S: Sized {'
pub use issue_24183::S;
}
// @has issue_20646/fn.fun.html \
-// '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait<Output = i32>'
+// '//pre[@class="rust item-decl"]' 'where T: Trait<Output = i32>'
pub fn fun<T>(_: T) where T: Trait<Output=i32> {}
pub mod reexport {
// '//*[@id="associatedtype.Output"]' \
// 'type Output'
// @has issue_20646/reexport/fn.fun.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'where T: Trait<Output = i32>'
+ // '//pre[@class="rust item-decl"]' 'where T: Trait<Output = i32>'
pub use issue_20646::{Trait, fun};
}
// @has issue_20727_2/trait.Add.html
pub trait Add<RHS = Self> {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add<RHS = Self> {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Add<RHS = Self> {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Output;'
type Output;
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+ // @has - '//pre[@class="rust item-decl"]' 'fn add(self, rhs: RHS) -> Self::Output;'
fn add(self, rhs: RHS) -> Self::Output;
}
// @has issue_20727_2/reexport/trait.Add.html
pub mod reexport {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Add<RHS = Self> {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output;'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn add(self, rhs: RHS) -> Self::Output;'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Add<RHS = Self> {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Output;'
+ // @has - '//pre[@class="rust item-decl"]' 'fn add(self, rhs: RHS) -> Self::Output;'
pub use issue_20727::Add;
}
// @has issue_20727_3/trait.Deref2.html
pub trait Deref2 {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Deref2 {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Target: Bar;'
type Target: Bar;
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
+ // @has - '//pre[@class="rust item-decl"]' 'fn deref(&self) -> Self::Target;'
fn deref(&self) -> Self::Target;
}
// @has issue_20727_3/reexport/trait.Deref2.html
pub mod reexport {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref2 {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: Bar;'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn deref(&self) -> Self::Target;'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Deref2 {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Target: Bar;'
+ // @has - '//pre[@class="rust item-decl"]' 'fn deref(&self) -> Self::Target;'
pub use issue_20727::Deref2;
}
// @has issue_20727_4/trait.Index.html
pub trait Index<Idx: ?Sized> {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Index<Idx: ?Sized> {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Index<Idx: ?Sized> {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Output: ?Sized'
type Output: ?Sized;
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// 'fn index(&self, index: Idx) -> &Self::Output'
fn index(&self, index: Idx) -> &Self::Output;
}
// @has issue_20727_4/trait.IndexMut.html
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// 'trait IndexMut<Idx: ?Sized>: Index<Idx> {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
}
pub mod reexport {
// @has issue_20727_4/reexport/trait.Index.html
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Index<Idx>where Idx: ?Sized,{'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Output: ?Sized'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' 'trait Index<Idx>where Idx: ?Sized,{'
+ // @has - '//pre[@class="rust item-decl"]' 'type Output: ?Sized'
+ // @has - '//pre[@class="rust item-decl"]' \
// 'fn index(&self, index: Idx) -> &Self::Output'
pub use issue_20727::Index;
// @has issue_20727_4/reexport/trait.IndexMut.html
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// 'trait IndexMut<Idx>: Index<Idx>where Idx: ?Sized,{'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;'
pub use issue_20727::IndexMut;
}
// @has issue_20727/trait.Deref.html
pub trait Deref {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
+ // @has - '//pre[@class="rust item-decl"]' 'trait Deref {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Target: ?Sized;'
type Target: ?Sized;
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' \
// "fn deref<'a>(&'a self) -> &'a Self::Target;"
fn deref<'a>(&'a self) -> &'a Self::Target;
}
// @has issue_20727/reexport/trait.Deref.html
pub mod reexport {
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'trait Deref {'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'type Target: ?Sized;'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' \
+ // @has - '//pre[@class="rust item-decl"]' 'trait Deref {'
+ // @has - '//pre[@class="rust item-decl"]' 'type Target: ?Sized;'
+ // @has - '//pre[@class="rust item-decl"]' \
// "fn deref<'a>(&'a self) -> &'a Self::Target;"
pub use issue_20727::Deref;
}
extern "C" {
// @has issue_22038/fn.foo1.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn foo1()'
+ // '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn foo1()'
pub fn foo1();
}
extern "system" {
// @has issue_22038/fn.foo2.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "system" fn foo2()'
+ // '//pre[@class="rust item-decl"]' 'pub unsafe extern "system" fn foo2()'
pub fn foo2();
}
// @has issue_22038/fn.bar.html \
-// '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "C" fn bar()'
+// '//pre[@class="rust item-decl"]' 'pub extern "C" fn bar()'
pub extern "C" fn bar() {}
// @has issue_22038/fn.baz.html \
-// '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "system" fn baz()'
+// '//pre[@class="rust item-decl"]' 'pub extern "system" fn baz()'
pub extern "system" fn baz() {}
pub struct S;
// @has issue_33302/constant.CST.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'pub const CST: i32'
+ // '//pre[@class="rust item-decl"]' 'pub const CST: i32'
pub const CST: i32 = ($n * $n);
// @has issue_33302/static.ST.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'pub static ST: i32'
+ // '//pre[@class="rust item-decl"]' 'pub static ST: i32'
pub static ST: i32 = ($n * $n);
pub trait T<X> {
fn ignore(_: &X) {}
const C: X;
// @has issue_33302/trait.T.html \
- // '//div[@class="item-decl"]/pre[@class="rust"]' 'const D: i32'
+ // '//pre[@class="rust item-decl"]' 'const D: i32'
// @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
const D: i32 = ($n * $n);
}
extern crate issue_85454;
// @has foo/trait.FromResidual.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+// @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
pub trait FromResidual<R = <Self as Try>::Residual> {
fn from_residual(residual: R) -> Self;
}
pub mod reexport {
// @has foo/reexport/trait.FromResidual.html
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+ // @has - '//pre[@class="rust item-decl"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
pub use issue_85454::*;
}
extern crate issue_98697_reexport_with_anonymous_lifetime;
-// @has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'fn repro<F>()where F: Fn(&str)'
-// @!has issue_98697/fn.repro.html '//div[@class="item-decl"]/pre[@class="rust"]/code' 'for<'
+// @has issue_98697/fn.repro.html '//pre[@class="rust item-decl"]/code' 'fn repro<F>()where F: Fn(&str)'
+// @!has issue_98697/fn.repro.html '//pre[@class="rust item-decl"]/code' 'for<'
pub use issue_98697_reexport_with_anonymous_lifetime::repro;
// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header"]' 'impl MyTrait<&Extra> for Extra'
#![feature(rustc_attrs)]
// @has 'foo/fn.foo.html'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
+// @has - '//pre[@class="rust item-decl"]' 'fn foo(x: usize, const Y: usize, z: usize) -> [usize; 3]'
#[rustc_legacy_const_generics(1)]
pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
[x, Y, z]
}
// @has 'foo/fn.bar.html'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
+// @has - '//pre[@class="rust item-decl"]' 'fn bar(x: usize, const Y: usize, const Z: usize) -> [usize; 3]'
#[rustc_legacy_const_generics(1, 2)]
pub fn bar<const Y: usize, const Z: usize>(x: usize) -> [usize; 3] {
[x, Y, z]
#![crate_name = "foo"]
// @has 'foo/type.Resolutions.html'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "pub type Resolutions<'tcx> = &'tcx u8;"
+// @has - '//pre[@class="rust item-decl"]' "pub type Resolutions<'tcx> = &'tcx u8;"
pub type Resolutions<'tcx> = &'tcx u8;
}
// @has 'foo/struct.Providers.html'
-// @has - '//*[@class="item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8,"
-// @has - '//*[@class="item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16,"
+// @has - '//*[@class="rust item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8,"
+// @has - '//*[@class="rust item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16,"
// @has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8"
// @has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16"
gen! {
pub fn bar(mut bar: ()) {}
}
-// @count foo/fn.baz.html '//div[@class="item-decl"]/pre[@class="rust"]' 1
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]' 'mut'
+// @count foo/fn.baz.html '//pre[@class="rust item-decl"]' 1
+// @!has - '//pre[@class="rust item-decl"]' 'mut'
pub fn baz(mut foo: Foo) {}
type X = <() as Trait>::X;
}
-// @has 'normalize_assoc_item/fn.f.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f() -> isize'
+// @has 'normalize_assoc_item/fn.f.html' '//pre[@class="rust item-decl"]' 'pub fn f() -> isize'
pub fn f() -> <usize as Trait>::X {
0
}
-// @has 'normalize_assoc_item/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f2() -> fn() -> i32'
+// @has 'normalize_assoc_item/fn.f2.html' '//pre[@class="rust item-decl"]' 'pub fn f2() -> fn() -> i32'
pub fn f2() -> <isize as Trait>::X {
todo!()
}
// These can't be normalized because they depend on a generic parameter.
// However the user can choose whether the text should be displayed as `Inner::X` or `<Inner as Trait>::X`.
-// @has 'normalize_assoc_item/struct.Unknown.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
+// @has 'normalize_assoc_item/struct.Unknown.html' '//pre[@class="rust item-decl"]' 'pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);'
pub struct Unknown<Inner: Trait>(pub <Inner as Trait>::X);
-// @has 'normalize_assoc_item/struct.Unknown2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
+// @has 'normalize_assoc_item/struct.Unknown2.html' '//pre[@class="rust item-decl"]' 'pub struct Unknown2<Inner: Trait>(pub Inner::X);'
pub struct Unknown2<Inner: Trait>(pub Inner::X);
trait Lifetimes<'a> {
type Y = &'a isize;
}
-// @has 'normalize_assoc_item/fn.g.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn g() -> &isize"
+// @has 'normalize_assoc_item/fn.g.html' '//pre[@class="rust item-decl"]' "pub fn g() -> &isize"
pub fn g() -> <usize as Lifetimes<'static>>::Y {
&0
}
-// @has 'normalize_assoc_item/constant.A.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub const A: &isize"
+// @has 'normalize_assoc_item/constant.A.html' '//pre[@class="rust item-decl"]' "pub const A: &isize"
pub const A: <usize as Lifetimes<'static>>::Y = &0;
// test cross-crate re-exports
extern crate inner;
-// @has 'normalize_assoc_item/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn foo() -> i32"
+// @has 'normalize_assoc_item/fn.foo.html' '//pre[@class="rust item-decl"]' "pub fn foo() -> i32"
pub use inner::foo;
-// @has 'normalize_assoc_item/fn.h.html' '//div[@class="item-decl"]/pre[@class="rust"]' "pub fn h<T>() -> IntoIter<T, Global>"
+// @has 'normalize_assoc_item/fn.h.html' '//pre[@class="rust item-decl"]' "pub fn h<T>() -> IntoIter<T, Global>"
pub fn h<T>() -> <Vec<T> as IntoIterator>::IntoIter {
vec![].into_iter()
}
#![crate_name = "foo"]
// @has foo/fn.bar.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn bar() -> '
+// @has - '//pre[@class="rust item-decl"]' 'pub fn bar() -> '
/// foo
pub fn bar() -> usize {
2
#![crate_name = "foo"]
// @has foo/fn.f.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn f(_: u8)'
+// @has - '//pre[@class="rust item-decl"]' 'pub fn f(_: u8)'
pub fn f(0u8..=255: u8) {}
extern crate all_item_types;
// @has 'foo/fn.foo_ffn.html'
-// @has - '//*[@class="item-decl"]//code' 'pub unsafe extern "C" fn foo_ffn()'
+// @has - '//*[@class="rust item-decl"]//code' 'pub unsafe extern "C" fn foo_ffn()'
pub use all_item_types::foo_ffn;
extern crate reexports;
-// @has 'foo/macro.addr_of.html' '//*[@class="item-decl"]' 'pub macro addr_of($place:expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="rust item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
// @!has 'foo/macro.addr_of_local.html'
use reexports::addr_of_local;
-// @has 'foo/struct.Foo.html' '//*[@class="item-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="rust item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
// @!has 'foo/struct.FooCrate.html'
pub(crate) use reexports::FooCrate;
// @!has 'foo/struct.FooLocal.html'
use reexports::FooLocal;
-// @has 'foo/enum.Bar.html' '//*[@class="item-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="rust item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
// @!has 'foo/enum.BarCrate.html'
pub(crate) use reexports::BarCrate;
// @!has 'foo/enum.BarLocal.html'
use reexports::BarLocal;
-// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//pre[@class="rust item-decl"]' 'pub fn foo()'
pub use reexports::foo;
// @!has 'foo/fn.foo_crate.html'
pub(crate) use reexports::foo_crate;
// @!has 'foo/fn.foo_local.html'
use reexports::foo_local;
-// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//pre[@class="rust item-decl"]' 'pub type Type ='
pub use reexports::Type;
// @!has 'foo/type.TypeCrate.html'
pub(crate) use reexports::TypeCrate;
// @!has 'foo/type.TypeLocal.html'
use reexports::TypeLocal;
-// @has 'foo/union.Union.html' '//*[@class="item-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="rust item-decl"]' 'pub union Union {'
pub use reexports::Union;
// @!has 'foo/union.UnionCrate.html'
pub(crate) use reexports::UnionCrate;
pub mod outer {
pub mod inner {
- // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="item-decl"]' 'pub macro addr_of($place:expr) {'
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="rust item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
- // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
+ // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="rust item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
pub(crate) use reexports::addr_of_crate;
- // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
+ // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="rust item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
pub(super) use reexports::addr_of_super;
// @!has 'foo/outer/inner/macro.addr_of_self.html'
pub(self) use reexports::addr_of_self;
// @!has 'foo/outer/inner/macro.addr_of_local.html'
use reexports::addr_of_local;
- // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="item-decl"]' 'pub struct Foo;'
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="rust item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
- // @has 'foo/outer/inner/struct.FooCrate.html' '//*[@class="item-decl"]' 'pub(crate) struct FooCrate;'
+ // @has 'foo/outer/inner/struct.FooCrate.html' '//*[@class="rust item-decl"]' 'pub(crate) struct FooCrate;'
pub(crate) use reexports::FooCrate;
- // @has 'foo/outer/inner/struct.FooSuper.html' '//*[@class="item-decl"]' 'pub(in outer) struct FooSuper;'
+ // @has 'foo/outer/inner/struct.FooSuper.html' '//*[@class="rust item-decl"]' 'pub(in outer) struct FooSuper;'
pub(super) use reexports::FooSuper;
// @!has 'foo/outer/inner/struct.FooSelf.html'
pub(self) use reexports::FooSelf;
// @!has 'foo/outer/inner/struct.FooLocal.html'
use reexports::FooLocal;
- // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="item-decl"]' 'pub enum Bar {'
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="rust item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
- // @has 'foo/outer/inner/enum.BarCrate.html' '//*[@class="item-decl"]' 'pub(crate) enum BarCrate {'
+ // @has 'foo/outer/inner/enum.BarCrate.html' '//*[@class="rust item-decl"]' 'pub(crate) enum BarCrate {'
pub(crate) use reexports::BarCrate;
- // @has 'foo/outer/inner/enum.BarSuper.html' '//*[@class="item-decl"]' 'pub(in outer) enum BarSuper {'
+ // @has 'foo/outer/inner/enum.BarSuper.html' '//*[@class="rust item-decl"]' 'pub(in outer) enum BarSuper {'
pub(super) use reexports::BarSuper;
// @!has 'foo/outer/inner/enum.BarSelf.html'
pub(self) use reexports::BarSelf;
// @!has 'foo/outer/inner/enum.BarLocal.html'
use reexports::BarLocal;
- // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
+ // @has 'foo/outer/inner/fn.foo.html' '//pre[@class="rust item-decl"]' 'pub fn foo()'
pub use reexports::foo;
- // @has 'foo/outer/inner/fn.foo_crate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) fn foo_crate()'
+ // @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
pub(crate) use reexports::foo_crate;
- // @has 'foo/outer/inner/fn.foo_super.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) fn foo_super()'
+ // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
pub(super) use::reexports::foo_super;
// @!has 'foo/outer/inner/fn.foo_self.html'
pub(self) use reexports::foo_self;
// @!has 'foo/outer/inner/fn.foo_local.html'
use reexports::foo_local;
- // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
+ // @has 'foo/outer/inner/type.Type.html' '//pre[@class="rust item-decl"]' 'pub type Type ='
pub use reexports::Type;
- // @has 'foo/outer/inner/type.TypeCrate.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(crate) type TypeCrate ='
+ // @has 'foo/outer/inner/type.TypeCrate.html' '//pre[@class="rust item-decl"]' 'pub(crate) type TypeCrate ='
pub(crate) use reexports::TypeCrate;
- // @has 'foo/outer/inner/type.TypeSuper.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub(in outer) type TypeSuper ='
+ // @has 'foo/outer/inner/type.TypeSuper.html' '//pre[@class="rust item-decl"]' 'pub(in outer) type TypeSuper ='
pub(super) use reexports::TypeSuper;
// @!has 'foo/outer/inner/type.TypeSelf.html'
pub(self) use reexports::TypeSelf;
// @!has 'foo/outer/inner/type.TypeLocal.html'
use reexports::TypeLocal;
- // @has 'foo/outer/inner/union.Union.html' '//*[@class="item-decl"]' 'pub union Union {'
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="rust item-decl"]' 'pub union Union {'
pub use reexports::Union;
- // @has 'foo/outer/inner/union.UnionCrate.html' '//*[@class="item-decl"]' 'pub(crate) union UnionCrate {'
+ // @has 'foo/outer/inner/union.UnionCrate.html' '//*[@class="rust item-decl"]' 'pub(crate) union UnionCrate {'
pub(crate) use reexports::UnionCrate;
- // @has 'foo/outer/inner/union.UnionSuper.html' '//*[@class="item-decl"]' 'pub(in outer) union UnionSuper {'
+ // @has 'foo/outer/inner/union.UnionSuper.html' '//*[@class="rust item-decl"]' 'pub(in outer) union UnionSuper {'
pub(super) use reexports::UnionSuper;
// @!has 'foo/outer/inner/union.UnionSelf.html'
pub(self) use reexports::UnionSelf;
extern crate reexports;
-// @has 'foo/macro.addr_of.html' '//*[@class="item-decl"]' 'pub macro addr_of($place:expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="rust item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
// @!has 'foo/macro.addr_of_local.html'
use reexports::addr_of_local;
-// @has 'foo/struct.Foo.html' '//*[@class="item-decl"]' 'pub struct Foo;'
+// @has 'foo/struct.Foo.html' '//*[@class="rust item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
// @!has 'foo/struct.FooCrate.html'
pub(crate) use reexports::FooCrate;
// @!has 'foo/struct.FooLocal.html'
use reexports::FooLocal;
-// @has 'foo/enum.Bar.html' '//*[@class="item-decl"]' 'pub enum Bar {'
+// @has 'foo/enum.Bar.html' '//*[@class="rust item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
// @!has 'foo/enum.BarCrate.html'
pub(crate) use reexports::BarCrate;
// @!has 'foo/enum.BarLocal.html'
use reexports::BarLocal;
-// @has 'foo/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
+// @has 'foo/fn.foo.html' '//pre[@class="rust item-decl"]' 'pub fn foo()'
pub use reexports::foo;
// @!has 'foo/fn.foo_crate.html'
pub(crate) use reexports::foo_crate;
// @!has 'foo/fn.foo_local.html'
use reexports::foo_local;
-// @has 'foo/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
+// @has 'foo/type.Type.html' '//pre[@class="rust item-decl"]' 'pub type Type ='
pub use reexports::Type;
// @!has 'foo/type.TypeCrate.html'
pub(crate) use reexports::TypeCrate;
// @!has 'foo/type.TypeLocal.html'
use reexports::TypeLocal;
-// @has 'foo/union.Union.html' '//*[@class="item-decl"]' 'pub union Union {'
+// @has 'foo/union.Union.html' '//*[@class="rust item-decl"]' 'pub union Union {'
pub use reexports::Union;
// @!has 'foo/union.UnionCrate.html'
pub(crate) use reexports::UnionCrate;
pub mod outer {
pub mod inner {
- // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="item-decl"]' 'pub macro addr_of($place:expr) {'
+ // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="rust item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/outer/inner/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
// @!has 'foo/outer/inner/macro.addr_of_local.html'
use reexports::addr_of_local;
- // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="item-decl"]' 'pub struct Foo;'
+ // @has 'foo/outer/inner/struct.Foo.html' '//*[@class="rust item-decl"]' 'pub struct Foo;'
pub use reexports::Foo;
// @!has 'foo/outer/inner/struct.FooCrate.html'
pub(crate) use reexports::FooCrate;
// @!has 'foo/outer/inner/struct.FooLocal.html'
use reexports::FooLocal;
- // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="item-decl"]' 'pub enum Bar {'
+ // @has 'foo/outer/inner/enum.Bar.html' '//*[@class="rust item-decl"]' 'pub enum Bar {'
pub use reexports::Bar;
// @!has 'foo/outer/inner/enum.BarCrate.html'
pub(crate) use reexports::BarCrate;
// @!has 'foo/outer/inner/enum.BarLocal.html'
use reexports::BarLocal;
- // @has 'foo/outer/inner/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo()'
+ // @has 'foo/outer/inner/fn.foo.html' '//pre[@class="rust item-decl"]' 'pub fn foo()'
pub use reexports::foo;
// @!has 'foo/outer/inner/fn.foo_crate.html'
pub(crate) use reexports::foo_crate;
// @!has 'foo/outer/inner/fn.foo_local.html'
use reexports::foo_local;
- // @has 'foo/outer/inner/type.Type.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub type Type ='
+ // @has 'foo/outer/inner/type.Type.html' '//pre[@class="rust item-decl"]' 'pub type Type ='
pub use reexports::Type;
// @!has 'foo/outer/inner/type.TypeCrate.html'
pub(crate) use reexports::TypeCrate;
// @!has 'foo/outer/inner/type.TypeLocal.html'
use reexports::TypeLocal;
- // @has 'foo/outer/inner/union.Union.html' '//*[@class="item-decl"]' 'pub union Union {'
+ // @has 'foo/outer/inner/union.Union.html' '//*[@class="rust item-decl"]' 'pub union Union {'
pub use reexports::Union;
// @!has 'foo/outer/inner/union.UnionCrate.html'
pub(crate) use reexports::UnionCrate;
pub struct S<T>(T);
-// @!has foo/trait.Tr.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' '~const'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where"]' ': Clone'
+// @!has foo/trait.Tr.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '~const'
+// @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust item-decl"]/code/span[@class="where"]' '~const'
+// @has - '//pre[@class="rust item-decl"]/code/span[@class="where"]' ': Clone'
#[const_trait]
pub trait Tr<T> {
// @!has - '//section[@id="method.a"]/h4[@class="code-header"]' '~const'
}
}
-// @!has foo/fn.foo.html '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' '~const'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/a[@class="trait"]' 'Clone'
-// @!has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' '~const'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]/code/span[@class="where fmt-newline"]' ': Clone'
+// @!has foo/fn.foo.html '//pre[@class="rust item-decl"]/code/a[@class="trait"]' '~const'
+// @has - '//pre[@class="rust item-decl"]/code/a[@class="trait"]' 'Clone'
+// @!has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' '~const'
+// @has - '//pre[@class="rust item-decl"]/code/span[@class="where fmt-newline"]' ': Clone'
pub const fn foo<F: ~const Clone + ~const Destruct>()
where
Option<F>: ~const Clone + ~const Destruct,
extern "rust-intrinsic" {
// @has 'foo/fn.abort.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+ // @has - '//pre[@class="rust item-decl"]' 'pub extern "rust-intrinsic" fn abort() -> !'
#[rustc_safe_intrinsic]
pub fn abort() -> !;
// @has 'foo/fn.unreachable.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+ // @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
pub fn unreachable() -> !;
}
extern "C" {
// @has 'foo/fn.needs_drop.html'
- // @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+ // @has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "C" fn needs_drop() -> !'
pub fn needs_drop() -> !;
}
pub struct MyBox<T: ?Sized>(*const T);
// @has 'foo/fn.alpha.html'
-// @snapshot link_slice_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_slice_u32 - '//pre[@class="rust item-decl"]/code'
pub fn alpha() -> &'static [u32] {
loop {}
}
// @has 'foo/fn.beta.html'
-// @snapshot link_slice_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_slice_generic - '//pre[@class="rust item-decl"]/code'
pub fn beta<T>() -> &'static [T] {
loop {}
}
// @has 'foo/fn.gamma.html'
-// @snapshot link_box_u32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_box_u32 - '//pre[@class="rust item-decl"]/code'
pub fn gamma() -> MyBox<[u32]> {
loop {}
}
// @has 'foo/fn.delta.html'
-// @snapshot link_box_generic - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_box_generic - '//pre[@class="rust item-decl"]/code'
pub fn delta<T>() -> MyBox<[T]> {
loop {}
}
hir_id: usize,
}
-// @has 'foo/fn.body_owner.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn body_owner(_: BodyId)'
+// @has 'foo/fn.body_owner.html' '//pre[@class="rust item-decl"]' 'pub fn body_owner(_: BodyId)'
pub fn body_owner(BodyId { hir_id }: BodyId) {
// ...
}
#![crate_name = "foo"]
// @has foo/fn.foo.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' "_: &(dyn ToString + 'static)"
+// @has - '//pre[@class="rust item-decl"]' "_: &(dyn ToString + 'static)"
pub fn foo(_: &(ToString + 'static)) {}
// @has 'toggle_item_contents/struct.PrivStruct.html'
// @count - '//details[@class="toggle type-contents-toggle"]' 0
-// @has - '//div[@class="item-decl"]' '/* private fields */'
+// @has - '//pre[@class="rust item-decl"]' '/* private fields */'
pub struct PrivStruct {
a: usize,
b: usize,
}
// @has 'toggle_item_contents/enum.LargeEnum.html'
-// @count - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 1
-// @has - '//div[@class="item-decl"]/pre//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
+// @count - '//pre[@class="rust item-decl"]//details[@class="toggle type-contents-toggle"]' 1
+// @has - '//pre[@class="rust item-decl"]//details[@class="toggle type-contents-toggle"]' 'Show 13 variants'
pub enum LargeEnum {
A, B, C, D, E, F(u8), G, H, I, J, K, L, M
}
// @has foo/index.html '//a[@class="traitalias"]' 'Foo'
// @has foo/traitalias.CopyAlias.html
-// @has - '//section[@id="main-content"]/div[@class="item-decl"]/pre' 'trait CopyAlias = Copy;'
+// @has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait CopyAlias = Copy;'
pub trait CopyAlias = Copy;
// @has foo/traitalias.Alias2.html
-// @has - '//section[@id="main-content"]/div[@class="item-decl"]/pre' 'trait Alias2 = Copy + Debug;'
+// @has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Alias2 = Copy + Debug;'
pub trait Alias2 = Copy + Debug;
// @has foo/traitalias.Foo.html
-// @has - '//section[@id="main-content"]/div[@class="item-decl"]/pre' 'trait Foo<T> = Into<T> + Debug;'
+// @has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Foo<T> = Into<T> + Debug;'
pub trait Foo<T> = Into<T> + Debug;
// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
pub fn bar<T>() where T: Alias2 {}
);
// @has foo/enum.Bar.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'BarVariant(String),'
+// @has - '//pre[@class="rust item-decl"]' 'BarVariant(String),'
// @matches - '//*[@id="variant.BarVariant.fields"]/h4' '^Tuple Fields$'
// @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
// @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
#![crate_name = "foo"]
// @has foo/fn.tuple0.html //pre 'pub fn tuple0(x: ())'
-// @snapshot link_unit - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link_unit - '//pre[@class="rust item-decl"]/code'
pub fn tuple0(x: ()) -> () { x }
// @has foo/fn.tuple1.html //pre 'pub fn tuple1(x: (i32,)) -> (i32,)'
-// @snapshot link1_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link1_i32 - '//pre[@class="rust item-decl"]/code'
pub fn tuple1(x: (i32,)) -> (i32,) { x }
// @has foo/fn.tuple2.html //pre 'pub fn tuple2(x: (i32, i32)) -> (i32, i32)'
-// @snapshot link2_i32 - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link2_i32 - '//pre[@class="rust item-decl"]/code'
pub fn tuple2(x: (i32, i32)) -> (i32, i32) { x }
// @has foo/fn.tuple1_t.html //pre 'pub fn tuple1_t<T>(x: (T,)) -> (T,)'
-// @snapshot link1_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link1_t - '//pre[@class="rust item-decl"]/code'
pub fn tuple1_t<T>(x: (T,)) -> (T,) { x }
// @has foo/fn.tuple2_t.html //pre 'pub fn tuple2_t<T>(x: (T, T)) -> (T, T)'
-// @snapshot link2_t - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link2_t - '//pre[@class="rust item-decl"]/code'
pub fn tuple2_t<T>(x: (T, T)) -> (T, T) { x }
// @has foo/fn.tuple2_tu.html //pre 'pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U)'
-// @snapshot link2_tu - '//div[@class="item-decl"]/pre[@class="rust"]/code'
+// @snapshot link2_tu - '//pre[@class="rust item-decl"]/code'
pub fn tuple2_tu<T, U>(x: (T, U)) -> (T, U) { x }
extern crate unit_return;
-// @has 'foo/fn.f0.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u8) + Clone'
+// @has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' 'F: FnMut(u8) + Clone'
pub fn f0<F: FnMut(u8) + Clone>(f: F) {}
-// @has 'foo/fn.f1.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u16) + Clone'
+// @has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' 'F: FnMut(u16) + Clone'
pub fn f1<F: FnMut(u16) -> () + Clone>(f: F) {}
-// @has 'foo/fn.f2.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u32) + Clone'
+// @has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' 'F: FnMut(u32) + Clone'
pub use unit_return::f2;
-// @has 'foo/fn.f3.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'F: FnMut(u64) + Clone'
+// @has 'foo/fn.f3.html' '//pre[@class="rust item-decl"]' 'F: FnMut(u64) + Clone'
pub use unit_return::f3;
#![crate_name = "foo"]
// @has foo/fn.foo.html
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo<X, Y: ?Sized>(_: &X)'
-// @has - '//div[@class="item-decl"]/pre[@class="rust"]' 'where X: ?Sized,'
+// @has - '//pre[@class="rust item-decl"]' 'pub fn foo<X, Y: ?Sized>(_: &X)'
+// @has - '//pre[@class="rust item-decl"]' 'where X: ?Sized,'
pub fn foo<X, Y: ?Sized>(_: &X) where X: ?Sized {}
-<div class="item-decl"><pre class="rust"><code>pub struct Simd<T>(_)<br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
+<pre class="rust item-decl"><code>pub struct Simd<T>(_)<br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub trait TraitWhere {
+<pre class="rust item-decl"><code>pub trait TraitWhere {
type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />    <span class="where">where<br />        Self: 'a</span>;
fn <a href="#method.func" class="fn">func</a>(self)<br />    <span class="where">where<br />        Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>,
{ ... }
<span class="item-spacer" /> fn <a href="#method.lines" class="fn">lines</a>(self) -> <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a><Self><br />    <span class="where">where<br />        Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span>,
{ ... }
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
pub struct Echo<E>(E);
// @has 'foo/struct.Simd.html'
-// @snapshot SWhere_Simd_item-decl - '//div[@class="item-decl"]'
+// @snapshot SWhere_Simd_item-decl - '//pre[@class="rust item-decl"]'
pub struct Simd<T>([T; 1])
where
T: MyTrait;
// @has 'foo/trait.TraitWhere.html'
-// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="item-decl"]'
+// @snapshot SWhere_TraitWhere_item-decl - '//pre[@class="rust item-decl"]'
pub trait TraitWhere {
type Item<'a> where Self: 'a;
// "impl<F> MyTrait for Foxtrot<F>where F: MyTrait"
impl<F> MyTrait for Foxtrot<F>where F: MyTrait {}
-// @has foo/type.Golf.html '//div[@class="item-decl"]/pre[@class="rust"]' \
+// @has foo/type.Golf.html '//pre[@class="rust item-decl"]' \
// "type Golf<T>where T: Clone, = (T, T)"
pub type Golf<T> where T: Clone = (T, T);
-<div class="item-decl"><pre class="rust"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub enum Cow2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
+<pre class="rust item-decl"><code>pub enum Cow2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
#![crate_name = "foo"]
// @has 'foo/trait.ToOwned.html'
-// @snapshot trait - '//*[@class="item-decl"]'
+// @snapshot trait - '//*[@class="rust item-decl"]'
pub trait ToOwned<T>
where T: Clone
{
}
// @has 'foo/trait.ToOwned2.html'
-// @snapshot trait2 - '//*[@class="item-decl"]'
+// @snapshot trait2 - '//*[@class="rust item-decl"]'
// There should be a whitespace before `{` in this case!
pub trait ToOwned2<T: Clone> {
type Owned;
}
// @has 'foo/enum.Cow.html'
-// @snapshot enum - '//*[@class="item-decl"]'
+// @snapshot enum - '//*[@class="rust item-decl"]'
pub enum Cow<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
}
// @has 'foo/enum.Cow2.html'
-// @snapshot enum2 - '//*[@class="item-decl"]'
+// @snapshot enum2 - '//*[@class="rust item-decl"]'
// There should be a whitespace before `{` in this case!
pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
Borrowed(&'a B),
}
// @has 'foo/struct.Struct.html'
-// @snapshot struct - '//*[@class="item-decl"]'
+// @snapshot struct - '//*[@class="rust item-decl"]'
pub struct Struct<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
}
// @has 'foo/struct.Struct2.html'
-// @snapshot struct2 - '//*[@class="item-decl"]'
+// @snapshot struct2 - '//*[@class="rust item-decl"]'
// There should be a whitespace before `{` in this case!
pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
pub a: &'a B,
}
// @has 'foo/union.Union.html'
-// @snapshot union - '//*[@class="item-decl"]'
+// @snapshot union - '//*[@class="rust item-decl"]'
pub union Union<'a, B: ?Sized + 'a>
where
B: ToOwned<Clone>,
}
// @has 'foo/union.Union2.html'
-// @snapshot union2 - '//*[@class="item-decl"]'
+// @snapshot union2 - '//*[@class="rust item-decl"]'
// There should be a whitespace before `{` in this case!
pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
a: &'a B,
-<div class="item-decl"><pre class="rust"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub struct Struct2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
+<pre class="rust item-decl"><code>pub struct Struct2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub trait ToOwned<T><span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
+<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
fn <a href="#tymethod.to_owned" class="fn">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>;
<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fn">whatever</a>(&self) -> T;
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub trait ToOwned2<T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> {
+<pre class="rust item-decl"><code>pub trait ToOwned2<T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> {
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
fn <a href="#tymethod.to_owned" class="fn">to_owned</a>(&self) -> Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>;
<span class="item-spacer" /> fn <a href="#tymethod.whatever" class="fn">whatever</a>(&self) -> T;
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub union Union<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
/* private fields */
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
-<div class="item-decl"><pre class="rust"><code>pub union Union2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
+<pre class="rust item-decl"><code>pub union Union2<'a, B: ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + 'a> {
/* private fields */
-}</code></pre></div>
\ No newline at end of file
+}</code></pre>
\ No newline at end of file
use std::fmt::Debug;
-// @has 'wrapping/fn.foo.html' '//div[@class="item-decl"]/pre[@class="rust"]' 'pub fn foo() -> impl Debug'
-// @count - '//div[@class="item-decl"]/pre[@class="rust"]/br' 0
+// @has 'wrapping/fn.foo.html' '//pre[@class="rust item-decl"]' 'pub fn foo() -> impl Debug'
+// @count - '//pre[@class="rust item-decl"]/br' 0
pub fn foo() -> impl Debug {}
--- /dev/null
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::marker::PhantomData;
+
+pub trait Bytes {
+ const BYTES: usize;
+}
+
+#[derive(Clone, Debug)]
+pub struct Conster<OT>
+where
+ OT: Bytes,
+ [(); OT::BYTES]: Sized,
+{
+ _offset_type: PhantomData<fn(OT) -> OT>,
+}
+
+impl<OT> Conster<OT>
+where
+ OT: Bytes,
+ [(); OT::BYTES]: Sized,
+{
+ pub fn new() -> Self {
+ Conster { _offset_type: PhantomData }
+ }
+}
+
+pub fn make_conster<COT>() -> Conster<COT>
+where
+ COT: Bytes,
+ [(); COT::BYTES]: Sized,
+{
+ Conster::new()
+}
+
+fn main() {}
// See https://github.com/rust-lang/rust/pull/53562
// and https://github.com/rust-lang/rfcs/pull/2527
-// and https://twitter.com/garblefart/status/1393236602856611843
+// and https://web.archive.org/web/20211010063452/https://twitter.com/garblefart/status/1393236602856611843
// for context.
fn main() {
--- /dev/null
+// Check that suggestions to add a zero to integers with a preceding dot only appear when the change
+// will result in a valid floating point literal.
+
+fn main() {}
+
+fn a() {
+ _ = .3u32;
+ //~^ ERROR expected expression, found `.`
+}
+
+fn b() {
+ _ = .0b0;
+ //~^ ERROR expected expression, found `.`
+}
+
+fn c() {
+ _ = .0o07;
+ //~^ ERROR expected expression, found `.`
+}
+
+fn d() {
+ _ = .0x0ABC;
+ //~^ ERROR expected expression, found `.`
+}
--- /dev/null
+error: expected expression, found `.`
+ --> $DIR/recover-invalid-float-invalid.rs:7:9
+ |
+LL | _ = .3u32;
+ | ^ expected expression
+
+error: expected expression, found `.`
+ --> $DIR/recover-invalid-float-invalid.rs:12:9
+ |
+LL | _ = .0b0;
+ | ^ expected expression
+
+error: expected expression, found `.`
+ --> $DIR/recover-invalid-float-invalid.rs:17:9
+ |
+LL | _ = .0o07;
+ | ^ expected expression
+
+error: expected expression, found `.`
+ --> $DIR/recover-invalid-float-invalid.rs:22:9
+ |
+LL | _ = .0x0ABC;
+ | ^ expected expression
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(unsized_tuple_coercion)]
+
+trait Foo {}
+
+impl Foo for i32 {}
+
+fn main() {
+ // Unsizing via struct
+ let _: Box<dyn Foo> = Box::new(1i32);
+
+ // Slice unsizing
+ let y = [1, 2, 3];
+ let _: &[i32] = &y;
+
+ // Tuple unsizing
+ let hi = (1i32,);
+ let _: &(dyn Foo,) = &hi;
+
+ // Dropping auto traits
+ let a: &(dyn Foo + Send) = &1;
+ let _: &dyn Foo = a;
+}
--- /dev/null
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+#![feature(trait_upcasting)]
+
+trait Foo: Bar<i32> + Bar<u32> {}
+
+trait Bar<T> {}
+
+fn main() {
+ let x: &dyn Foo = todo!();
+ let y: &dyn Bar<i32> = x;
+ let z: &dyn Bar<u32> = x;
+}
--- /dev/null
+// compile-flags: -Ztrait-solver=next
+
+#![feature(trait_upcasting)]
+
+trait Foo: Bar<i32> + Bar<u32> {}
+
+trait Bar<T> {}
+
+fn main() {
+ let x: &dyn Foo = todo!();
+ let y: &dyn Bar<usize> = x;
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/upcast-wrong-substs.rs:11:30
+ |
+LL | let y: &dyn Bar<usize> = x;
+ | --------------- ^ expected trait `Bar`, found trait `Foo`
+ | |
+ | expected due to this
+ |
+ = note: expected reference `&dyn Bar<usize>`
+ found reference `&dyn Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.