Auto merge of #3121 - rust-lang:rustup-2023-10-14, r=saethlin

Automatic sync from rustc
This commit is contained in:
bors 2023-10-14 05:17:07 +00:00
commit 99d6cd4a04
102 changed files with 2272 additions and 1872 deletions

View File

@ -3650,6 +3650,7 @@ dependencies = [
"serde_json",
"smallvec",
"tempfile",
"thin-vec",
"thorin-dwp",
"tracing",
"windows",
@ -5081,7 +5082,6 @@ version = "0.0.0"
dependencies = [
"addr2line",
"alloc",
"cc",
"cfg-if",
"compiler_builtins",
"core",

View File

@ -548,7 +548,11 @@ pub fn cfg_matches(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
"unexpected `cfg` condition value",
if let Some(value) = cfg.value {
format!("unexpected `cfg` condition value: `{value}`")
} else {
format!("unexpected `cfg` condition value: (none)")
},
BuiltinLintDiagnostics::UnexpectedCfgValue(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
@ -560,7 +564,7 @@ pub fn cfg_matches(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
"unexpected `cfg` condition name",
format!("unexpected `cfg` condition name: `{}`", cfg.name),
BuiltinLintDiagnostics::UnexpectedCfgName(
(cfg.name, cfg.name_span),
cfg.value.map(|v| (v, cfg.value_span.unwrap())),

View File

@ -7,14 +7,15 @@
use std::thread::JoinHandle;
use cranelift_object::{ObjectBuilder, ObjectModule};
use rustc_codegen_ssa::assert_module_sources::CguReuse;
use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
use rustc_codegen_ssa::base::determine_cgu_reuse;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputFilenames, OutputType};
use rustc_session::Session;
@ -374,43 +375,47 @@ pub(crate) fn run_aot(
}
}
// Calculate the CGU reuse
let cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>()
});
rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| {
for (i, cgu) in cgus.iter().enumerate() {
let cgu_reuse = cgu_reuse[i];
cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
}
});
let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len());
let modules = tcx.sess.time("codegen mono items", || {
cgus.iter()
.map(|cgu| {
let cgu_reuse = if backend_config.disable_incr_cache {
CguReuse::No
} else {
determine_cgu_reuse(tcx, cgu)
};
tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
match cgu_reuse {
CguReuse::No => {
let dep_node = cgu.codegen_dep_node(tcx);
tcx.dep_graph
.with_task(
dep_node,
tcx,
(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(tcx.sess.diagnostic()),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
)
.0
}
CguReuse::PreLto => unreachable!(),
CguReuse::PostLto => {
concurrency_limiter.job_already_done();
OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
}
.enumerate()
.map(|(i, cgu)| match cgu_reuse[i] {
CguReuse::No => {
let dep_node = cgu.codegen_dep_node(tcx);
tcx.dep_graph
.with_task(
dep_node,
tcx,
(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(tcx.sess.diagnostic()),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
)
.0
}
CguReuse::PreLto => unreachable!("LTO not yet supported"),
CguReuse::PostLto => {
concurrency_limiter.job_already_done();
OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
}
})
.collect::<Vec<_>>()
@ -489,32 +494,3 @@ pub(crate) fn run_aot(
concurrency_limiter,
})
}
// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953
fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
if !tcx.dep_graph.is_fully_enabled() {
return CguReuse::No;
}
let work_product_id = &cgu.work_product_id();
if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
// We don't have anything cached for this CGU. This can happen
// if the CGU did not exist in the previous session.
return CguReuse::No;
}
// Try to mark the CGU as green. If it we can do so, it means that nothing
// affecting the LLVM module has changed and we can re-use a cached version.
// If we compile with any kind of LTO, this means we can re-use the bitcode
// of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
// know that later). If we are not doing LTO, there is only one optimized
// version of each module, so we re-use that.
let dep_node = cgu.codegen_dep_node(tcx);
assert!(
!tcx.dep_graph.dep_node_exists(&dep_node),
"CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
cgu.name()
);
if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No }
}

View File

@ -19,7 +19,6 @@
use rustc_middle::bug;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, CrateType, Lto};
use std::ffi::{CStr, CString};
@ -584,7 +583,6 @@ fn thin_lto(
copy_jobs.push(work_product);
info!(" - {}: re-used", module_name);
assert!(cgcx.incr_comp_session_dir.is_some());
cgcx.cgu_reuse_tracker.set_actual_reuse(module_name, CguReuse::PostLto);
continue;
}
}

View File

@ -397,7 +397,12 @@ fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type
// extracts all the individual values.
let ety = element.llvm_type(cx);
return Some(cx.type_vector(ety, *count));
if *count == 1 {
// Emitting `<1 x T>` would be silly; just use the scalar.
return Some(ety);
} else {
return Some(cx.type_vector(ety, *count));
}
}
// FIXME: The above only handled integer arrays; surely more things

View File

@ -16,6 +16,7 @@ pathdiff = "0.2.0"
serde_json = "1.0.59"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
regex = "1.4"
thin-vec = "0.2.12"
rustc_serialize = { path = "../rustc_serialize" }
rustc_arena = { path = "../rustc_arena" }

View File

@ -11,6 +11,9 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
codegen_ssa_cgu_not_recorded =
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
@ -39,6 +42,8 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err}
codegen_ssa_failed_to_write = failed to write {$path}: {$error}
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
@ -46,6 +51,12 @@ codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files w
codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
.note = an unsuffixed integer value, e.g., `1`, is expected
codegen_ssa_incorrect_cgu_reuse_type =
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
[one] {"at least "}
*[other] {""}
}`{$expected_reuse}`
codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
@ -153,12 +164,18 @@ codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for
codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
codegen_ssa_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).
codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
codegen_ssa_missing_query_depgraph =
found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
@ -166,6 +183,11 @@ codegen_ssa_multiple_external_func_decl = multiple declarations of external func
codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
.help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
codegen_ssa_no_field = no field `{$name}`
codegen_ssa_no_module_named =
no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
@ -297,6 +319,8 @@ codegen_ssa_unknown_atomic_operation = unknown atomic operation
codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target

View File

@ -25,16 +25,21 @@
use crate::errors;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
use rustc_middle::ty::TyCtxt;
use rustc_session::cgu_reuse_tracker::*;
use rustc_span::symbol::{sym, Symbol};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
use std::fmt;
use thin_vec::ThinVec;
#[allow(missing_docs)]
pub fn assert_module_sources(tcx: TyCtxt<'_>) {
pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) {
tcx.dep_graph.with_ignore(|| {
if tcx.sess.opts.incremental.is_none() {
return;
@ -43,21 +48,34 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) {
let available_cgus =
tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect();
let ams = AssertModuleSource { tcx, available_cgus };
let mut ams = AssertModuleSource {
tcx,
available_cgus,
cgu_reuse_tracker: if tcx.sess.opts.unstable_opts.query_dep_graph {
CguReuseTracker::new()
} else {
CguReuseTracker::new_disabled()
},
};
for attr in tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) {
ams.check_attr(attr);
}
})
set_reuse(&mut ams.cgu_reuse_tracker);
ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess);
});
}
struct AssertModuleSource<'tcx> {
tcx: TyCtxt<'tcx>,
available_cgus: UnordSet<Symbol>,
cgu_reuse_tracker: CguReuseTracker,
}
impl<'tcx> AssertModuleSource<'tcx> {
fn check_attr(&self, attr: &ast::Attribute) {
fn check_attr(&mut self, attr: &ast::Attribute) {
let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
(CguReuse::PreLto, ComparisonKind::AtLeast)
} else if attr.has_name(sym::rustc_partition_codegened) {
@ -129,7 +147,7 @@ fn check_attr(&self, attr: &ast::Attribute) {
});
}
self.tcx.sess.cgu_reuse_tracker.set_expectation(
self.cgu_reuse_tracker.set_expectation(
cgu_name,
&user_path,
attr.span,
@ -169,3 +187,109 @@ fn check_config(&self, attr: &ast::Attribute) -> bool {
false
}
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum CguReuse {
No,
PreLto,
PostLto,
}
impl fmt::Display for CguReuse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
CguReuse::No => write!(f, "No"),
CguReuse::PreLto => write!(f, "PreLto "),
CguReuse::PostLto => write!(f, "PostLto "),
}
}
}
impl IntoDiagnosticArg for CguReuse {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ComparisonKind {
Exact,
AtLeast,
}
struct TrackerData {
actual_reuse: FxHashMap<String, CguReuse>,
expected_reuse: FxHashMap<String, (String, Span, CguReuse, ComparisonKind)>,
}
pub struct CguReuseTracker {
data: Option<TrackerData>,
}
impl CguReuseTracker {
fn new() -> CguReuseTracker {
let data =
TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() };
CguReuseTracker { data: Some(data) }
}
fn new_disabled() -> CguReuseTracker {
CguReuseTracker { data: None }
}
pub fn set_actual_reuse(&mut self, cgu_name: &str, kind: CguReuse) {
if let Some(data) = &mut self.data {
debug!("set_actual_reuse({cgu_name:?}, {kind:?})");
let prev_reuse = data.actual_reuse.insert(cgu_name.to_string(), kind);
assert!(prev_reuse.is_none());
}
}
fn set_expectation(
&mut self,
cgu_name: Symbol,
cgu_user_name: &str,
error_span: Span,
expected_reuse: CguReuse,
comparison_kind: ComparisonKind,
) {
if let Some(data) = &mut self.data {
debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})");
data.expected_reuse.insert(
cgu_name.to_string(),
(cgu_user_name.to_string(), error_span, expected_reuse, comparison_kind),
);
}
}
fn check_expected_reuse(&self, sess: &Session) {
if let Some(ref data) = self.data {
for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in
&data.expected_reuse
{
if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) {
let (error, at_least) = match comparison_kind {
ComparisonKind::Exact => (expected_reuse != actual_reuse, false),
ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true),
};
if error {
let at_least = if at_least { 1 } else { 0 };
errors::IncorrectCguReuseType {
span: *error_span,
cgu_user_name,
actual_reuse,
expected_reuse,
at_least,
};
}
} else {
sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
}
}
}
}
}

View File

@ -26,7 +26,6 @@
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::exported_symbols::SymbolExportInfo;
use rustc_middle::ty::TyCtxt;
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType};
use rustc_session::config::{Passes, SwitchWithOptPath};
use rustc_session::Session;
@ -366,8 +365,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
/// The incremental compilation session directory, or None if we are not
/// compiling incrementally
pub incr_comp_session_dir: Option<PathBuf>,
/// Used to update CGU re-use information during the thinlto phase.
pub cgu_reuse_tracker: CguReuseTracker,
/// Channel back to the main control thread to send messages to
pub coordinator_send: Sender<Box<dyn Any + Send>>,
}
@ -1119,7 +1116,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
remark: sess.opts.cg.remark.clone(),
remark_dir,
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
coordinator_send,
expanded_args: tcx.sess.expanded_args.clone(),
diag_emitter: shared_emitter.clone(),
@ -1969,8 +1965,6 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId,
}
});
sess.cgu_reuse_tracker.check_expected_reuse(sess);
sess.abort_if_errors();
let work_products =

View File

@ -1,3 +1,4 @@
use crate::assert_module_sources::CguReuse;
use crate::back::link::are_upstream_rust_objects_already_included;
use crate::back::metadata::create_compressed_metadata_file;
use crate::back::write::{
@ -31,7 +32,6 @@
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
use rustc_session::Session;
use rustc_span::symbol::sym;
@ -683,6 +683,13 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>()
});
crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| {
for (i, cgu) in codegen_units.iter().enumerate() {
let cgu_reuse = cgu_reuse[i];
cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
}
});
let mut total_codegen_time = Duration::new(0, 0);
let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size());
@ -727,7 +734,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
ongoing_codegen.check_for_errors(tcx.sess);
let cgu_reuse = cgu_reuse[i];
tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
match cgu_reuse {
CguReuse::No => {
@ -994,7 +1000,7 @@ pub fn provide(providers: &mut Providers) {
};
}
fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
if !tcx.dep_graph.is_fully_enabled() {
return CguReuse::No;
}

View File

@ -1,5 +1,6 @@
//! Errors emitted by codegen_ssa
use crate::assert_module_sources::CguReuse;
use crate::back::command::Command;
use crate::fluent_generated as fluent;
use rustc_errors::{
@ -16,6 +17,74 @@
use std::path::{Path, PathBuf};
use std::process::ExitStatus;
#[derive(Diagnostic)]
#[diag(codegen_ssa_incorrect_cgu_reuse_type)]
pub struct IncorrectCguReuseType<'a> {
#[primary_span]
pub span: Span,
pub cgu_user_name: &'a str,
pub actual_reuse: CguReuse,
pub expected_reuse: CguReuse,
pub at_least: u8,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_cgu_not_recorded)]
pub struct CguNotRecorded<'a> {
pub cgu_user_name: &'a str,
pub cgu_name: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_reuse_kind)]
pub struct UnknownReuseKind {
#[primary_span]
pub span: Span,
pub kind: Symbol,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_missing_query_depgraph)]
pub struct MissingQueryDepGraph {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_malformed_cgu_name)]
pub struct MalformedCguName {
#[primary_span]
pub span: Span,
pub user_path: String,
pub crate_name: String,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_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(codegen_ssa_field_associated_value_expected)]
pub struct FieldAssociatedValueExpected {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_no_field)]
pub struct NoField {
#[primary_span]
pub span: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_lib_def_write_failure)]
pub struct LibDefWriteFailure {

View File

@ -46,6 +46,7 @@
use std::io;
use std::path::{Path, PathBuf};
pub mod assert_module_sources;
pub mod back;
pub mod base;
pub mod codegen_attrs;

View File

@ -1,6 +1,3 @@
use crate::const_eval::CheckAlignment;
use crate::errors::ConstEvalError;
use either::{Left, Right};
use rustc_hir::def::DefKind;
@ -15,7 +12,9 @@
use rustc_target::abi::{self, Abi};
use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
use crate::const_eval::CheckAlignment;
use crate::errors;
use crate::errors::ConstEvalError;
use crate::interpret::eval_nullary_intrinsic;
use crate::interpret::{
intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx,
@ -290,14 +289,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
key.param_env,
// Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime.
CompileTimeInterpreter::new(
CanAccessStatics::from(is_static),
if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
CheckAlignment::Error
} else {
CheckAlignment::FutureIncompat
},
),
CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error),
);
let res = ecx.load_mir(cid.instance.def, cid.promoted);

View File

@ -1,10 +1,9 @@
use rustc_hir::def::DefKind;
use rustc_hir::{LangItem, CRATE_HIR_ID};
use rustc_hir::LangItem;
use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use std::borrow::Borrow;
use std::hash::Hash;
use std::ops::ControlFlow;
@ -21,11 +20,11 @@
use rustc_target::spec::abi::Abi as CallAbi;
use crate::errors::{LongRunning, LongRunningWarn};
use crate::fluent_generated as fluent;
use crate::interpret::{
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
};
use crate::{errors, fluent_generated as fluent};
use super::error::*;
@ -65,22 +64,11 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
#[derive(Copy, Clone)]
pub enum CheckAlignment {
/// Ignore alignment when following relocations.
/// Ignore all alignment requirements.
/// This is mainly used in interning.
No,
/// Hard error when dereferencing a misaligned pointer.
Error,
/// Emit a future incompat lint when dereferencing a misaligned pointer.
FutureIncompat,
}
impl CheckAlignment {
pub fn should_check(&self) -> bool {
match self {
CheckAlignment::No => false,
CheckAlignment::Error | CheckAlignment::FutureIncompat => true,
}
}
}
#[derive(Copy, Clone, PartialEq)]
@ -358,8 +346,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
#[inline(always)]
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
ecx.machine.check_alignment
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
matches!(ecx.machine.check_alignment, CheckAlignment::Error)
}
#[inline(always)]
@ -367,39 +355,6 @@ fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>)
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
}
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
let err = err_ub!(AlignmentCheckFailed { has, required }).into();
match check {
CheckAlignment::Error => Err(err),
CheckAlignment::No => span_bug!(
ecx.cur_span(),
"`alignment_check_failed` called when no alignment check requested"
),
CheckAlignment::FutureIncompat => {
let (_, backtrace) = err.into_parts();
backtrace.print_backtrace();
let (span, frames) = super::get_span_and_frames(&ecx);
ecx.tcx.emit_spanned_lint(
INVALID_ALIGNMENT,
ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
span,
errors::AlignmentCheckFailed {
has: has.bytes(),
required: required.bytes(),
frames,
},
);
Ok(())
}
}
}
fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>,

View File

@ -12,11 +12,9 @@
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_target::abi::{Align, Size};
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi as CallAbi;
use crate::const_eval::CheckAlignment;
use super::{
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance,
@ -135,7 +133,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
const POST_MONO_CHECKS: bool = true;
/// Whether memory accesses should be alignment-checked.
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment;
fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Whether, when checking alignment, we should look at the actual address and thus support
/// custom alignment logic based on whatever the integer address happens to be.
@ -143,13 +141,6 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
check: CheckAlignment,
) -> InterpResult<'tcx, ()>;
/// Whether to enforce the validity invariant for a specific layout.
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool;

View File

@ -18,7 +18,6 @@
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size};
use crate::const_eval::CheckAlignment;
use crate::fluent_generated as fluent;
use super::{
@ -373,8 +372,7 @@ fn get_ptr_access(
self.check_and_deref_ptr(
ptr,
size,
align,
M::enforce_alignment(self),
M::enforce_alignment(self).then_some(align),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let (size, align) = self
@ -395,17 +393,10 @@ pub fn check_ptr_access_align(
align: Align,
msg: CheckInAllocMsg,
) -> InterpResult<'tcx> {
self.check_and_deref_ptr(
ptr,
size,
align,
CheckAlignment::Error,
msg,
|alloc_id, _, _| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
Ok((size, align, ()))
},
)?;
self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
Ok((size, align, ()))
})?;
Ok(())
}
@ -419,8 +410,7 @@ fn check_and_deref_ptr<T>(
&self,
ptr: Pointer<Option<M::Provenance>>,
size: Size,
align: Align,
check: CheckAlignment,
align: Option<Align>,
msg: CheckInAllocMsg,
alloc_size: impl FnOnce(
AllocId,
@ -436,8 +426,8 @@ fn check_and_deref_ptr<T>(
throw_ub!(DanglingIntPointer(addr, msg));
}
// Must be aligned.
if check.should_check() {
self.check_offset_align(addr, align, check)?;
if let Some(align) = align {
self.check_offset_align(addr, align)?;
}
None
}
@ -460,16 +450,16 @@ fn check_and_deref_ptr<T>(
}
// Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds.
if check.should_check() {
if let Some(align) = align {
if M::use_addr_for_alignment_check(self) {
// `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
self.check_offset_align(ptr.addr().bytes(), align, check)?;
self.check_offset_align(ptr.addr().bytes(), align)?;
} else {
// Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() {
M::alignment_check_failed(self, alloc_align, align, check)?;
throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align });
}
self.check_offset_align(offset.bytes(), align, check)?;
self.check_offset_align(offset.bytes(), align)?;
}
}
@ -480,18 +470,16 @@ fn check_and_deref_ptr<T>(
})
}
fn check_offset_align(
&self,
offset: u64,
align: Align,
check: CheckAlignment,
) -> InterpResult<'tcx> {
fn check_offset_align(&self, offset: u64, align: Align) -> InterpResult<'tcx> {
if offset % align.bytes() == 0 {
Ok(())
} else {
// The biggest power of two through which `offset` is divisible.
let offset_pow2 = 1 << offset.trailing_zeros();
M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
throw_ub!(AlignmentCheckFailed {
has: Align::from_bytes(offset_pow2).unwrap(),
required: align
});
}
}
}
@ -609,8 +597,7 @@ pub fn get_ptr_alloc<'a>(
let ptr_and_alloc = self.check_and_deref_ptr(
ptr,
size,
align,
M::enforce_alignment(self),
M::enforce_alignment(self).then_some(align),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let alloc = self.get_alloc_raw(alloc_id)?;

View File

@ -500,8 +500,7 @@ pub fn check_mplace(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResu
.size_and_align_of_mplace(&mplace)?
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
// Due to packed places, only `mplace.align` matters.
let align =
if M::enforce_alignment(self).should_check() { mplace.align } else { Align::ONE };
let align = if M::enforce_alignment(self) { mplace.align } else { Align::ONE };
self.check_ptr_access_align(mplace.ptr(), size, align, CheckInAllocMsg::DerefTest)?;
Ok(())
}

View File

@ -8,10 +8,10 @@
#![cfg_attr(not(bootstrap), doc(rust_logo))]
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(lazy_cell)]
#![feature(decl_macro)]
#![feature(panic_update_hook)]
#![feature(lazy_cell)]
#![feature(let_chains)]
#![feature(panic_update_hook)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
@ -395,7 +395,7 @@ fn run_compiler(
if ppm.needs_ast_map() {
queries.global_ctxt()?.enter(|tcx| {
tcx.ensure().early_lint_checks(());
pretty::print_after_hir_lowering(tcx, *ppm);
pretty::print(sess, *ppm, pretty::PrintExtra::NeedsAstMap { tcx });
Ok(())
})?;
@ -404,7 +404,7 @@ fn run_compiler(
queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
} else {
let krate = queries.parse()?.steal();
pretty::print_after_parsing(sess, &krate, *ppm);
pretty::print(sess, *ppm, pretty::PrintExtra::AfterParsing { krate });
}
trace!("finished pretty-printing");
return early_exit();
@ -545,7 +545,7 @@ pub enum Compilation {
}
impl Compilation {
pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
match self {
Compilation::Stop => Compilation::Stop,
Compilation::Continue => next(),
@ -657,7 +657,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
}
}
pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
if sess.opts.unstable_opts.link_only {
if let Input::File(file) = &sess.io.input {
let outputs = compiler.build_output_filenames(sess, &[]);
@ -698,7 +698,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
}
}
pub fn list_metadata(
fn list_metadata(
handler: &EarlyErrorHandler,
sess: &Session,
metadata_loader: &dyn MetadataLoader,
@ -1184,7 +1184,7 @@ fn print_flag_list<T>(
///
/// So with all that in mind, the comments below have some more detail about the
/// contortions done here to get things to work out correctly.
pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
@ -1283,9 +1283,9 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
}
}
pub static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
pub fn ice_path() -> &'static Option<PathBuf> {
fn ice_path() -> &'static Option<PathBuf> {
ICE_PATH.get_or_init(|| {
if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
return None;
@ -1394,7 +1394,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
///
/// When `install_ice_hook` is called, this function will be called as the panic
/// hook.
pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(

View File

@ -1,14 +1,13 @@
//! The various pretty-printing routines.
use rustc_ast as ast;
use rustc_ast_pretty::pprust;
use rustc_errors::ErrorGuaranteed;
use rustc_ast_pretty::pprust as pprust_ast;
use rustc_hir as hir;
use rustc_hir_pretty as pprust_hir;
use rustc_middle::hir::map as hir_map;
use rustc_middle::bug;
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{OutFileName, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::FileName;
@ -20,174 +19,57 @@
pub use self::PpSourceMode::*;
use crate::abort_on_err;
// This slightly awkward construction is to allow for each PpMode to
// choose whether it needs to do analyses (which can consume the
// Session) and then pass through the session (now attached to the
// analysis results) on to the chosen pretty-printer, along with the
// `&PpAnn` object.
//
// Note that since the `&PrinterSupport` is freshly constructed on each
// call, it would not make sense to try to attach the lifetime of `self`
// to the lifetime of the `&PrinterObject`.
struct AstNoAnn;
/// Constructs a `PrinterSupport` object and passes it to `f`.
fn call_with_pp_support<'tcx, A, F>(
ppmode: &PpSourceMode,
sess: &'tcx Session,
tcx: Option<TyCtxt<'tcx>>,
f: F,
) -> A
where
F: FnOnce(&dyn PrinterSupport) -> A,
{
match *ppmode {
Normal | Expanded => {
let annotation = NoAnn { sess, tcx };
f(&annotation)
}
impl pprust_ast::PpAnn for AstNoAnn {}
Identified | ExpandedIdentified => {
let annotation = IdentifiedAnnotation { sess, tcx };
f(&annotation)
}
ExpandedHygiene => {
let annotation = HygieneAnnotation { sess };
f(&annotation)
}
}
}
fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A
where
F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A,
{
match *ppmode {
PpHirMode::Normal => {
let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) };
f(&annotation, tcx.hir())
}
PpHirMode::Identified => {
let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) };
f(&annotation, tcx.hir())
}
PpHirMode::Typed => {
abort_on_err(tcx.analysis(()), tcx.sess);
let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) };
tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir()))
}
}
struct HirNoAnn<'tcx> {
tcx: TyCtxt<'tcx>,
}
trait PrinterSupport: pprust::PpAnn {
/// Provides a uniform interface for re-extracting a reference to a
/// `Session` from a value that now owns it.
fn sess(&self) -> &Session;
/// Produces the pretty-print annotation object.
///
/// (Rust does not yet support upcasting from a trait object to
/// an object for one of its supertraits.)
fn pp_ann(&self) -> &dyn pprust::PpAnn;
}
trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
/// Provides a uniform interface for re-extracting a reference to a
/// `Session` from a value that now owns it.
fn sess(&self) -> &Session;
/// Provides a uniform interface for re-extracting a reference to an
/// `hir_map::Map` from a value that now owns it.
fn hir_map(&self) -> Option<hir_map::Map<'hir>>;
/// Produces the pretty-print annotation object.
///
/// (Rust does not yet support upcasting from a trait object to
/// an object for one of its supertraits.)
fn pp_ann(&self) -> &dyn pprust_hir::PpAnn;
}
struct NoAnn<'hir> {
sess: &'hir Session,
tcx: Option<TyCtxt<'hir>>,
}
impl<'hir> PrinterSupport for NoAnn<'hir> {
fn sess(&self) -> &Session {
self.sess
}
fn pp_ann(&self) -> &dyn pprust::PpAnn {
self
}
}
impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
fn sess(&self) -> &Session {
self.sess
}
fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
self.tcx.map(|tcx| tcx.hir())
}
fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
self
}
}
impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
impl<'tcx> pprust_hir::PpAnn for HirNoAnn<'tcx> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
if let Some(tcx) = self.tcx {
pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
}
pprust_hir::PpAnn::nested(
&(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>),
state,
nested,
)
}
}
struct IdentifiedAnnotation<'hir> {
sess: &'hir Session,
tcx: Option<TyCtxt<'hir>>,
}
struct AstIdentifiedAnn;
impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
fn sess(&self) -> &Session {
self.sess
}
fn pp_ann(&self) -> &dyn pprust::PpAnn {
self
}
}
impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
if let pprust::AnnNode::Expr(_) = node {
impl pprust_ast::PpAnn for AstIdentifiedAnn {
fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) {
if let pprust_ast::AnnNode::Expr(_) = node {
s.popen();
}
}
fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
match node {
pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {}
pprust::AnnNode::Item(item) => {
fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) {
match node {
pprust_ast::AnnNode::Crate(_)
| pprust_ast::AnnNode::Ident(_)
| pprust_ast::AnnNode::Name(_) => {}
pprust_ast::AnnNode::Item(item) => {
s.s.space();
s.synth_comment(item.id.to_string())
}
pprust::AnnNode::SubItem(id) => {
pprust_ast::AnnNode::SubItem(id) => {
s.s.space();
s.synth_comment(id.to_string())
}
pprust::AnnNode::Block(blk) => {
pprust_ast::AnnNode::Block(blk) => {
s.s.space();
s.synth_comment(format!("block {}", blk.id))
}
pprust::AnnNode::Expr(expr) => {
pprust_ast::AnnNode::Expr(expr) => {
s.s.space();
s.synth_comment(expr.id.to_string());
s.pclose()
}
pprust::AnnNode::Pat(pat) => {
pprust_ast::AnnNode::Pat(pat) => {
s.s.space();
s.synth_comment(format!("pat {}", pat.id));
}
@ -195,31 +77,25 @@ fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
}
}
impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
fn sess(&self) -> &Session {
self.sess
}
fn hir_map(&self) -> Option<hir_map::Map<'hir>> {
self.tcx.map(|tcx| tcx.hir())
}
fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
self
}
struct HirIdentifiedAnn<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
if let Some(ref tcx) = self.tcx {
pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested)
}
pprust_hir::PpAnn::nested(
&(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>),
state,
nested,
)
}
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
if let pprust_hir::AnnNode::Expr(_) = node {
s.popen();
}
}
fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
match node {
pprust_hir::AnnNode::Name(_) => {}
@ -252,32 +128,22 @@ fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
}
}
struct HygieneAnnotation<'a> {
struct AstHygieneAnn<'a> {
sess: &'a Session,
}
impl<'a> PrinterSupport for HygieneAnnotation<'a> {
fn sess(&self) -> &Session {
self.sess
}
fn pp_ann(&self) -> &dyn pprust::PpAnn {
self
}
}
impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
impl<'a> pprust_ast::PpAnn for AstHygieneAnn<'a> {
fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) {
match node {
pprust::AnnNode::Ident(&Ident { name, span }) => {
pprust_ast::AnnNode::Ident(&Ident { name, span }) => {
s.s.space();
s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
}
pprust::AnnNode::Name(&name) => {
pprust_ast::AnnNode::Name(&name) => {
s.s.space();
s.synth_comment(name.as_u32().to_string())
}
pprust::AnnNode::Crate(_) => {
pprust_ast::AnnNode::Crate(_) => {
s.s.hardbreak();
let verbose = self.sess.verbose();
s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose));
@ -288,26 +154,12 @@ fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
}
}
struct TypedAnnotation<'tcx> {
struct HirTypedAnn<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>,
}
impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> {
fn sess(&self) -> &Session {
self.tcx.sess
}
fn hir_map(&self) -> Option<hir_map::Map<'tcx>> {
Some(self.tcx.hir())
}
fn pp_ann(&self) -> &dyn pprust_hir::PpAnn {
self
}
}
impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> {
impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> {
fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
let old_maybe_typeck_results = self.maybe_typeck_results.get();
if let pprust_hir::Nested::Body(id) = nested {
@ -317,11 +169,13 @@ fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested)
pprust_hir::PpAnn::nested(pp_ann, state, nested);
self.maybe_typeck_results.set(old_maybe_typeck_results);
}
fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
if let pprust_hir::AnnNode::Expr(_) = node {
s.popen();
}
}
fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
if let pprust_hir::AnnNode::Expr(expr) = node {
let typeck_results = self.maybe_typeck_results.get().or_else(|| {
@ -360,119 +214,119 @@ fn write_or_print(out: &str, sess: &Session) {
sess.io.output_file.as_ref().unwrap_or(&OutFileName::Stdout).overwrite(out, sess);
}
pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) {
// Extra data for pretty-printing, the form of which depends on what kind of
// pretty-printing we are doing.
pub enum PrintExtra<'tcx> {
AfterParsing { krate: ast::Crate },
NeedsAstMap { tcx: TyCtxt<'tcx> },
}
impl<'tcx> PrintExtra<'tcx> {
fn with_krate<F, R>(&self, f: F) -> R
where
F: FnOnce(&ast::Crate) -> R,
{
match self {
PrintExtra::AfterParsing { krate, .. } => f(krate),
PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering(()).borrow().1),
}
}
fn tcx(&self) -> TyCtxt<'tcx> {
match self {
PrintExtra::AfterParsing { .. } => bug!("PrintExtra::tcx"),
PrintExtra::NeedsAstMap { tcx } => *tcx,
}
}
}
pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
if ppm.needs_analysis() {
abort_on_err(ex.tcx().analysis(()), sess);
}
let (src, src_name) = get_source(sess);
let out = match ppm {
Source(s) => {
// Silently ignores an identified node.
call_with_pp_support(&s, sess, None, move |annotation| {
debug!("pretty printing source code {:?}", s);
let sess = annotation.sess();
let parse = &sess.parse_sess;
pprust::print_crate(
debug!("pretty printing source code {:?}", s);
let annotation: Box<dyn pprust_ast::PpAnn> = match s {
Normal => Box::new(AstNoAnn),
Expanded => Box::new(AstNoAnn),
Identified => Box::new(AstIdentifiedAnn),
ExpandedIdentified => Box::new(AstIdentifiedAnn),
ExpandedHygiene => Box::new(AstHygieneAnn { sess }),
};
let parse = &sess.parse_sess;
let is_expanded = ppm.needs_ast_map();
ex.with_krate(|krate| {
pprust_ast::print_crate(
sess.source_map(),
krate,
src_name,
src,
annotation.pp_ann(),
false,
&*annotation,
is_expanded,
parse.edition,
&sess.parse_sess.attr_id_generator,
)
})
}
AstTree(PpAstTreeMode::Normal) => {
AstTree => {
debug!("pretty printing AST tree");
format!("{krate:#?}")
ex.with_krate(|krate| format!("{krate:#?}"))
}
_ => unreachable!(),
};
write_or_print(&out, sess);
}
pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
if ppm.needs_analysis() {
abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
return;
}
let (src, src_name) = get_source(tcx.sess);
let out = match ppm {
Source(s) => {
// Silently ignores an identified node.
call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
debug!("pretty printing source code {:?}", s);
let sess = annotation.sess();
let parse = &sess.parse_sess;
pprust::print_crate(
sess.source_map(),
&tcx.resolver_for_lowering(()).borrow().1,
AstTreeExpanded => {
debug!("pretty-printing expanded AST");
format!("{:#?}", ex.tcx().resolver_for_lowering(()).borrow().1)
}
Hir(s) => {
debug!("pretty printing HIR {:?}", s);
let tcx = ex.tcx();
let f = |annotation: &dyn pprust_hir::PpAnn| {
let sm = sess.source_map();
let hir_map = tcx.hir();
let attrs = |id| hir_map.attrs(id);
pprust_hir::print_crate(
sm,
hir_map.root_module(),
src_name,
src,
annotation.pp_ann(),
true,
parse.edition,
&sess.parse_sess.attr_id_generator,
&attrs,
annotation,
)
})
};
match s {
PpHirMode::Normal => {
let annotation = HirNoAnn { tcx };
f(&annotation)
}
PpHirMode::Identified => {
let annotation = HirIdentifiedAnn { tcx };
f(&annotation)
}
PpHirMode::Typed => {
let annotation = HirTypedAnn { tcx, maybe_typeck_results: Cell::new(None) };
tcx.dep_graph.with_ignore(|| f(&annotation))
}
}
}
AstTree(PpAstTreeMode::Expanded) => {
debug!("pretty-printing expanded AST");
format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1)
}
Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
debug!("pretty printing HIR {:?}", s);
let sess = annotation.sess();
let sm = sess.source_map();
let attrs = |id| hir_map.attrs(id);
pprust_hir::print_crate(
sm,
hir_map.root_module(),
src_name,
src,
&attrs,
annotation.pp_ann(),
)
}),
HirTree => {
call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| {
debug!("pretty printing HIR tree");
format!("{:#?}", hir_map.krate())
})
debug!("pretty printing HIR tree");
format!("{:#?}", ex.tcx().hir().krate())
}
_ => unreachable!(),
};
write_or_print(&out, tcx.sess);
}
// In an ideal world, this would be a public function called by the driver after
// analysis is performed. However, we want to call `phase_3_run_analysis_passes`
// with a different callback than the standard driver, so that isn't easy.
// Instead, we call that function ourselves.
fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> {
tcx.analysis(())?;
let out = match ppm {
Mir => {
let mut out = Vec::new();
write_mir_pretty(tcx, None, &mut out).unwrap();
write_mir_pretty(ex.tcx(), None, &mut out).unwrap();
String::from_utf8(out).unwrap()
}
MirCFG => {
let mut out = Vec::new();
write_mir_graphviz(tcx, None, &mut out).unwrap();
write_mir_graphviz(ex.tcx(), None, &mut out).unwrap();
String::from_utf8(out).unwrap()
}
ThirTree => {
let tcx = ex.tcx();
let mut out = String::new();
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR tree");
@ -481,8 +335,8 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
}
out
}
ThirFlat => {
let tcx = ex.tcx();
let mut out = String::new();
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR flat");
@ -491,11 +345,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
}
out
}
_ => unreachable!(),
};
write_or_print(&out, tcx.sess);
Ok(())
write_or_print(&out, sess);
}

View File

@ -659,6 +659,7 @@ pub fn span_labels(
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self);
forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn help_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
forward!(pub fn span_help(
&mut self,
sp: impl Into<MultiSpan>,

View File

@ -52,8 +52,6 @@ fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
impl PpAnn for NoAnn {}
pub const NO_ANN: &dyn PpAnn = &NoAnn;
/// Identical to the `PpAnn` implementation for `hir::Crate`,
/// except it avoids creating a dependency on the whole crate.
impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
fn nested(&self, state: &mut State<'_>, nested: Nested) {
match nested {
@ -75,7 +73,11 @@ pub struct State<'a> {
}
impl<'a> State<'a> {
pub fn print_node(&mut self, node: Node<'_>) {
fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
(self.attrs)(id)
}
fn print_node(&mut self, node: Node<'_>) {
match node {
Node::Param(a) => self.print_param(a),
Node::Item(a) => self.print_item(a),
@ -144,7 +146,7 @@ fn print_generic_args(&mut self, _: &ast::GenericArgs, _colons_before_params: bo
}
}
pub const INDENT_UNIT: isize = 4;
const INDENT_UNIT: isize = 4;
/// Requires you to pass an input filename and reader so that
/// it can scan the input text for comments to copy forward.
@ -156,7 +158,12 @@ pub fn print_crate<'a>(
attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> String {
let mut s = State::new_from_input(sm, filename, input, attrs, ann);
let mut s = State {
s: pp::Printer::new(),
comments: Some(Comments::new(sm, filename, input)),
attrs,
ann,
};
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
@ -166,28 +173,7 @@ pub fn print_crate<'a>(
s.s.eof()
}
impl<'a> State<'a> {
pub fn new_from_input(
sm: &'a SourceMap,
filename: FileName,
input: String,
attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute],
ann: &'a dyn PpAnn,
) -> State<'a> {
State {
s: pp::Printer::new(),
comments: Some(Comments::new(sm, filename, input)),
attrs,
ann,
}
}
fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] {
(self.attrs)(id)
}
}
pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
where
F: FnOnce(&mut State<'_>),
{
@ -196,52 +182,20 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
printer.s.eof()
}
pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String {
to_string(NO_ANN, |s| s.print_generic_params(generic_params))
}
pub fn bounds_to_string<'b>(bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>) -> String {
to_string(NO_ANN, |s| s.print_bounds("", bounds))
}
pub fn ty_to_string(ty: &hir::Ty<'_>) -> String {
to_string(NO_ANN, |s| s.print_type(ty))
}
pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String {
to_string(NO_ANN, |s| s.print_path_segment(segment))
}
pub fn path_to_string(segment: &hir::Path<'_>) -> String {
to_string(NO_ANN, |s| s.print_path(segment, false))
}
pub fn qpath_to_string(segment: &hir::QPath<'_>) -> String {
to_string(NO_ANN, |s| s.print_qpath(segment, false))
}
pub fn fn_to_string(
decl: &hir::FnDecl<'_>,
header: hir::FnHeader,
name: Option<Symbol>,
generics: &hir::Generics<'_>,
arg_names: &[Ident],
body_id: Option<hir::BodyId>,
) -> String {
to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id))
}
pub fn enum_def_to_string(
enum_definition: &hir::EnumDef<'_>,
generics: &hir::Generics<'_>,
name: Symbol,
span: rustc_span::Span,
) -> String {
to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span))
pub fn pat_to_string(pat: &hir::Pat<'_>) -> String {
to_string(NO_ANN, |s| s.print_pat(pat))
}
impl<'a> State<'a> {
pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
self.maybe_print_comment(span.hi());
self.break_offset_if_not_bol(1, -INDENT_UNIT);
self.word("}");
@ -250,11 +204,11 @@ pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
}
}
pub fn bclose(&mut self, span: rustc_span::Span) {
fn bclose(&mut self, span: rustc_span::Span) {
self.bclose_maybe_open(span, true)
}
pub fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
where
F: FnMut(&mut State<'_>, &T),
G: FnMut(&T) -> rustc_span::Span,
@ -275,25 +229,25 @@ pub fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut g
self.end();
}
pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
}
pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
self.print_inner_attributes(attrs);
for &item_id in _mod.item_ids {
self.ann.nested(self, Nested::Item(item_id));
}
}
pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) {
if !lifetime.is_elided() {
self.print_lifetime(lifetime);
self.nbsp();
}
}
pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.maybe_print_comment(ty.span.lo());
self.ibox(0);
match ty.kind {
@ -371,7 +325,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
self.end()
}
pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(self.attrs(item.hir_id()));
@ -478,8 +432,7 @@ fn print_item_type(
self.end(); // end the outer ibox
}
/// Pretty-print an item
pub fn print_item(&mut self, item: &hir::Item<'_>) {
fn print_item(&mut self, item: &hir::Item<'_>) {
self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo());
let attrs = self.attrs(item.hir_id());
@ -704,7 +657,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
self.ann.post(self, AnnNode::Item(item))
}
pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
self.print_path(t.path, false);
}
@ -721,7 +674,7 @@ fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
self.print_trait_ref(&t.trait_ref);
}
pub fn print_enum_def(
fn print_enum_def(
&mut self,
enum_definition: &hir::EnumDef<'_>,
generics: &hir::Generics<'_>,
@ -736,7 +689,7 @@ pub fn print_enum_def(
self.print_variants(enum_definition.variants, span);
}
pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
self.bopen();
for v in variants {
self.space_if_not_bol();
@ -751,14 +704,14 @@ pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span
self.bclose(span)
}
pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
match defaultness {
hir::Defaultness::Default { .. } => self.word_nbsp("default"),
hir::Defaultness::Final => (),
}
}
pub fn print_struct(
fn print_struct(
&mut self,
struct_def: &hir::VariantData<'_>,
generics: &hir::Generics<'_>,
@ -807,7 +760,7 @@ pub fn print_struct(
}
}
pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
fn print_variant(&mut self, v: &hir::Variant<'_>) {
self.head("");
let generics = hir::Generics::empty();
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
@ -817,7 +770,8 @@ pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
self.print_anon_const(d);
}
}
pub fn print_method_sig(
fn print_method_sig(
&mut self,
ident: Ident,
m: &hir::FnSig<'_>,
@ -828,7 +782,7 @@ pub fn print_method_sig(
self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id);
}
pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
self.hardbreak_if_not_bol();
self.maybe_print_comment(ti.span.lo());
@ -856,7 +810,7 @@ pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
self.ann.post(self, AnnNode::SubItem(ti.hir_id()))
}
pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
self.hardbreak_if_not_bol();
self.maybe_print_comment(ii.span.lo());
@ -881,7 +835,7 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
}
pub fn print_local(
fn print_local(
&mut self,
init: Option<&hir::Expr<'_>>,
els: Option<&hir::Block<'_>>,
@ -914,7 +868,7 @@ pub fn print_local(
self.end()
}
pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
self.maybe_print_comment(st.span.lo());
match st.kind {
hir::StmtKind::Local(loc) => {
@ -937,19 +891,19 @@ pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
self.maybe_print_trailing_comment(st.span, None)
}
pub fn print_block(&mut self, blk: &hir::Block<'_>) {
fn print_block(&mut self, blk: &hir::Block<'_>) {
self.print_block_with_attrs(blk, &[])
}
pub fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) {
fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) {
self.print_block_maybe_unclosed(blk, &[], false)
}
pub fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) {
fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) {
self.print_block_maybe_unclosed(blk, attrs, true)
}
pub fn print_block_maybe_unclosed(
fn print_block_maybe_unclosed(
&mut self,
blk: &hir::Block<'_>,
attrs: &[ast::Attribute],
@ -1005,7 +959,7 @@ fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
}
}
pub fn print_if(
fn print_if(
&mut self,
test: &hir::Expr<'_>,
blk: &hir::Expr<'_>,
@ -1018,14 +972,14 @@ pub fn print_if(
self.print_else(elseopt)
}
pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
fn print_array_length(&mut self, len: &hir::ArrayLen) {
match len {
hir::ArrayLen::Infer(_, _) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
}
}
pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
fn print_anon_const(&mut self, constant: &hir::AnonConst) {
self.ann.nested(self, Nested::Body(constant.body))
}
@ -1041,7 +995,7 @@ fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
/// `if cond { ... }`.
pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
@ -1360,7 +1314,7 @@ enum AsmArg<'a> {
self.pclose();
}
pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
fn print_expr(&mut self, expr: &hir::Expr<'_>) {
self.maybe_print_comment(expr.span.lo());
self.print_outer_attributes(self.attrs(expr.hir_id));
self.ibox(INDENT_UNIT);
@ -1593,7 +1547,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
self.end()
}
pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
self.print_pat(loc.pat);
if let Some(ty) = loc.ty {
self.word_space(":");
@ -1601,11 +1555,11 @@ pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
}
}
pub fn print_name(&mut self, name: Symbol) {
fn print_name(&mut self, name: Symbol) {
self.print_ident(Ident::with_dummy_span(name))
}
pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
self.maybe_print_comment(path.span.lo());
for (i, segment) in path.segments.iter().enumerate() {
@ -1619,14 +1573,14 @@ pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: b
}
}
pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
self.print_generic_args(segment.args(), false);
}
}
pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
match *qpath {
hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params),
hir::QPath::Resolved(Some(qself), path) => {
@ -1743,7 +1697,7 @@ fn print_generic_args(
}
}
pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
self.print_ident(binding.ident);
self.print_generic_args(binding.gen_args, false);
self.space();
@ -1761,7 +1715,7 @@ pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
}
}
pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
// Pat isn't normalized, but the beauty of it
@ -1905,7 +1859,7 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.ann.post(self, AnnNode::Pat(pat))
}
pub fn print_patfield(&mut self, field: &hir::PatField<'_>) {
fn print_patfield(&mut self, field: &hir::PatField<'_>) {
if self.attrs(field.hir_id).is_empty() {
self.space();
}
@ -1919,12 +1873,12 @@ pub fn print_patfield(&mut self, field: &hir::PatField<'_>) {
self.end();
}
pub fn print_param(&mut self, arg: &hir::Param<'_>) {
fn print_param(&mut self, arg: &hir::Param<'_>) {
self.print_outer_attributes(self.attrs(arg.hir_id));
self.print_pat(arg.pat);
}
pub fn print_arm(&mut self, arm: &hir::Arm<'_>) {
fn print_arm(&mut self, arm: &hir::Arm<'_>) {
// I have no idea why this check is necessary, but here it
// is :(
if self.attrs(arm.hir_id).is_empty() {
@ -1976,7 +1930,7 @@ pub fn print_arm(&mut self, arm: &hir::Arm<'_>) {
self.end() // close enclosing cbox
}
pub fn print_fn(
fn print_fn(
&mut self,
decl: &hir::FnDecl<'_>,
header: hir::FnHeader,
@ -2056,14 +2010,14 @@ fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId)
}
}
pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) {
match capture_clause {
hir::CaptureBy::Value => self.word_space("move"),
hir::CaptureBy::Ref => {}
}
}
pub fn print_closure_binder(
fn print_closure_binder(
&mut self,
binder: hir::ClosureBinder,
generic_params: &[GenericParam<'_>],
@ -2083,7 +2037,8 @@ pub fn print_closure_binder(
match binder {
hir::ClosureBinder::Default => {}
// we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions
// We need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional
// restrictions.
hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"),
hir::ClosureBinder::For { .. } => {
self.word("for");
@ -2099,7 +2054,7 @@ pub fn print_closure_binder(
}
}
pub fn print_bounds<'b>(
fn print_bounds<'b>(
&mut self,
prefix: &'static str,
bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>,
@ -2137,7 +2092,7 @@ pub fn print_bounds<'b>(
}
}
pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
if !generic_params.is_empty() {
self.word("<");
@ -2147,7 +2102,7 @@ pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) {
}
}
pub fn print_generic_param(&mut self, param: &GenericParam<'_>) {
fn print_generic_param(&mut self, param: &GenericParam<'_>) {
if let GenericParamKind::Const { .. } = param.kind {
self.word_space("const");
}
@ -2175,11 +2130,11 @@ pub fn print_generic_param(&mut self, param: &GenericParam<'_>) {
}
}
pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
fn print_lifetime(&mut self, lifetime: &hir::Lifetime) {
self.print_ident(lifetime.ident)
}
pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
if generics.predicates.is_empty() {
return;
}
@ -2236,7 +2191,7 @@ pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) {
}
}
pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
match mutbl {
hir::Mutability::Mut => self.word_nbsp("mut"),
hir::Mutability::Not => {
@ -2247,12 +2202,12 @@ pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
}
}
pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
self.print_mutability(mt.mutbl, print_const);
self.print_type(mt.ty);
}
pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
if let hir::FnRetTy::DefaultReturn(..) = decl.output {
return;
}
@ -2271,7 +2226,7 @@ pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
}
}
pub fn print_ty_fn(
fn print_ty_fn(
&mut self,
abi: Abi,
unsafety: hir::Unsafety,
@ -2299,7 +2254,7 @@ pub fn print_ty_fn(
self.end();
}
pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
self.print_constness(header.constness);
match header.asyncness {
@ -2317,21 +2272,21 @@ pub fn print_fn_header_info(&mut self, header: hir::FnHeader) {
self.word("fn")
}
pub fn print_constness(&mut self, s: hir::Constness) {
fn print_constness(&mut self, s: hir::Constness) {
match s {
hir::Constness::NotConst => {}
hir::Constness::Const => self.word_nbsp("const"),
}
}
pub fn print_unsafety(&mut self, s: hir::Unsafety) {
fn print_unsafety(&mut self, s: hir::Unsafety) {
match s {
hir::Unsafety::Normal => {}
hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
}
}
pub fn print_is_auto(&mut self, s: hir::IsAuto) {
fn print_is_auto(&mut self, s: hir::IsAuto) {
match s {
hir::IsAuto::Yes => self.word_nbsp("auto"),
hir::IsAuto::No => {}

View File

@ -2036,7 +2036,8 @@ fn label_fn_like(
}
let typeck = self.typeck_results.borrow();
for (rcvr, args) in call_finder.calls {
if let Some(rcvr_ty) = typeck.node_type_opt(rcvr.hir_id)
if rcvr.hir_id.owner == typeck.hir_owner
&& let Some(rcvr_ty) = typeck.node_type_opt(rcvr.hir_id)
&& let ty::Closure(call_def_id, _) = rcvr_ty.kind()
&& def_id == *call_def_id
&& let Some(idx) = expected_idx

View File

@ -1504,9 +1504,7 @@ fn error_tuple_variant_index_shorthand(
{
let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand);
if has_shorthand_field_name {
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
s.print_qpath(qpath, false)
});
let path = rustc_hir_pretty::qpath_to_string(qpath);
let mut err = struct_span_err!(
self.tcx.sess,
pat.span,
@ -1688,9 +1686,7 @@ fn error_tuple_variant_as_struct_pat(
return None;
}
let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
s.print_qpath(qpath, false)
});
let path = rustc_hir_pretty::qpath_to_string(qpath);
let mut err = struct_span_err!(
self.tcx.sess,
pat.span,
@ -1740,9 +1736,7 @@ fn get_suggested_tuple_struct_pattern(
f
}
}
Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
s.print_pat(field.pat)
}),
Err(_) => rustc_hir_pretty::pat_to_string(field.pat),
}
})
.collect::<Vec<String>>()

View File

@ -46,8 +46,6 @@ incremental_delete_partial = failed to delete partly initialized session dir `{$
incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
incremental_field_associated_value_expected = associated value expected for `{$name}`
incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
incremental_finalized_gc_failed =
@ -63,25 +61,15 @@ incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$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_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_missing_depnode = missing `DepNode` variant
incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
incremental_missing_query_depgraph =
found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err}
incremental_no_cfg = no cfg attribute
incremental_no_field = no field `{$name}`
incremental_no_module_named =
no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
incremental_no_path = no path from `{$source}` to `{$target}`
incremental_not_clean = `{$dep_node_str}` should be clean but is not
@ -107,8 +95,6 @@ incremental_undefined_clean_dirty_assertions_item =
incremental_unknown_item = unknown item `{$name}`
incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized

View File

@ -40,56 +40,6 @@ pub struct NoPath {
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> {

View File

@ -16,7 +16,6 @@
extern crate tracing;
mod assert_dep_graph;
pub mod assert_module_sources;
mod errors;
mod persist;

View File

@ -957,10 +957,9 @@ pub fn start_codegen<'tcx>(
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
// Don't run these test assertions when not doing codegen. Compiletest tries to build
// Don't run this test assertions when not doing codegen. Compiletest tries to build
// build-fail tests in check mode first and expects it to not give an error in that case.
if tcx.sess.opts.output_types.should_codegen() {
rustc_incremental::assert_module_sources::assert_module_sources(tcx);
rustc_symbol_mangling::test::report_symbol_names(tcx);
}

View File

@ -727,11 +727,14 @@ fn lookup_with_diagnostics(
.collect::<Vec<_>>();
possibilities.sort();
let mut should_print_possibilities = true;
if let Some((value, value_span)) = value {
if best_match_values.contains(&Some(value)) {
db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
should_print_possibilities = false;
} else if best_match_values.contains(&None) {
db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
should_print_possibilities = false;
} else if let Some(first_value) = possibilities.first() {
db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
} else {
@ -741,13 +744,25 @@ fn lookup_with_diagnostics(
db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
}
if !possibilities.is_empty() {
if !possibilities.is_empty() && should_print_possibilities {
let possibilities = possibilities.join("`, `");
db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
}
} else {
db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
}
} else if !possibilities.is_empty() {
let mut possibilities = possibilities.iter()
.map(Symbol::as_str)
.collect::<Vec<_>>();
possibilities.sort();
let possibilities = possibilities.join("`, `");
// The list of expected names can be long (even by default) and
// so the diagnostic produced can take a lot of space. To avoid
// cloging the user output we only want to print that diagnostic
// once.
db.help_once(format!("expected names are: `{possibilities}`"));
}
},
BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {

View File

@ -506,6 +506,11 @@ macro_rules! add_lint_group {
"replaced with another group of lints, see RFC \
<https://rust-lang.github.io/rfcs/2145-type-privacy.html> for more information",
);
store.register_removed(
"invalid_alignment",
"converted into hard error, see PR #104616 \
<https://github.com/rust-lang/rust/pull/104616> for more information",
);
}
fn register_internals(store: &mut LintStore) {

View File

@ -986,45 +986,6 @@
"detects trivial casts of numeric types which could be removed"
}
declare_lint! {
/// The `invalid_alignment` lint detects dereferences of misaligned pointers during
/// constant evaluation.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(const_mut_refs)]
/// const FOO: () = unsafe {
/// let x = &[0_u8; 4];
/// let y = x.as_ptr().cast::<u32>();
/// let mut z = 123;
/// y.copy_to_nonoverlapping(&mut z, 1); // the address of a `u8` array is unknown
/// // and thus we don't know if it is aligned enough for copying a `u32`.
/// };
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The compiler allowed dereferencing raw pointers irrespective of alignment
/// during const eval due to the const evaluator at the time not making it easy
/// or cheap to check. Now that it is both, this is not accepted anymore.
///
/// Since it was undefined behaviour to begin with, this breakage does not violate
/// Rust's stability guarantees. Using undefined behaviour can cause arbitrary
/// behaviour, including failure to build.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub INVALID_ALIGNMENT,
Deny,
"raw pointers must be aligned before dereferencing",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>",
};
}
declare_lint! {
/// The `exported_private_dependencies` lint detects private dependencies
/// that are exposed in a public interface.
@ -3430,7 +3391,6 @@
INDIRECT_STRUCTURAL_MATCH,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
INLINE_NO_SANITIZE,
INVALID_ALIGNMENT,
INVALID_DOC_ATTRIBUTES,
INVALID_MACRO_EXPORT_ARGUMENTS,
INVALID_TYPE_PARAM_DEFAULT,

File diff suppressed because it is too large Load Diff

View File

@ -307,7 +307,7 @@
use self::ArmType::*;
use self::Usefulness::*;
use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, Fields};
use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
use rustc_data_structures::captures::Captures;
@ -368,8 +368,6 @@ pub(super) struct PatCtxt<'a, 'p, 'tcx> {
/// Whether the current pattern is the whole pattern as found in a match arm, or if it's a
/// subpattern.
pub(super) is_top_level: bool,
/// Whether the current pattern is from a `non_exhaustive` enum.
pub(super) is_non_exhaustive: bool,
}
impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
@ -616,62 +614,41 @@ fn apply_constructor(
WithWitnesses(ref witnesses) if witnesses.is_empty() => self,
WithWitnesses(witnesses) => {
let new_witnesses = if let Constructor::Missing { .. } = ctor {
// We got the special `Missing` constructor, so each of the missing constructors
// gives a new pattern that is not caught by the match. We list those patterns.
if pcx.is_non_exhaustive {
witnesses
.into_iter()
// Here we don't want the user to try to list all variants, we want them to add
// a wildcard, so we only suggest that.
.map(|witness| {
witness.apply_constructor(pcx, &Constructor::NonExhaustive)
})
.collect()
} else {
let mut split_wildcard = SplitWildcard::new(pcx);
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
// This lets us know if we skipped any variants because they are marked
// `doc(hidden)` or they are unstable feature gate (only stdlib types).
let mut hide_variant_show_wild = false;
// Construct for each missing constructor a "wild" version of this
// constructor, that matches everything that can be built with
// it. For example, if `ctor` is a `Constructor::Variant` for
// `Option::Some`, we get the pattern `Some(_)`.
let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard
.iter_missing(pcx)
.filter_map(|missing_ctor| {
// Check if this variant is marked `doc(hidden)`
if missing_ctor.is_doc_hidden_variant(pcx)
|| missing_ctor.is_unstable_variant(pcx)
{
hide_variant_show_wild = true;
return None;
}
Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()))
})
.collect();
if hide_variant_show_wild {
new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
}
witnesses
.into_iter()
.flat_map(|witness| {
new_patterns.iter().map(move |pat| {
Witness(
witness
.0
.iter()
.chain(once(pat))
.map(DeconstructedPat::clone_and_forget_reachability)
.collect(),
)
})
})
.collect()
let mut missing = ConstructorSet::for_ty(pcx.cx, pcx.ty)
.compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor));
if missing.iter().any(|c| c.is_non_exhaustive()) {
// We only report `_` here; listing other constructors would be redundant.
missing = vec![Constructor::NonExhaustive];
}
// We got the special `Missing` constructor, so each of the missing constructors
// gives a new pattern that is not caught by the match.
// We construct for each missing constructor a version of this constructor with
// wildcards for fields, i.e. that matches everything that can be built with it.
// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get
// the pattern `Some(_)`.
let new_patterns: Vec<DeconstructedPat<'_, '_>> = missing
.into_iter()
.map(|missing_ctor| {
DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())
})
.collect();
witnesses
.into_iter()
.flat_map(|witness| {
new_patterns.iter().map(move |pat| {
Witness(
witness
.0
.iter()
.chain(once(pat))
.map(DeconstructedPat::clone_and_forget_reachability)
.collect(),
)
})
})
.collect()
} else {
witnesses
.into_iter()
@ -844,9 +821,8 @@ fn is_useful<'p, 'tcx>(
ty = row.head().ty();
}
}
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level };
let v_ctor = v.head().ctor();
debug!(?v_ctor);
@ -861,7 +837,8 @@ fn is_useful<'p, 'tcx>(
}
// We split the head constructor of `v`.
let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard();
let is_non_exhaustive_and_wild =
cx.is_foreign_non_exhaustive_enum(ty) && v_ctor.is_wildcard();
// For each constructor, we compute whether there's a value that starts with it that would
// witness the usefulness of `v`.
let start_matrix = &matrix;
@ -895,27 +872,21 @@ fn is_useful<'p, 'tcx>(
&& usefulness.is_useful() && matches!(witness_preference, RealArm)
&& matches!(
&ctor,
Constructor::Missing { nonexhaustive_enum_missing_real_variants: true }
Constructor::Missing { nonexhaustive_enum_missing_visible_variants: true }
)
{
let patterns = {
let mut split_wildcard = SplitWildcard::new(pcx);
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
// Construct for each missing constructor a "wild" version of this
// constructor, that matches everything that can be built with
// it. For example, if `ctor` is a `Constructor::Variant` for
// `Option::Some`, we get the pattern `Some(_)`.
split_wildcard
.iter_missing(pcx)
// Filter out the `NonExhaustive` because we want to list only real
// variants. Also remove any unstable feature gated variants.
// Because of how we computed `nonexhaustive_enum_missing_real_variants`,
// this will not return an empty `Vec`.
.filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx)))
.cloned()
.map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor))
.collect::<Vec<_>>()
};
let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty)
.compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor));
// Construct for each missing constructor a "wild" version of this constructor, that
// matches everything that can be built with it. For example, if `ctor` is a
// `Constructor::Variant` for `Option::Some`, we get the pattern `Some(_)`.
let patterns = missing
.into_iter()
// Because of how we computed `nonexhaustive_enum_missing_visible_variants`,
// this will not return an empty `Vec`.
.filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden)))
.map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor))
.collect::<Vec<_>>();
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
// is not exhaustive enough.

View File

@ -2,8 +2,6 @@
//! assertion failures
use either::Right;
use rustc_const_eval::const_eval::CheckAlignment;
use rustc_const_eval::ReportErrorExt;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
@ -16,7 +14,7 @@
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
use crate::dataflow_const_prop::Patch;
@ -141,27 +139,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
type MemoryKind = !;
#[inline(always)]
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
// We do not check for alignment to avoid having to carry an `Align`
// in `ConstValue::Indirect`.
CheckAlignment::No
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // no reason to enforce alignment
}
#[inline(always)]
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
false // for now, we don't enforce validity
}
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
_has: Align,
_required: Align,
_check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
span_bug!(
ecx.cur_span(),
"`alignment_check_failed` called when no alignment check requested"
)
}
fn load_mir(
_ecx: &InterpCx<'mir, 'tcx, Self>,

View File

@ -245,13 +245,13 @@ fn make_bcb_counters(
// the loop. The `traversal` state includes a `context_stack`, providing a way to know if
// the current BCB is in one or more nested loops or not.
let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks);
while let Some(bcb) = traversal.next(self.basic_coverage_blocks) {
while let Some(bcb) = traversal.next() {
if bcb_has_coverage_spans(bcb) {
debug!("{:?} has at least one coverage span. Get or make its counter", bcb);
let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
if self.bcb_needs_branch_counters(bcb) {
self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?;
self.make_branch_counters(&traversal, bcb, branching_counter_operand)?;
}
} else {
debug!(
@ -274,7 +274,7 @@ fn make_bcb_counters(
fn make_branch_counters(
&mut self,
traversal: &mut TraverseCoverageGraphWithLoops,
traversal: &TraverseCoverageGraphWithLoops<'_>,
branching_bcb: BasicCoverageBlock,
branching_counter_operand: Operand,
) -> Result<(), Error> {
@ -507,21 +507,14 @@ fn recursive_get_or_make_edge_counter_operand(
/// found, select any branch.
fn choose_preferred_expression_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
traversal: &TraverseCoverageGraphWithLoops<'_>,
branches: &[BcbBranch],
) -> BcbBranch {
let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches);
if let Some(reloop_branch_without_counter) =
some_reloop_branch.filter(branch_needs_a_counter)
{
debug!(
"Selecting reloop_branch={:?} that still needs a counter, to get the \
`Expression`",
reloop_branch_without_counter
);
reloop_branch_without_counter
let good_reloop_branch = self.find_good_reloop_branch(traversal, &branches);
if let Some(reloop_branch) = good_reloop_branch {
assert!(self.branch_has_no_counter(&reloop_branch));
debug!("Selecting reloop branch {reloop_branch:?} to get an expression");
reloop_branch
} else {
let &branch_without_counter =
branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect(
@ -538,75 +531,52 @@ fn choose_preferred_expression_branch(
}
}
/// At most, one of the branches (or its edge, from the branching_bcb, if the branch has
/// multiple incoming edges) can have a counter computed by expression.
///
/// If at least one of the branches leads outside of a loop (`found_loop_exit` is
/// true), and at least one other branch does not exit the loop (the first of which
/// is captured in `some_reloop_branch`), it's likely any reloop branch will be
/// executed far more often than loop exit branch, making the reloop branch a better
/// candidate for an expression.
fn find_some_reloop_branch(
/// Tries to find a branch that leads back to the top of a loop, and that
/// doesn't already have a counter. Such branches are good candidates to
/// be given an expression (instead of a physical counter), because they
/// will tend to be executed more times than a loop-exit branch.
fn find_good_reloop_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
traversal: &TraverseCoverageGraphWithLoops<'_>,
branches: &[BcbBranch],
) -> Option<BcbBranch> {
let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch);
// Consider each loop on the current traversal context stack, top-down.
for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
let mut all_branches_exit_this_loop = true;
let mut some_reloop_branch: Option<BcbBranch> = None;
for context in traversal.context_stack.iter().rev() {
if let Some((backedge_from_bcbs, _)) = &context.loop_backedges {
let mut found_loop_exit = false;
for &branch in branches.iter() {
if backedge_from_bcbs.iter().any(|&backedge_from_bcb| {
self.bcb_dominates(branch.target_bcb, backedge_from_bcb)
}) {
if let Some(reloop_branch) = some_reloop_branch {
if self.branch_has_no_counter(&reloop_branch) {
// we already found a candidate reloop_branch that still
// needs a counter
continue;
}
}
// The path from branch leads back to the top of the loop. Set this
// branch as the `reloop_branch`. If this branch already has a
// counter, and we find another reloop branch that doesn't have a
// counter yet, that branch will be selected as the `reloop_branch`
// instead.
some_reloop_branch = Some(branch);
} else {
// The path from branch leads outside this loop
found_loop_exit = true;
}
if found_loop_exit
&& some_reloop_branch.filter(branch_needs_a_counter).is_some()
{
// Found both a branch that exits the loop and a branch that returns
// to the top of the loop (`reloop_branch`), and the `reloop_branch`
// doesn't already have a counter.
break;
// Try to find a branch that doesn't exit this loop and doesn't
// already have a counter.
for &branch in branches {
// A branch is a reloop branch if it dominates any BCB that has
// an edge back to the loop header. (Other branches are exits.)
let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| {
self.basic_coverage_blocks.dominates(branch.target_bcb, reloop_bcb)
});
if is_reloop_branch {
all_branches_exit_this_loop = false;
if self.branch_has_no_counter(&branch) {
// We found a good branch to be given an expression.
return Some(branch);
}
// Keep looking for another reloop branch without a counter.
} else {
// This branch exits the loop.
}
if !found_loop_exit {
debug!(
"No branches exit the loop, so any branch without an existing \
counter can have the `Expression`."
);
break;
}
if some_reloop_branch.is_some() {
debug!(
"Found a branch that exits the loop and a branch the loops back to \
the top of the loop (`reloop_branch`). The `reloop_branch` will \
get the `Expression`, as long as it still needs a counter."
);
break;
}
// else all branches exited this loop context, so run the same checks with
// the outer loop(s)
}
if !all_branches_exit_this_loop {
// We found one or more reloop branches, but all of them already
// have counters. Let the caller choose one of the exit branches.
debug!("All reloop branches had counters; skip checking the other loops");
return None;
}
// All of the branches exit this loop, so keep looking for a good
// reloop branch for one of the outer loops.
}
some_reloop_branch
None
}
#[inline]
@ -652,9 +622,4 @@ fn branch_counter(&self, branch: &BcbBranch) -> Option<&BcbCounter> {
fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool {
self.bcb_predecessors(bcb).len() <= 1
}
#[inline]
fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
self.basic_coverage_blocks.dominates(dom, node)
}
}

View File

@ -6,6 +6,7 @@
use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::ops::{Index, IndexMut};
/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
@ -385,57 +386,72 @@ fn bcb_filtered_successors<'a, 'tcx>(
/// ensures a loop is completely traversed before processing Blocks after the end of the loop.
#[derive(Debug)]
pub(super) struct TraversalContext {
/// From one or more backedges returning to a loop header.
pub loop_backedges: Option<(Vec<BasicCoverageBlock>, BasicCoverageBlock)>,
/// BCB with one or more incoming loop backedges, indicating which loop
/// this context is for.
///
/// If `None`, this is the non-loop context for the function as a whole.
loop_header: Option<BasicCoverageBlock>,
/// worklist, to be traversed, of CoverageGraph in the loop with the given loop
/// backedges, such that the loop is the inner inner-most loop containing these
/// CoverageGraph
pub worklist: Vec<BasicCoverageBlock>,
/// Worklist of BCBs to be processed in this context.
worklist: VecDeque<BasicCoverageBlock>,
}
pub(super) struct TraverseCoverageGraphWithLoops {
pub backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
pub context_stack: Vec<TraversalContext>,
pub(super) struct TraverseCoverageGraphWithLoops<'a> {
basic_coverage_blocks: &'a CoverageGraph,
backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
context_stack: Vec<TraversalContext>,
visited: BitSet<BasicCoverageBlock>,
}
impl TraverseCoverageGraphWithLoops {
pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
let start_bcb = basic_coverage_blocks.start_node();
impl<'a> TraverseCoverageGraphWithLoops<'a> {
pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
let backedges = find_loop_backedges(basic_coverage_blocks);
let context_stack =
vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }];
let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
let context_stack = vec![TraversalContext { loop_header: None, worklist }];
// `context_stack` starts with a `TraversalContext` for the main function context (beginning
// with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top
// of the stack as loops are entered, and popped off of the stack when a loop's worklist is
// exhausted.
let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
Self { backedges, context_stack, visited }
Self { basic_coverage_blocks, backedges, context_stack, visited }
}
pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option<BasicCoverageBlock> {
/// For each loop on the loop context stack (top-down), yields a list of BCBs
/// within that loop that have an outgoing edge back to the loop header.
pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
self.context_stack
.iter()
.rev()
.filter_map(|context| context.loop_header)
.map(|header_bcb| self.backedges[header_bcb].as_slice())
}
pub(super) fn next(&mut self) -> Option<BasicCoverageBlock> {
debug!(
"TraverseCoverageGraphWithLoops::next - context_stack: {:?}",
self.context_stack.iter().rev().collect::<Vec<_>>()
);
while let Some(context) = self.context_stack.last_mut() {
if let Some(next_bcb) = context.worklist.pop() {
if !self.visited.insert(next_bcb) {
debug!("Already visited: {:?}", next_bcb);
if let Some(bcb) = context.worklist.pop_front() {
if !self.visited.insert(bcb) {
debug!("Already visited: {bcb:?}");
continue;
}
debug!("Visiting {:?}", next_bcb);
if self.backedges[next_bcb].len() > 0 {
debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb);
debug!("Visiting {bcb:?}");
if self.backedges[bcb].len() > 0 {
debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
self.context_stack.push(TraversalContext {
loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)),
worklist: Vec::new(),
loop_header: Some(bcb),
worklist: VecDeque::new(),
});
}
self.extend_worklist(basic_coverage_blocks, next_bcb);
return Some(next_bcb);
self.add_successors_to_worklists(bcb);
return Some(bcb);
} else {
// Strip contexts with empty worklists from the top of the stack
self.context_stack.pop();
@ -445,13 +461,10 @@ pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option<BasicCov
None
}
pub fn extend_worklist(
&mut self,
basic_coverage_blocks: &CoverageGraph,
bcb: BasicCoverageBlock,
) {
let successors = &basic_coverage_blocks.successors[bcb];
pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) {
let successors = &self.basic_coverage_blocks.successors[bcb];
debug!("{:?} has {} successors:", bcb, successors.len());
for &successor in successors {
if successor == bcb {
debug!(
@ -460,56 +473,44 @@ pub fn extend_worklist(
bcb
);
// Don't re-add this successor to the worklist. We are already processing it.
// FIXME: This claims to skip just the self-successor, but it actually skips
// all other successors as well. Does that matter?
break;
}
for context in self.context_stack.iter_mut().rev() {
// Add successors of the current BCB to the appropriate context. Successors that
// stay within a loop are added to the BCBs context worklist. Successors that
// exit the loop (they are not dominated by the loop header) must be reachable
// from other BCBs outside the loop, and they will be added to a different
// worklist.
//
// Branching blocks (with more than one successor) must be processed before
// blocks with only one successor, to prevent unnecessarily complicating
// `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
// branching block would have given an `Expression` (or vice versa).
let (some_successor_to_add, some_loop_header) =
if let Some((_, loop_header)) = context.loop_backedges {
if basic_coverage_blocks.dominates(loop_header, successor) {
(Some(successor), Some(loop_header))
} else {
(None, None)
}
} else {
(Some(successor), None)
};
if let Some(successor_to_add) = some_successor_to_add {
if basic_coverage_blocks.successors[successor_to_add].len() > 1 {
debug!(
"{:?} successor is branching. Prioritize it at the beginning of \
the {}",
successor_to_add,
if let Some(loop_header) = some_loop_header {
format!("worklist for the loop headed by {loop_header:?}")
} else {
String::from("non-loop worklist")
},
);
context.worklist.insert(0, successor_to_add);
} else {
debug!(
"{:?} successor is non-branching. Defer it to the end of the {}",
successor_to_add,
if let Some(loop_header) = some_loop_header {
format!("worklist for the loop headed by {loop_header:?}")
} else {
String::from("non-loop worklist")
},
);
context.worklist.push(successor_to_add);
// Add successors of the current BCB to the appropriate context. Successors that
// stay within a loop are added to the BCBs context worklist. Successors that
// exit the loop (they are not dominated by the loop header) must be reachable
// from other BCBs outside the loop, and they will be added to a different
// worklist.
//
// Branching blocks (with more than one successor) must be processed before
// blocks with only one successor, to prevent unnecessarily complicating
// `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
// branching block would have given an `Expression` (or vice versa).
let context = self
.context_stack
.iter_mut()
.rev()
.find(|context| match context.loop_header {
Some(loop_header) => {
self.basic_coverage_blocks.dominates(loop_header, successor)
}
break;
}
None => true,
})
.unwrap_or_else(|| bug!("should always fall back to the root non-loop context"));
debug!("adding to worklist for {:?}", context.loop_header);
// FIXME: The code below had debug messages claiming to add items to a
// particular end of the worklist, but was confused about which end was
// which. The existing behaviour has been preserved for now, but it's
// unclear what the intended behaviour was.
if self.basic_coverage_blocks.successors[successor].len() > 1 {
context.worklist.push_back(successor);
} else {
context.worklist.push_front(successor);
}
}
}

View File

@ -628,7 +628,7 @@ fn test_traverse_coverage_with_loops() {
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
let mut traversed_in_order = Vec::new();
let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks);
while let Some(bcb) = traversal.next(&basic_coverage_blocks) {
while let Some(bcb) = traversal.next() {
traversed_in_order.push(bcb);
}

View File

@ -2,7 +2,6 @@
//!
//! Currently, this pass only propagates scalar values.
use rustc_const_eval::const_eval::CheckAlignment;
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
@ -17,7 +16,7 @@
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
use rustc_span::def_id::DefId;
use rustc_span::DUMMY_SP;
use rustc_target::abi::{Align, FieldIdx, VariantIdx};
use rustc_target::abi::{FieldIdx, VariantIdx};
use crate::MirPass;
@ -709,23 +708,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
const PANIC_ON_ALLOC_FAIL: bool = true;
#[inline(always)]
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment {
// We do not check for alignment to avoid having to carry an `Align`
// in `ConstValue::ByRef`.
CheckAlignment::No
fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // no reason to enforce alignment
}
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
unimplemented!()
}
fn alignment_check_failed(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_has: Align,
_required: Align,
_check: CheckAlignment,
) -> interpret::InterpResult<'tcx, ()> {
unimplemented!()
}
fn before_access_global(
_tcx: TyCtxt<'tcx>,

View File

@ -827,6 +827,65 @@ pub fn maybe_suggest_struct_literal(
None
}
pub(super) fn recover_closure_body(
&mut self,
mut err: DiagnosticBuilder<'a, ErrorGuaranteed>,
before: token::Token,
prev: token::Token,
token: token::Token,
lo: Span,
decl_hi: Span,
) -> PResult<'a, P<Expr>> {
err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
match before.kind {
token::OpenDelim(Delimiter::Brace)
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
{
// `{ || () }` should have been `|| { () }`
err.multipart_suggestion(
"you might have meant to open the body of the closure, instead of enclosing \
the closure in a block",
vec![
(before.span, String::new()),
(prev.span.shrink_to_hi(), " {".to_string()),
],
Applicability::MaybeIncorrect,
);
err.emit();
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
}
token::OpenDelim(Delimiter::Parenthesis)
if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
{
// We are within a function call or tuple, we can emit the error
// and recover.
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis), &token::Comma]);
err.multipart_suggestion_verbose(
"you might have meant to open the body of the closure",
vec![
(prev.span.shrink_to_hi(), " {".to_string()),
(self.token.span.shrink_to_lo(), "}".to_string()),
],
Applicability::MaybeIncorrect,
);
err.emit();
}
_ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => {
// We don't have a heuristic to correctly identify where the block
// should be closed.
err.multipart_suggestion_verbose(
"you might have meant to open the body of the closure",
vec![(prev.span.shrink_to_hi(), " {".to_string())],
Applicability::HasPlaceholders,
);
return Err(err);
}
_ => return Err(err),
}
Ok(self.mk_expr_err(lo.to(self.token.span)))
}
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {

View File

@ -2209,6 +2209,7 @@ fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
let before = self.prev_token.clone();
let binder = if self.check_keyword(kw::For) {
let lo = self.token.span;
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
@ -2239,7 +2240,12 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
FnRetTy::Default(_) => {
let restrictions =
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
self.parse_expr_res(restrictions, None)?
let prev = self.prev_token.clone();
let token = self.token.clone();
match self.parse_expr_res(restrictions, None) {
Ok(expr) => expr,
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
}
}
_ => {
// If an explicit return type is given, require a block to appear (RFC 968).
@ -2459,10 +2465,16 @@ fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
/// Parses a `let $pat = $expr` pseudo-expression.
fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
let is_recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
Some(self.sess.emit_err(errors::ExpectedExpressionFoundLet {
let err = errors::ExpectedExpressionFoundLet {
span: self.token.span,
reason: ForbiddenLetReason::OtherForbidden,
}))
};
if self.prev_token.kind == token::BinOp(token::Or) {
// This was part of a closure, the that part of the parser recover.
return Err(err.into_diagnostic(&self.sess.span_diagnostic));
} else {
Some(self.sess.emit_err(err))
}
} else {
None
};

View File

@ -5,9 +5,6 @@ session_cannot_enable_crt_static_linux = sanitizer is incompatible with statical
session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
session_cgu_not_recorded =
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded
session_cli_feature_diagnostic_help =
add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
@ -34,12 +31,6 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n
session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
.note = compatible flavors are: {$compatible_list}
session_incorrect_cgu_reuse_type =
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
[one] {"at least "}
*[other] {""}
}`{$expected_reuse}`
session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
session_int_literal_too_large = integer literal is too large

View File

@ -1,136 +0,0 @@
//! Some facilities for tracking how codegen-units are reused during incremental
//! compilation. This is used for incremental compilation tests and debug
//! output.
use crate::errors::{CguNotRecorded, IncorrectCguReuseType};
use crate::Session;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
use std::fmt::{self};
use std::sync::{Arc, Mutex};
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum CguReuse {
No,
PreLto,
PostLto,
}
impl fmt::Display for CguReuse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
CguReuse::No => write!(f, "No"),
CguReuse::PreLto => write!(f, "PreLto "),
CguReuse::PostLto => write!(f, "PostLto "),
}
}
}
impl IntoDiagnosticArg for CguReuse {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ComparisonKind {
Exact,
AtLeast,
}
struct TrackerData {
actual_reuse: FxHashMap<String, CguReuse>,
expected_reuse: FxHashMap<String, (String, SendSpan, CguReuse, ComparisonKind)>,
}
// Span does not implement `Send`, so we can't just store it in the shared
// `TrackerData` object. Instead of splitting up `TrackerData` into shared and
// non-shared parts (which would be complicated), we just mark the `Span` here
// explicitly as `Send`. That's safe because the span data here is only ever
// accessed from the main thread.
struct SendSpan(Span);
unsafe impl Send for SendSpan {}
#[derive(Clone)]
pub struct CguReuseTracker {
data: Option<Arc<Mutex<TrackerData>>>,
}
impl CguReuseTracker {
pub fn new() -> CguReuseTracker {
let data =
TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() };
CguReuseTracker { data: Some(Arc::new(Mutex::new(data))) }
}
pub fn new_disabled() -> CguReuseTracker {
CguReuseTracker { data: None }
}
pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) {
if let Some(ref data) = self.data {
debug!("set_actual_reuse({cgu_name:?}, {kind:?})");
let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind);
if let Some(prev_reuse) = prev_reuse {
// The only time it is legal to overwrite reuse state is when
// we discover during ThinLTO that we can actually reuse the
// post-LTO version of a CGU.
assert_eq!(prev_reuse, CguReuse::PreLto);
}
}
}
pub fn set_expectation(
&self,
cgu_name: Symbol,
cgu_user_name: &str,
error_span: Span,
expected_reuse: CguReuse,
comparison_kind: ComparisonKind,
) {
if let Some(ref data) = self.data {
debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})");
let mut data = data.lock().unwrap();
data.expected_reuse.insert(
cgu_name.to_string(),
(cgu_user_name.to_string(), SendSpan(error_span), expected_reuse, comparison_kind),
);
}
}
pub fn check_expected_reuse(&self, sess: &Session) {
if let Some(ref data) = self.data {
let data = data.lock().unwrap();
for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in
&data.expected_reuse
{
if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) {
let (error, at_least) = match comparison_kind {
ComparisonKind::Exact => (expected_reuse != actual_reuse, false),
ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true),
};
if error {
let at_least = if at_least { 1 } else { 0 };
IncorrectCguReuseType {
span: error_span.0,
cgu_user_name,
actual_reuse,
expected_reuse,
at_least,
};
}
} else {
sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name });
}
}
}
}
}

View File

@ -2925,8 +2925,8 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) ->
"expanded" => Source(PpSourceMode::Expanded),
"expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
"expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
"ast-tree" => AstTree(PpAstTreeMode::Normal),
"ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
"ast-tree" => AstTree,
"ast-tree,expanded" => AstTreeExpanded,
"hir" => Hir(PpHirMode::Normal),
"hir,identified" => Hir(PpHirMode::Identified),
"hir,typed" => Hir(PpHirMode::Typed),
@ -3083,14 +3083,6 @@ pub enum PpSourceMode {
ExpandedHygiene,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpAstTreeMode {
/// `-Zunpretty=ast`
Normal,
/// `-Zunpretty=ast,expanded`
Expanded,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpHirMode {
/// `-Zunpretty=hir`
@ -3106,7 +3098,10 @@ pub enum PpMode {
/// Options that print the source code, i.e.
/// `-Zunpretty=normal` and `-Zunpretty=expanded`
Source(PpSourceMode),
AstTree(PpAstTreeMode),
/// `-Zunpretty=ast-tree`
AstTree,
/// `-Zunpretty=ast-tree,expanded`
AstTreeExpanded,
/// Options that print the HIR, i.e. `-Zunpretty=hir`
Hir(PpHirMode),
/// `-Zunpretty=hir-tree`
@ -3126,10 +3121,10 @@ pub fn needs_ast_map(&self) -> bool {
use PpMode::*;
use PpSourceMode::*;
match *self {
Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
Source(Normal | Identified) | AstTree => false,
Source(Expanded | ExpandedIdentified | ExpandedHygiene)
| AstTree(PpAstTreeMode::Expanded)
| AstTreeExpanded
| Hir(_)
| HirTree
| ThirTree
@ -3141,7 +3136,7 @@ pub fn needs_ast_map(&self) -> bool {
pub fn needs_hir(&self) -> bool {
use PpMode::*;
match *self {
Source(_) | AstTree(_) => false,
Source(_) | AstTree | AstTreeExpanded => false,
Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true,
}
@ -3149,7 +3144,7 @@ pub fn needs_hir(&self) -> bool {
pub fn needs_analysis(&self) -> bool {
use PpMode::*;
matches!(*self, Mir | MirCFG | ThirTree | ThirFlat)
matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat)
}
}

View File

@ -1,6 +1,5 @@
use std::num::NonZeroU32;
use crate::cgu_reuse_tracker::CguReuse;
use crate::parse::ParseSess;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
@ -9,24 +8,6 @@
use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
#[derive(Diagnostic)]
#[diag(session_incorrect_cgu_reuse_type)]
pub struct IncorrectCguReuseType<'a> {
#[primary_span]
pub span: Span,
pub cgu_user_name: &'a str,
pub actual_reuse: CguReuse,
pub expected_reuse: CguReuse,
pub at_least: u8,
}
#[derive(Diagnostic)]
#[diag(session_cgu_not_recorded)]
pub struct CguNotRecorded<'a> {
pub cgu_user_name: &'a str,
pub cgu_name: &'a str,
}
pub struct FeatureGateError {
pub span: MultiSpan,
pub explain: DiagnosticMessage,

View File

@ -23,7 +23,6 @@
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages;
pub mod cgu_reuse_tracker;
pub mod utils;
pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
pub use rustc_lint_defs as lint;

View File

@ -1,4 +1,3 @@
use crate::cgu_reuse_tracker::CguReuseTracker;
use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use crate::config::{
@ -153,9 +152,6 @@ pub struct Session {
pub io: CompilerIO,
incr_comp_session: OneThread<RefCell<IncrCompSession>>,
/// Used for incremental compilation tests. Will only be populated if
/// `-Zquery-dep-graph` is specified.
pub cgu_reuse_tracker: CguReuseTracker,
/// Used by `-Z self-profile`.
pub prof: SelfProfilerRef,
@ -1431,12 +1427,6 @@ pub fn build_session(
});
let print_fuel = AtomicU64::new(0);
let cgu_reuse_tracker = if sopts.unstable_opts.query_dep_graph {
CguReuseTracker::new()
} else {
CguReuseTracker::new_disabled()
};
let prof = SelfProfilerRef::new(
self_profiler,
sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
@ -1461,7 +1451,6 @@ pub fn build_session(
sysroot,
io,
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
cgu_reuse_tracker,
prof,
perf_stats: PerfStats {
symbol_hash_time: Lock::new(Duration::from_secs(0)),

View File

@ -1,6 +1,6 @@
use super::{ObligationCauseCode, PredicateObligation};
use crate::infer::error_reporting::TypeErrCtxt;
use rustc_ast::{MetaItem, NestedMetaItem};
use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, ErrorGuaranteed};
@ -474,18 +474,40 @@ fn parse(
}
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
let mut is_diagnostic_namespace_variant = false;
let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| {
if tcx.features().diagnostic_namespace {
is_diagnostic_namespace_variant = true;
tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next()
} else {
None
}
}) else {
return Ok(None);
};
if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
return Self::parse_attribute(attr, false, tcx, item_def_id);
} else if tcx.features().diagnostic_namespace {
tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented])
.filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose())
.try_fold(None, |aggr: Option<Self>, directive| {
let directive = directive?;
if let Some(aggr) = aggr {
let mut subcommands = aggr.subcommands;
subcommands.extend(directive.subcommands);
Ok(Some(Self {
condition: aggr.condition.or(directive.condition),
subcommands,
message: aggr.message.or(directive.message),
label: aggr.label.or(directive.label),
note: aggr.note.or(directive.note),
parent_label: aggr.parent_label.or(directive.parent_label),
append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
}))
} else {
Ok(Some(directive))
}
})
} else {
Ok(None)
}
}
fn parse_attribute(
attr: &Attribute,
is_diagnostic_namespace_variant: bool,
tcx: TyCtxt<'tcx>,
item_def_id: DefId,
) -> Result<Option<Self>, ErrorGuaranteed> {
let result = if let Some(items) = attr.meta_item_list() {
Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
} else if let Some(value) = attr.value_str() {

View File

@ -686,7 +686,10 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
/// // they both get dropped!
/// ```
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
#[rustc_const_unstable(feature = "const_maybe_uninit_assume_init_read", issue = "63567")]
#[rustc_const_stable(
feature = "const_maybe_uninit_assume_init_read",
since = "CURRENT_RUSTC_VERSION"
)]
#[inline(always)]
#[track_caller]
pub const unsafe fn assume_init_read(&self) -> T {

View File

@ -319,7 +319,7 @@ pub const fn new(v: bool) -> AtomicBool {
/// # Examples
///
/// ```
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
/// #![feature(pointer_is_aligned)]
/// use std::sync::atomic::{self, AtomicBool};
/// use std::mem::align_of;
///
@ -346,13 +346,21 @@ pub const fn new(v: bool) -> AtomicBool {
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
/// be bigger than `align_of::<bool>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
/// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship
/// with atomic accesses via the returned value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
///
/// [valid]: crate::ptr#safety
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
#[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
// SAFETY: guaranteed by the caller
unsafe { &*ptr.cast() }
@ -1113,7 +1121,7 @@ pub const fn new(p: *mut T) -> AtomicPtr<T> {
/// # Examples
///
/// ```
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
/// #![feature(pointer_is_aligned)]
/// use std::sync::atomic::{self, AtomicPtr};
/// use std::mem::align_of;
///
@ -1140,13 +1148,23 @@ pub const fn new(p: *mut T) -> AtomicPtr<T> {
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this can be bigger than `align_of::<*mut T>()`).
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
/// can be bigger than `align_of::<*mut T>()`).
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
/// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship
/// with atomic accesses via the returned value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not overlap
/// with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
/// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
/// from the same thread.
/// * This method should not be used to create overlapping or mixed-size atomic accesses, as
/// these are not supported by the memory model.
///
/// [valid]: crate::ptr#safety
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
#[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
// SAFETY: guaranteed by the caller
unsafe { &*ptr.cast() }
@ -2083,7 +2101,7 @@ pub const fn new(v: $int_type) -> Self {
/// # Examples
///
/// ```
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
/// #![feature(pointer_is_aligned)]
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
/// use std::mem::align_of;
///
@ -2111,14 +2129,25 @@ pub const fn new(v: $int_type) -> Self {
///
/// # Safety
///
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
#[doc = concat!(" * `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
#[doc = concat!(" * `ptr` must be aligned to \
`align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this \
can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
/// * Non-atomic accesses to the value behind `ptr` must have a happens-before
/// relationship with atomic accesses via the returned value (or vice-versa).
/// * In other words, time periods where the value is accessed atomically may not
/// overlap with periods where the value is accessed non-atomically.
/// * This requirement is trivially satisfied if `ptr` is never used non-atomically
/// for the duration of lifetime `'a`. Most use cases should be able to follow
/// this guideline.
/// * This requirement is also trivially satisfied if all accesses (atomic or not) are
/// done from the same thread.
/// * This method should not be used to create overlapping or mixed-size atomic
/// accesses, as these are not supported by the memory model.
///
/// [valid]: crate::ptr#safety
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
#[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
// SAFETY: guaranteed by the caller
unsafe { &*ptr.cast() }

View File

@ -15,7 +15,6 @@
#![feature(const_hash)]
#![feature(const_heap)]
#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init_read)]
#![feature(const_nonnull_new)]
#![feature(const_pointer_byte_offsets)]
#![feature(const_pointer_is_aligned)]

View File

@ -36,10 +36,6 @@ object = { version = "0.32.0", default-features = false, optional = true, featur
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
rand_xorshift = "0.3.0"
[build-dependencies]
# Dependency of the `backtrace` crate's build script
cc = "1.0.67"
[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }

View File

@ -1,11 +1,5 @@
use std::env;
// backtrace-rs requires a feature check on Android targets, so
// we need to run its build.rs as well.
#[allow(unused_extern_crates)]
#[path = "../backtrace/build.rs"]
mod backtrace_build_rs;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
@ -65,6 +59,4 @@ fn main() {
}
println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
println!("cargo:rustc-cfg=backtrace_in_libstd");
backtrace_build_rs::main();
}

View File

@ -159,3 +159,36 @@ fn test_program_kind() {
);
}
}
// Test that Rust std handles wait status values (`ExitStatus`) the way that Unix does,
// at least for the values which represent a Unix exit status (`ExitCode`).
// Should work on every #[cfg(unix)] platform. However:
#[cfg(not(any(
// Fuchsia is not Unix and has totally broken std::os::unix.
// https://github.com/rust-lang/rust/issues/58590#issuecomment-836535609
target_os = "fuchsia",
)))]
#[test]
fn unix_exit_statuses() {
use crate::num::NonZeroI32;
use crate::os::unix::process::ExitStatusExt;
use crate::process::*;
for exit_code in 0..=0xff {
// FIXME impl From<ExitCode> for ExitStatus and then test that here too;
// the two ExitStatus values should be the same
let raw_wait_status = exit_code << 8;
let exit_status = ExitStatus::from_raw(raw_wait_status);
assert_eq!(exit_status.code(), Some(exit_code));
if let Ok(nz) = NonZeroI32::try_from(exit_code) {
assert!(!exit_status.success());
let es_error = exit_status.exit_ok().unwrap_err();
assert_eq!(es_error.code().unwrap(), i32::from(nz));
} else {
assert!(exit_status.success());
assert_eq!(exit_status.exit_ok(), Ok(()));
}
}
}

View File

@ -1074,3 +1074,8 @@ fn take_pidfd(&mut self) -> io::Result<PidFd> {
#[cfg(test)]
#[path = "process_unix/tests.rs"]
mod tests;
// See [`process_unsupported_wait_status::compare_with_linux`];
#[cfg(all(test, target_os = "linux"))]
#[path = "process_unsupported/wait_status.rs"]
mod process_unsupported_wait_status;

View File

@ -55,56 +55,8 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub struct ExitStatus(c_int);
impl ExitStatus {
#[cfg_attr(target_os = "horizon", allow(unused))]
pub fn success(&self) -> bool {
self.code() == Some(0)
}
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
Err(ExitStatusError(1.try_into().unwrap()))
}
pub fn code(&self) -> Option<i32> {
None
}
pub fn signal(&self) -> Option<i32> {
None
}
pub fn core_dumped(&self) -> bool {
false
}
pub fn stopped_signal(&self) -> Option<i32> {
None
}
pub fn continued(&self) -> bool {
false
}
pub fn into_raw(&self) -> c_int {
0
}
}
/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
impl From<c_int> for ExitStatus {
fn from(a: c_int) -> ExitStatus {
ExitStatus(a as i32)
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "exit code: {}", self.0)
}
}
mod wait_status;
pub use wait_status::ExitStatus;
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatusError(NonZero_c_int);

View File

@ -0,0 +1,68 @@
//! Emulated wait status for non-Unix #[cfg(unix) platforms
//!
//! Separate module to facilitate testing against a real Unix implementation.
use crate::ffi::c_int;
use crate::fmt;
/// Emulated wait status for use by `process_unsupported.rs`
///
/// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]`
/// but do not actually support subprocesses at all.
///
/// These platforms aren't Unix, but are simply pretending to be for porting convenience.
/// So, we provide a faithful pretence here.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
pub struct ExitStatus {
wait_status: c_int,
}
/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it
impl From<c_int> for ExitStatus {
fn from(wait_status: c_int) -> ExitStatus {
ExitStatus { wait_status }
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "emulated wait status: {}", self.wait_status)
}
}
impl ExitStatus {
pub fn code(&self) -> Option<i32> {
// Linux and FreeBSD both agree that values linux 0x80
// count as "WIFEXITED" even though this is quite mad.
// Likewise the macros disregard all the high bits, so are happy to declare
// out-of-range values to be WIFEXITED, WIFSTOPPED, etc.
let w = self.wait_status;
if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None }
}
pub fn signal(&self) -> Option<i32> {
let signal = self.wait_status & 0x007f;
if signal > 0 && signal < 0x7f { Some(signal) } else { None }
}
pub fn core_dumped(&self) -> bool {
self.signal().is_some() && (self.wait_status & 0x80) != 0
}
pub fn stopped_signal(&self) -> Option<i32> {
let w = self.wait_status;
if (w & 0xff) == 0x7f { Some((w & 0xff00) >> 8) } else { None }
}
pub fn continued(&self) -> bool {
self.wait_status == 0xffff
}
pub fn into_raw(&self) -> c_int {
self.wait_status
}
}
#[cfg(test)]
#[path = "wait_status/tests.rs"] // needed because of strange layout of process_unsupported
mod tests;

View File

@ -0,0 +1,36 @@
// Note that tests in this file are run on Linux as well as on platforms using process_unsupported
// Test that our emulation exactly matches Linux
//
// This test runs *on Linux* but it tests
// the implementation used on non-Unix `#[cfg(unix)]` platforms.
//
// I.e. we're using Linux as a proxy for "trad unix".
#[cfg(target_os = "linux")]
#[test]
fn compare_with_linux() {
use super::ExitStatus as Emulated;
use crate::os::unix::process::ExitStatusExt as _;
use crate::process::ExitStatus as Real;
// Check that we handle out-of-range values similarly, too.
for wstatus in -0xf_ffff..0xf_ffff {
let emulated = Emulated::from(wstatus);
let real = Real::from_raw(wstatus);
macro_rules! compare { { $method:ident } => {
assert_eq!(
emulated.$method(),
real.$method(),
"{wstatus:#x}.{}()",
stringify!($method),
);
} }
compare!(code);
compare!(signal);
compare!(core_dumped);
compare!(stopped_signal);
compare!(continued);
compare!(into_raw);
}
}

View File

@ -286,10 +286,6 @@ target | std | host | notes
`mipsel-unknown-linux-musl` | ✓ | | MIPS (little endian) Linux with musl libc
`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP)
[`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * | | MIPS (LE) Sony PlayStation 1 (PSX)
`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
`mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc
`mipsel-unknown-none` | * | | Bare MIPS (LE) softfloat
[`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? | | 32-bit MIPS Release 6 Big Endian

View File

@ -0,0 +1,19 @@
# `no-jump-tables`
The tracking issue for this feature is [#116592](https://github.com/rust-lang/rust/issues/116592)
---
This option enables the `-fno-jump-tables` flag for LLVM, which makes the
codegen backend avoid generating jump tables when lowering switches.
This option adds the LLVM `no-jump-tables=true` attribute to every function.
The option can be used to help provide protection against
jump-oriented-programming (JOP) attacks, such as with the linux kernel's [IBT].
```sh
RUSTFLAGS="-Zno-jump-tables" cargo +nightly build -Z build-std
```
[IBT]: https://www.phoronix.com/news/Linux-IBT-By-Default-Tip

View File

@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
for arm in arms {
if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
let path_str = rustc_hir_pretty::qpath_to_string(path);
if path_str == "Err" {
let mut matching_wild = inner.iter().any(is_wild);
let mut ident_bind_name = kw::Underscore;

View File

@ -49,7 +49,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
cx,
arguments.iter().collect(),
cx.typeck_results().expr_ty(fn_expr),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
&rustc_hir_pretty::qpath_to_string(path),
"function",
);
}

View File

@ -1 +1 @@
3d575a2f2ef8a6eb99064bb31c16feb8d508f1ee
2a7c2df506fcd5611967a203cc994da5f21abd1e

View File

@ -12,7 +12,6 @@
use rand::SeedableRng;
use rustc_ast::ast::Mutability;
use rustc_const_eval::const_eval::CheckAlignment;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[allow(unused)]
use rustc_data_structures::static_assert_size;
@ -885,12 +884,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
const PANIC_ON_ALLOC_FAIL: bool = false;
#[inline(always)]
fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment {
if ecx.machine.check_alignment == AlignmentCheck::None {
CheckAlignment::No
} else {
CheckAlignment::Error
}
fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.check_alignment != AlignmentCheck::None
}
#[inline(always)]
@ -898,15 +893,6 @@ fn use_addr_for_alignment_check(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.check_alignment == AlignmentCheck::Int
}
fn alignment_check_failed(
_ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
_check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
throw_ub!(AlignmentCheckFailed { has, required })
}
#[inline(always)]
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool {
ecx.machine.validate

View File

@ -0,0 +1,20 @@
// assembly-output: emit-asm
// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
// only-x86_64
// ignore-sgx
// ignore-macos (manipulates rsp too)
// Depending on various codegen choices, this might end up copying
// a `<2 x i8>`, an `i16`, or two `i8`s.
// Regardless of those choices, make sure the instructions use (2-byte) words.
// CHECK-LABEL: array_copy_2_elements:
#[no_mangle]
pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) {
// CHECK-NOT: byte
// CHECK-NOT: mov
// CHECK: mov{{.+}}, word ptr
// CHECK-NEXT: mov word ptr
// CHECK-NEXT: ret
*p = *a;
}

View File

@ -32,3 +32,25 @@
// CHECK: store <4 x i8> %[[TEMP2]], ptr %p, align 1
*p = *a;
}
// CHECK-LABEL: @array_copy_1_element
#[no_mangle]
pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) {
// CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1
// CHECK: %[[TEMP1:.+]] = load i8, ptr %a, align 1
// CHECK: store i8 %[[TEMP1]], ptr %[[LOCAL]], align 1
// CHECK: %[[TEMP2:.+]] = load i8, ptr %[[LOCAL]], align 1
// CHECK: store i8 %[[TEMP2]], ptr %p, align 1
*p = *a;
}
// CHECK-LABEL: @array_copy_2_elements
#[no_mangle]
pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) {
// CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1
// CHECK: %[[TEMP1:.+]] = load <2 x i8>, ptr %a, align 1
// CHECK: store <2 x i8> %[[TEMP1]], ptr %[[LOCAL]], align 1
// CHECK: %[[TEMP2:.+]] = load <2 x i8>, ptr %[[LOCAL]], align 1
// CHECK: store <2 x i8> %[[TEMP2]], ptr %p, align 1
*p = *a;
}

View File

@ -0,0 +1,33 @@
// compile-flags: -O
#![crate_type = "lib"]
// CHECK-LABEL: @array_copy_1_element
#[no_mangle]
pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) {
// CHECK-NOT: alloca
// CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1
// CHECK: store i8 %[[TEMP]], ptr %p, align 1
// CHECK: ret
*p = *a;
}
// CHECK-LABEL: @array_copy_2_elements
#[no_mangle]
pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) {
// CHECK-NOT: alloca
// CHECK: %[[TEMP:.+]] = load <2 x i8>, ptr %a, align 1
// CHECK: store <2 x i8> %[[TEMP]], ptr %p, align 1
// CHECK: ret
*p = *a;
}
// CHECK-LABEL: @array_copy_4_elements
#[no_mangle]
pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) {
// CHECK-NOT: alloca
// CHECK: %[[TEMP:.+]] = load <4 x i8>, ptr %a, align 1
// CHECK: store <4 x i8> %[[TEMP]], ptr %p, align 1
// CHECK: ret
*p = *a;
}

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `uniz`
--> $DIR/check-cfg.rs:5:7
|
LL | #[cfg(uniz)]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `invalid`
--> $DIR/check-cfg-test.rs:9:7
|
LL | #[cfg(feature = "invalid")]

View File

@ -1,9 +1,10 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `FALSE`
--> $DIR/allow-same-level.rs:7:7
|
LL | #[cfg(FALSE)]
| ^^^^^
|
= help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View File

@ -1,9 +1,10 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `target_architecture`
--> $DIR/compact-names.rs:11:28
|
LL | #[cfg(target(os = "linux", architecture = "arm"))]
| ^^^^^^^^^^^^^^^^^^^^
|
= help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `X`
--> $DIR/compact-values.rs:11:28
|
LL | #[cfg(target(os = "linux", arch = "X"))]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `featur`
--> $DIR/diagnotics.rs:4:7
|
LL | #[cfg(featur)]
@ -7,19 +7,18 @@ LL | #[cfg(featur)]
= help: expected values for `feature` are: `foo`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `featur`
--> $DIR/diagnotics.rs:8:7
|
LL | #[cfg(featur = "foo")]
| ^^^^^^^^^^^^^^
|
= help: expected values for `feature` are: `foo`
help: there is a config with a similar name and value
|
LL | #[cfg(feature = "foo")]
| ~~~~~~~
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `featur`
--> $DIR/diagnotics.rs:12:7
|
LL | #[cfg(featur = "fo")]
@ -31,13 +30,13 @@ help: there is a config with a similar name and different values
LL | #[cfg(feature = "foo")]
| ~~~~~~~~~~~~~~~
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `no_value`
--> $DIR/diagnotics.rs:19:7
|
LL | #[cfg(no_value)]
| ^^^^^^^^ help: there is a config with a similar name: `no_values`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `no_value`
--> $DIR/diagnotics.rs:23:7
|
LL | #[cfg(no_value = "foo")]
@ -48,7 +47,7 @@ help: there is a config with a similar name and no value
LL | #[cfg(no_values)]
| ~~~~~~~~~
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `bar`
--> $DIR/diagnotics.rs:27:7
|
LL | #[cfg(no_values = "bar")]

View File

@ -1,9 +1,10 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `unknown_key`
--> $DIR/empty-names.rs:6:7
|
LL | #[cfg(unknown_key = "value")]
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `value`
--> $DIR/empty-values.rs:6:7
|
LL | #[cfg(test = "value")]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `widnows`
--> $DIR/invalid-cfg-name.rs:7:7
|
LL | #[cfg(widnows)]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `sedre`
--> $DIR/invalid-cfg-value.rs:7:7
|
LL | #[cfg(feature = "sedre")]
@ -9,7 +9,7 @@ LL | #[cfg(feature = "sedre")]
= note: expected values for `feature` are: `full`, `serde`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `rand`
--> $DIR/invalid-cfg-value.rs:14:7
|
LL | #[cfg(feature = "rand")]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `widnows`
--> $DIR/mix.rs:11:7
|
LL | #[cfg(widnows)]
@ -6,7 +6,7 @@ LL | #[cfg(widnows)]
|
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: (none)
--> $DIR/mix.rs:15:7
|
LL | #[cfg(feature)]
@ -14,7 +14,7 @@ LL | #[cfg(feature)]
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `bar`
--> $DIR/mix.rs:22:7
|
LL | #[cfg(feature = "bar")]
@ -22,7 +22,7 @@ LL | #[cfg(feature = "bar")]
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:26:7
|
LL | #[cfg(feature = "zebra")]
@ -30,11 +30,13 @@ LL | #[cfg(feature = "zebra")]
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `uu`
--> $DIR/mix.rs:30:12
|
LL | #[cfg_attr(uu, test)]
| ^^
|
= help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
warning: unexpected condition value `bar` for condition name `feature`
|
@ -44,13 +46,13 @@ warning: unexpected `unknown_name` as condition name
|
= help: was set with `--cfg` but isn't in the `--check-cfg` expected names
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `widnows`
--> $DIR/mix.rs:39:10
|
LL | cfg!(widnows);
| ^^^^^^^ help: there is a config with a similar name: `windows`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `bar`
--> $DIR/mix.rs:42:10
|
LL | cfg!(feature = "bar");
@ -58,7 +60,7 @@ LL | cfg!(feature = "bar");
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:44:10
|
LL | cfg!(feature = "zebra");
@ -66,25 +68,25 @@ LL | cfg!(feature = "zebra");
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:46:10
|
LL | cfg!(xxx = "foo");
| ^^^^^^^^^^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:48:10
|
LL | cfg!(xxx);
| ^^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:50:14
|
LL | cfg!(any(xxx, windows));
| ^^^
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `bad`
--> $DIR/mix.rs:52:14
|
LL | cfg!(any(feature = "bad", windows));
@ -92,43 +94,43 @@ LL | cfg!(any(feature = "bad", windows));
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:54:23
|
LL | cfg!(any(windows, xxx));
| ^^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:56:20
|
LL | cfg!(all(unix, xxx));
| ^^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `aa`
--> $DIR/mix.rs:58:14
|
LL | cfg!(all(aa, bb));
| ^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `bb`
--> $DIR/mix.rs:58:18
|
LL | cfg!(all(aa, bb));
| ^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `aa`
--> $DIR/mix.rs:61:14
|
LL | cfg!(any(aa, bb));
| ^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `bb`
--> $DIR/mix.rs:61:18
|
LL | cfg!(any(aa, bb));
| ^^
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:64:20
|
LL | cfg!(any(unix, feature = "zebra"));
@ -136,13 +138,13 @@ LL | cfg!(any(unix, feature = "zebra"));
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:66:14
|
LL | cfg!(any(xxx, feature = "zebra"));
| ^^^
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:66:19
|
LL | cfg!(any(xxx, feature = "zebra"));
@ -150,19 +152,19 @@ LL | cfg!(any(xxx, feature = "zebra"));
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:69:14
|
LL | cfg!(any(xxx, unix, xxx));
| ^^^
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `xxx`
--> $DIR/mix.rs:69:25
|
LL | cfg!(any(xxx, unix, xxx));
| ^^^
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:72:14
|
LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
@ -170,7 +172,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:72:33
|
LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
@ -178,7 +180,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
|
= note: expected values for `feature` are: `foo`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `zebra`
--> $DIR/mix.rs:72:52
|
LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `foo`
--> $DIR/no-values.rs:6:7
|
LL | #[cfg(feature = "foo")]
@ -9,7 +9,7 @@ LL | #[cfg(feature = "foo")]
= note: no expected value for `feature`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `foo`
--> $DIR/no-values.rs:10:7
|
LL | #[cfg(test = "foo")]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: (none)
--> $DIR/order-independant.rs:8:7
|
LL | #[cfg(a)]
@ -7,7 +7,7 @@ LL | #[cfg(a)]
= note: expected values for `a` are: `b`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `unk`
--> $DIR/order-independant.rs:12:7
|
LL | #[cfg(a = "unk")]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: (none)
--> $DIR/order-independant.rs:8:7
|
LL | #[cfg(a)]
@ -7,7 +7,7 @@ LL | #[cfg(a)]
= note: expected values for `a` are: `b`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `unk`
--> $DIR/order-independant.rs:12:7
|
LL | #[cfg(a = "unk")]

View File

@ -1,9 +1,10 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `crossbeam_loom`
--> $DIR/stmt-no-ice.rs:7:11
|
LL | #[cfg(crossbeam_loom)]
| ^^^^^^^^^^^^^^
|
= help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: 1 warning emitted

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `linuz`
--> $DIR/values-target-json.rs:13:7
|
LL | #[cfg(target_os = "linuz")]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `target_oz`
--> $DIR/well-known-names.rs:6:7
|
LL | #[cfg(target_oz = "linux")]
@ -8,7 +8,7 @@ LL | #[cfg(target_oz = "linux")]
|
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `features`
--> $DIR/well-known-names.rs:13:7
|
LL | #[cfg(features = "foo")]
@ -16,7 +16,7 @@ LL | #[cfg(features = "foo")]
| |
| help: there is a config with a similar name: `feature`
warning: unexpected `cfg` condition name
warning: unexpected `cfg` condition name: `uniw`
--> $DIR/well-known-names.rs:20:7
|
LL | #[cfg(uniw)]

View File

@ -1,4 +1,4 @@
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `linuz`
--> $DIR/well-known-values.rs:7:7
|
LL | #[cfg(target_os = "linuz")]
@ -9,7 +9,7 @@ LL | #[cfg(target_os = "linuz")]
= note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `0`
--> $DIR/well-known-values.rs:14:7
|
LL | #[cfg(target_has_atomic = "0")]
@ -19,7 +19,7 @@ LL | #[cfg(target_has_atomic = "0")]
|
= note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `aa`
--> $DIR/well-known-values.rs:21:7
|
LL | #[cfg(unix = "aa")]
@ -29,7 +29,7 @@ LL | #[cfg(unix = "aa")]
|
= note: no expected value for `unix`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `miri`
--> $DIR/well-known-values.rs:28:7
|
LL | #[cfg(miri = "miri")]
@ -39,7 +39,7 @@ LL | #[cfg(miri = "miri")]
|
= note: no expected value for `miri`
warning: unexpected `cfg` condition value
warning: unexpected `cfg` condition value: `linux`
--> $DIR/well-known-values.rs:35:7
|
LL | #[cfg(doc = "linux")]

View File

@ -0,0 +1,36 @@
// normalize-stderr-test "alloc\d+" -> "allocN"
#![feature(const_pointer_byte_offsets)]
#![feature(pointer_byte_offsets)]
#![feature(const_mut_refs)]
const MISALIGNED_LOAD: () = unsafe {
let mem = [0u32; 8];
let ptr = mem.as_ptr().byte_add(1);
let _val = *ptr; //~ERROR: evaluation of constant value failed
//~^NOTE: accessing memory with alignment 1, but alignment 4 is required
};
const MISALIGNED_STORE: () = unsafe {
let mut mem = [0u32; 8];
let ptr = mem.as_mut_ptr().byte_add(1);
*ptr = 0; //~ERROR: evaluation of constant value failed
//~^NOTE: accessing memory with alignment 1, but alignment 4 is required
};
const MISALIGNED_COPY: () = unsafe {
let x = &[0_u8; 4];
let y = x.as_ptr().cast::<u32>();
let mut z = 123;
y.copy_to_nonoverlapping(&mut z, 1);
//~^NOTE
// The actual error points into the implementation of `copy_to_nonoverlapping`.
};
const OOB: () = unsafe {
let mem = [0u32; 1];
let ptr = mem.as_ptr().cast::<u64>();
let _val = *ptr; //~ERROR: evaluation of constant value failed
//~^NOTE: size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
};
fn main() {}

View File

@ -0,0 +1,36 @@
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:9:16
|
LL | let _val = *ptr;
| ^^^^ accessing memory with alignment 1, but alignment 4 is required
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:16:5
|
LL | *ptr = 0;
| ^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
= note: accessing memory with alignment 1, but alignment 4 is required
|
note: inside `copy_nonoverlapping::<u32>`
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
note: inside `ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `MISALIGNED_COPY`
--> $DIR/raw-pointer-ub.rs:24:5
|
LL | y.copy_to_nonoverlapping(&mut z, 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0080]: evaluation of constant value failed
--> $DIR/raw-pointer-ub.rs:32:16
|
LL | let _val = *ptr;
| ^^^^ dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0080`.

View File

@ -0,0 +1,22 @@
#![feature(diagnostic_namespace)]
#[diagnostic::on_unimplemented(
//~^WARN malformed `on_unimplemented` attribute
//~|WARN malformed `on_unimplemented` attribute
if(Self = ()),
message = "not used yet",
label = "not used yet",
note = "not used yet"
)]
#[diagnostic::on_unimplemented(message = "fallback!!")]
#[diagnostic::on_unimplemented(label = "fallback label")]
#[diagnostic::on_unimplemented(note = "fallback note")]
#[diagnostic::on_unimplemented(message = "fallback2!!")]
trait Foo {}
fn takes_foo(_: impl Foo) {}
fn main() {
takes_foo(());
//~^ERROR fallback!!
}

View File

@ -0,0 +1,52 @@
warning: malformed `on_unimplemented` attribute
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
|
LL | / #[diagnostic::on_unimplemented(
LL | |
LL | |
LL | | if(Self = ()),
... |
LL | | note = "not used yet"
LL | | )]
| |__^
|
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
warning: malformed `on_unimplemented` attribute
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1
|
LL | / #[diagnostic::on_unimplemented(
LL | |
LL | |
LL | | if(Self = ()),
... |
LL | | note = "not used yet"
LL | | )]
| |__^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: fallback!!
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15
|
LL | takes_foo(());
| --------- ^^ fallback label
| |
| required by a bound introduced by this call
|
= help: the trait `Foo` is not implemented for `()`
= note: fallback note
help: this trait has no implementations, consider adding one
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1
|
LL | trait Foo {}
| ^^^^^^^^^
note: required by a bound in `takes_foo`
--> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22
|
LL | fn takes_foo(_: impl Foo) {}
| ^^^ required by this bound in `takes_foo`
error: aborting due to previous error; 2 warnings emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,10 @@
// run-rustfix
fn main() {
let _ = vec![1, 2, 3].into_iter().map(|x| {
let y = x; //~ ERROR expected expression, found `let` statement
y
});
let _: () = foo(); //~ ERROR mismatched types
}
fn foo() {}

View File

@ -0,0 +1,10 @@
// run-rustfix
fn main() {
let _ = vec![1, 2, 3].into_iter().map(|x|
let y = x; //~ ERROR expected expression, found `let` statement
y
);
let _: () = foo; //~ ERROR mismatched types
}
fn foo() {}

View File

@ -0,0 +1,38 @@
error: expected expression, found `let` statement
--> $DIR/missing_block_in_fn_call.rs:4:9
|
LL | let _ = vec![1, 2, 3].into_iter().map(|x|
| --- while parsing the body of this closure
LL | let y = x;
| ^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
help: you might have meant to open the body of the closure
|
LL ~ let _ = vec![1, 2, 3].into_iter().map(|x| {
LL | let y = x;
LL | y
LL ~ });
|
error[E0308]: mismatched types
--> $DIR/missing_block_in_fn_call.rs:7:17
|
LL | let _: () = foo;
| -- ^^^ expected `()`, found fn item
| |
| expected due to this
...
LL | fn foo() {}
| -------- function `foo` defined here
|
= note: expected unit type `()`
found fn item `fn() {foo}`
help: use parentheses to call this function
|
LL | let _: () = foo();
| ++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,6 @@
fn main() {
let x = |x|
let y = x; //~ ERROR expected expression, found `let` statement
let _ = () + ();
y
}

View File

@ -0,0 +1,16 @@
error: expected expression, found `let` statement
--> $DIR/missing_block_in_let_binding.rs:3:9
|
LL | let x = |x|
| --- while parsing the body of this closure
LL | let y = x;
| ^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
help: you might have meant to open the body of the closure
|
LL | let x = |x| {
| +
error: aborting due to previous error

View File

@ -0,0 +1,9 @@
// run-rustfix
fn main() {
let _ = vec![1, 2, 3].into_iter().map(|x| {
let y = x; //~ ERROR expected expression, found `let` statement
y
});
let _: () = foo(); //~ ERROR mismatched types
}
fn foo() {}

View File

@ -0,0 +1,9 @@
// run-rustfix
fn main() {
let _ = vec![1, 2, 3].into_iter().map({|x|
let y = x; //~ ERROR expected expression, found `let` statement
y
});
let _: () = foo; //~ ERROR mismatched types
}
fn foo() {}

View File

@ -0,0 +1,36 @@
error: expected expression, found `let` statement
--> $DIR/ruby_style_closure_parse_error.rs:4:9
|
LL | let _ = vec![1, 2, 3].into_iter().map({|x|
| --- while parsing the body of this closure
LL | let y = x;
| ^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
help: you might have meant to open the body of the closure, instead of enclosing the closure in a block
|
LL - let _ = vec![1, 2, 3].into_iter().map({|x|
LL + let _ = vec![1, 2, 3].into_iter().map(|x| {
|
error[E0308]: mismatched types
--> $DIR/ruby_style_closure_parse_error.rs:7:17
|
LL | let _: () = foo;
| -- ^^^ expected `()`, found fn item
| |
| expected due to this
LL | }
LL | fn foo() {}
| -------- function `foo` defined here
|
= note: expected unit type `()`
found fn item `fn() {foo}`
help: use parentheses to call this function
|
LL | let _: () = foo();
| ++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -2,9 +2,15 @@ error: expected identifier, found `:`
--> $DIR/or-patterns-syntactic-fail.rs:11:19
|
LL | let _ = |A | B: E| ();
| ^ expected identifier
| ---- ^ expected identifier
| |
| while parsing the body of this closure
|
= note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: you might have meant to open the body of the closure
|
LL | let _ = |A | { B: E| ();
| +
error: top-level or-patterns are not allowed in function parameters
--> $DIR/or-patterns-syntactic-fail.rs:18:13

View File

@ -1,5 +1,6 @@
pub fn test() {
foo(|_|) //~ ERROR expected expression, found `)`
//~^ ERROR cannot find function `foo` in this scope
}
fn main() { }

View File

@ -2,7 +2,21 @@ error: expected expression, found `)`
--> $DIR/issue-32505.rs:2:12
|
LL | foo(|_|)
| ^ expected expression
| ---^ expected expression
| |
| while parsing the body of this closure
|
help: you might have meant to open the body of the closure
|
LL | foo(|_| {})
| ++
error: aborting due to previous error
error[E0425]: cannot find function `foo` in this scope
--> $DIR/issue-32505.rs:2:5
|
LL | foo(|_|)
| ^^^ not found in this scope
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.

View File

@ -0,0 +1,22 @@
#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![deny(unreachable_patterns)]
fn main() {}
fn foo(nevers: &[!]) {
match nevers {
&[] => (),
};
match nevers {
&[] => (),
&[_] => (), //~ ERROR unreachable pattern
&[_, _, ..] => (), //~ ERROR unreachable pattern
};
match nevers {
//~^ ERROR non-exhaustive patterns: `&[]` not covered
&[_] => (), //~ ERROR unreachable pattern
};
}

View File

@ -0,0 +1,39 @@
error: unreachable pattern
--> $DIR/slice_of_empty.rs:14:9
|
LL | &[_] => (),
| ^^^^
|
note: the lint level is defined here
--> $DIR/slice_of_empty.rs:3:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/slice_of_empty.rs:15:9
|
LL | &[_, _, ..] => (),
| ^^^^^^^^^^^
error: unreachable pattern
--> $DIR/slice_of_empty.rs:20:9
|
LL | &[_] => (),
| ^^^^
error[E0004]: non-exhaustive patterns: `&[]` not covered
--> $DIR/slice_of_empty.rs:18:11
|
LL | match nevers {
| ^^^^^^ pattern `&[]` not covered
|
= note: the matched value is of type `&[!]`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL | &[_] => (), &[] => todo!(),
| ++++++++++++++++
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0004`.

Some files were not shown because too many files have changed in this diff Show More