Merge from rustc
This commit is contained in:
commit
06db6bba3b
282 changed files with 2792 additions and 1515 deletions
|
|
@ -3537,6 +3537,7 @@ dependencies = [
|
|||
"ar_archive_writer",
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"cc",
|
||||
"either",
|
||||
"itertools",
|
||||
|
|
|
|||
|
|
@ -573,6 +573,7 @@ Libraries
|
|||
- [Replace sort implementations with stable `driftsort` and unstable `ipnsort`.](https://github.com/rust-lang/rust/pull/124032/) All `slice::sort*` and `slice::select_nth*` methods are expected to see significant performance improvements. See the [research project](https://github.com/Voultapher/sort-research-rs) for more details.
|
||||
- [Document behavior of `create_dir_all` with respect to empty paths.](https://github.com/rust-lang/rust/pull/125112/)
|
||||
- [Fix interleaved output in the default panic hook when multiple threads panic simultaneously.](https://github.com/rust-lang/rust/pull/127397/)
|
||||
- Fix `Command`'s batch files argument escaping not working when file name has trailing whitespace or periods (CVE-2024-43402).
|
||||
|
||||
<a id="1.81.0-Stabilized-APIs"></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,25 @@ pub enum InstructionSetAttr {
|
|||
ArmT32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic, Default)]
|
||||
pub enum OptimizeAttr {
|
||||
None,
|
||||
/// No `#[optimize(..)]` attribute
|
||||
#[default]
|
||||
Default,
|
||||
/// `#[optimize(none)]`
|
||||
DoNotOptimize,
|
||||
/// `#[optimize(speed)]`
|
||||
Speed,
|
||||
/// `#[optimize(size)]`
|
||||
Size,
|
||||
}
|
||||
|
||||
impl OptimizeAttr {
|
||||
pub fn do_not_optimize(&self) -> bool {
|
||||
matches!(self, Self::DoNotOptimize)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub enum DiagnosticAttribute {
|
||||
// tidy-alphabetical-start
|
||||
|
|
|
|||
|
|
@ -92,6 +92,9 @@ borrowck_lifetime_constraints_error =
|
|||
borrowck_limitations_implies_static =
|
||||
due to current limitations in the borrow checker, this implies a `'static` lifetime
|
||||
|
||||
borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console
|
||||
borrowck_long_type_full_path = the full type name has been written to '{$path}'
|
||||
|
||||
borrowck_move_closure_suggestion =
|
||||
consider adding 'move' keyword before the nested closure
|
||||
|
||||
|
|
|
|||
|
|
@ -289,6 +289,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
None => "value".to_owned(),
|
||||
};
|
||||
if needs_note {
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(ty, &mut path);
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
|
|
@ -304,6 +306,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
place: ¬e_msg,
|
||||
});
|
||||
};
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let UseSpans::FnSelfUse {
|
||||
|
|
|
|||
|
|
@ -596,12 +596,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, place_ty, expr, None);
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
|
|
@ -628,12 +635,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, place_ty, expr, Some(use_spans));
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
ty,
|
||||
place: &place_desc,
|
||||
span: use_span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
|
|
@ -831,12 +845,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, bind_to.ty, expr, None);
|
||||
}
|
||||
|
||||
let mut path = None;
|
||||
let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path);
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
});
|
||||
if let Some(path) = path {
|
||||
err.subdiagnostic(crate::session_diagnostics::LongTypePath {
|
||||
path: path.display().to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,17 +459,24 @@ pub(crate) enum OnClosureNote<'a> {
|
|||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||
#[note(borrowck_long_type_full_path)]
|
||||
#[note(borrowck_long_type_consider_verbose)]
|
||||
pub(crate) struct LongTypePath {
|
||||
pub(crate) path: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum TypeNoCopy<'a> {
|
||||
#[label(borrowck_ty_no_impl_copy)]
|
||||
Label {
|
||||
is_partial_move: bool,
|
||||
ty: Ty<'tcx>,
|
||||
ty: String,
|
||||
place: &'a str,
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_ty_no_impl_copy)]
|
||||
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
|
||||
Note { is_partial_move: bool, ty: String, place: &'a str },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -333,9 +333,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
let mut to_add = SmallVec::<[_; 16]>::new();
|
||||
|
||||
match codegen_fn_attrs.optimize {
|
||||
OptimizeAttr::None => {
|
||||
OptimizeAttr::Default => {
|
||||
to_add.extend(default_optimisation_attrs(cx));
|
||||
}
|
||||
OptimizeAttr::DoNotOptimize => {
|
||||
to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx));
|
||||
}
|
||||
OptimizeAttr::Size => {
|
||||
to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx));
|
||||
to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
|
||||
|
|
@ -343,12 +346,12 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
OptimizeAttr::Speed => {}
|
||||
}
|
||||
|
||||
let inline =
|
||||
if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
|
||||
InlineAttr::Hint
|
||||
} else {
|
||||
codegen_fn_attrs.inline
|
||||
};
|
||||
// `optnone` requires `noinline`
|
||||
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
|
||||
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
|
||||
(InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
|
||||
(inline, _) => inline,
|
||||
};
|
||||
to_add.extend(inline_attr(cx, inline));
|
||||
|
||||
// The `uwtable` attribute according to LLVM is:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
ar_archive_writer = "0.4.2"
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "2.4.1"
|
||||
bstr = "1.11.3"
|
||||
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
|
||||
# `cc` in `rustc_llvm` if you update the `cc` here.
|
||||
cc = "=1.2.7"
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
|
|||
codegen_ssa_linker_not_found = linker `{$linker_path}` not found
|
||||
.note = {$error}
|
||||
|
||||
codegen_ssa_linker_output = {$inner}
|
||||
|
||||
codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
|
||||
|
||||
codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ pub(crate) struct Command {
|
|||
args: Vec<OsString>,
|
||||
env: Vec<(OsString, OsString)>,
|
||||
env_remove: Vec<OsString>,
|
||||
env_clear: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -36,7 +37,13 @@ impl Command {
|
|||
}
|
||||
|
||||
fn _new(program: Program) -> Command {
|
||||
Command { program, args: Vec::new(), env: Vec::new(), env_remove: Vec::new() }
|
||||
Command {
|
||||
program,
|
||||
args: Vec::new(),
|
||||
env: Vec::new(),
|
||||
env_remove: Vec::new(),
|
||||
env_clear: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
|
||||
|
|
@ -79,6 +86,11 @@ impl Command {
|
|||
self
|
||||
}
|
||||
|
||||
pub(crate) fn env_clear(&mut self) -> &mut Command {
|
||||
self.env_clear = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn _env_remove(&mut self, key: &OsStr) {
|
||||
self.env_remove.push(key.to_owned());
|
||||
}
|
||||
|
|
@ -106,6 +118,9 @@ impl Command {
|
|||
for k in &self.env_remove {
|
||||
ret.env_remove(k);
|
||||
}
|
||||
if self.env_clear {
|
||||
ret.env_clear();
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ use rustc_ast::CRATE_NODE_ID;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
|
||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::lint_level;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
|
|
@ -29,6 +31,7 @@ use rustc_session::config::{
|
|||
OutputType, PrintKind, SplitDwarfKind, Strip,
|
||||
};
|
||||
use rustc_session::cstore::DllImport;
|
||||
use rustc_session::lint::builtin::LINKER_MESSAGES;
|
||||
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
|
|
@ -749,6 +752,14 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(codegen_ssa_linker_output)]
|
||||
/// Translating this is kind of useless. We don't pass translation flags to the linker, so we'd just
|
||||
/// end up with inconsistent languages within the same diagnostic.
|
||||
struct LinkerOutput {
|
||||
inner: String,
|
||||
}
|
||||
|
||||
/// Create a dynamic library or executable.
|
||||
///
|
||||
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
|
||||
|
|
@ -981,6 +992,11 @@ fn link_natively(
|
|||
|
||||
match prog {
|
||||
Ok(prog) => {
|
||||
let is_msvc_link_exe = sess.target.is_like_msvc
|
||||
&& flavor == LinkerFlavor::Msvc(Lld::No)
|
||||
// Match exactly "link.exe"
|
||||
&& linker_path.to_str() == Some("link.exe");
|
||||
|
||||
if !prog.status.success() {
|
||||
let mut output = prog.stderr.clone();
|
||||
output.extend_from_slice(&prog.stdout);
|
||||
|
|
@ -991,22 +1007,16 @@ fn link_natively(
|
|||
command: cmd,
|
||||
escaped_output,
|
||||
verbose: sess.opts.verbose,
|
||||
sysroot_dir: sess.sysroot.clone(),
|
||||
};
|
||||
sess.dcx().emit_err(err);
|
||||
// If MSVC's `link.exe` was expected but the return code
|
||||
// is not a Microsoft LNK error then suggest a way to fix or
|
||||
// install the Visual Studio build tools.
|
||||
if let Some(code) = prog.status.code() {
|
||||
if sess.target.is_like_msvc
|
||||
&& flavor == LinkerFlavor::Msvc(Lld::No)
|
||||
// Respect the command line override
|
||||
&& sess.opts.cg.linker.is_none()
|
||||
// Match exactly "link.exe"
|
||||
&& linker_path.to_str() == Some("link.exe")
|
||||
// All Microsoft `link.exe` linking error codes are
|
||||
// four digit numbers in the range 1000 to 9999 inclusive
|
||||
&& (code < 1000 || code > 9999)
|
||||
{
|
||||
// All Microsoft `link.exe` linking ror codes are
|
||||
// four digit numbers in the range 1000 to 9999 inclusive
|
||||
if is_msvc_link_exe && (code < 1000 || code > 9999) {
|
||||
let is_vs_installed = windows_registry::find_vs_version().is_ok();
|
||||
let has_linker =
|
||||
windows_registry::find_tool(&sess.target.arch, "link.exe").is_some();
|
||||
|
|
@ -1028,8 +1038,49 @@ fn link_natively(
|
|||
|
||||
sess.dcx().abort_if_errors();
|
||||
}
|
||||
info!("linker stderr:\n{}", escape_string(&prog.stderr));
|
||||
info!("linker stdout:\n{}", escape_string(&prog.stdout));
|
||||
|
||||
let stderr = escape_string(&prog.stderr);
|
||||
let mut stdout = escape_string(&prog.stdout);
|
||||
info!("linker stderr:\n{}", &stderr);
|
||||
info!("linker stdout:\n{}", &stdout);
|
||||
|
||||
// Hide some progress messages from link.exe that we don't care about.
|
||||
// See https://github.com/chromium/chromium/blob/bfa41e41145ffc85f041384280caf2949bb7bd72/build/toolchain/win/tool_wrapper.py#L144-L146
|
||||
if is_msvc_link_exe {
|
||||
if let Ok(str) = str::from_utf8(&prog.stdout) {
|
||||
let mut output = String::with_capacity(str.len());
|
||||
for line in stdout.lines() {
|
||||
if line.starts_with(" Creating library")
|
||||
|| line.starts_with("Generating code")
|
||||
|| line.starts_with("Finished generating code")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
output += line;
|
||||
output += "\r\n"
|
||||
}
|
||||
stdout = escape_string(output.trim().as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
let (level, src) = codegen_results.crate_info.lint_levels.linker_messages;
|
||||
let lint = |msg| {
|
||||
lint_level(sess, LINKER_MESSAGES, level, src, None, |diag| {
|
||||
LinkerOutput { inner: msg }.decorate_lint(diag)
|
||||
})
|
||||
};
|
||||
|
||||
if !prog.stderr.is_empty() {
|
||||
// We already print `warning:` at the start of the diagnostic. Remove it from the linker output if present.
|
||||
let stderr = stderr
|
||||
.strip_prefix("warning: ")
|
||||
.unwrap_or(&stderr)
|
||||
.replace(": warning: ", ": ");
|
||||
lint(format!("linker stderr: {stderr}"));
|
||||
}
|
||||
if !stdout.is_empty() {
|
||||
lint(format!("linker stdout: {}", stdout))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ use crate::mir::operand::OperandValue;
|
|||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
||||
CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
errors, meth, mir,
|
||||
};
|
||||
|
||||
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
|
|
@ -924,6 +925,7 @@ impl CrateInfo {
|
|||
dependency_formats: Lrc::clone(tcx.dependency_formats(())),
|
||||
windows_subsystem,
|
||||
natvis_debugger_visualizers: Default::default(),
|
||||
lint_levels: CodegenLintLevels::from_tcx(tcx),
|
||||
};
|
||||
|
||||
info.native_libraries.reserve(n_crates);
|
||||
|
|
@ -1053,10 +1055,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
|
||||
let any_for_speed = defids.items().any(|id| {
|
||||
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
|
||||
match optimize {
|
||||
attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
|
||||
attr::OptimizeAttr::Speed => true,
|
||||
}
|
||||
matches!(optimize, attr::OptimizeAttr::Speed)
|
||||
});
|
||||
|
||||
if any_for_speed {
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.inline = InlineAttr::Never;
|
||||
}
|
||||
|
||||
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
|
||||
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::Default, |ia, attr| {
|
||||
if !attr.has_name(sym::optimize) {
|
||||
return ia;
|
||||
}
|
||||
|
|
@ -587,17 +587,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
inline_span = Some(attr.span);
|
||||
if items.len() != 1 {
|
||||
err(attr.span, "expected one argument");
|
||||
OptimizeAttr::None
|
||||
OptimizeAttr::Default
|
||||
} else if list_contains_name(items, sym::size) {
|
||||
OptimizeAttr::Size
|
||||
} else if list_contains_name(items, sym::speed) {
|
||||
OptimizeAttr::Speed
|
||||
} else if list_contains_name(items, sym::none) {
|
||||
OptimizeAttr::DoNotOptimize
|
||||
} else {
|
||||
err(items[0].span(), "invalid argument");
|
||||
OptimizeAttr::None
|
||||
OptimizeAttr::Default
|
||||
}
|
||||
} else {
|
||||
OptimizeAttr::None
|
||||
OptimizeAttr::Default
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ pub(crate) struct LinkingFailed<'a> {
|
|||
pub command: Command,
|
||||
pub escaped_output: String,
|
||||
pub verbose: bool,
|
||||
pub sysroot_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
||||
|
|
@ -364,6 +365,8 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
|||
if self.verbose {
|
||||
diag.note(format!("{:?}", self.command));
|
||||
} else {
|
||||
self.command.env_clear();
|
||||
|
||||
enum ArgGroup {
|
||||
Regular(OsString),
|
||||
Objects(usize),
|
||||
|
|
@ -398,26 +401,55 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
|
|||
args.push(ArgGroup::Regular(arg));
|
||||
}
|
||||
}
|
||||
self.command.args(args.into_iter().map(|arg_group| match arg_group {
|
||||
ArgGroup::Regular(arg) => arg,
|
||||
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
|
||||
ArgGroup::Rlibs(dir, rlibs) => {
|
||||
let mut arg = dir.into_os_string();
|
||||
arg.push("/{");
|
||||
let mut first = true;
|
||||
for rlib in rlibs {
|
||||
if !first {
|
||||
arg.push(",");
|
||||
let crate_hash = regex::bytes::Regex::new(r"-[0-9a-f]+\.rlib$").unwrap();
|
||||
self.command.args(args.into_iter().map(|arg_group| {
|
||||
match arg_group {
|
||||
// SAFETY: we are only matching on ASCII, not any surrogate pairs, so any replacements we do will still be valid.
|
||||
ArgGroup::Regular(arg) => unsafe {
|
||||
use bstr::ByteSlice;
|
||||
OsString::from_encoded_bytes_unchecked(
|
||||
arg.as_encoded_bytes().replace(
|
||||
self.sysroot_dir.as_os_str().as_encoded_bytes(),
|
||||
b"<sysroot>",
|
||||
),
|
||||
)
|
||||
},
|
||||
ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
|
||||
ArgGroup::Rlibs(mut dir, rlibs) => {
|
||||
let is_sysroot_dir = match dir.strip_prefix(&self.sysroot_dir) {
|
||||
Ok(short) => {
|
||||
dir = Path::new("<sysroot>").join(short);
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
};
|
||||
let mut arg = dir.into_os_string();
|
||||
arg.push("/{");
|
||||
let mut first = true;
|
||||
for mut rlib in rlibs {
|
||||
if !first {
|
||||
arg.push(",");
|
||||
}
|
||||
first = false;
|
||||
if is_sysroot_dir {
|
||||
// SAFETY: Regex works one byte at a type, and our regex will not match surrogate pairs (because it only matches ascii).
|
||||
rlib = unsafe {
|
||||
OsString::from_encoded_bytes_unchecked(
|
||||
crate_hash
|
||||
.replace(rlib.as_encoded_bytes(), b"-*")
|
||||
.into_owned(),
|
||||
)
|
||||
};
|
||||
}
|
||||
arg.push(rlib);
|
||||
}
|
||||
first = false;
|
||||
arg.push(rlib);
|
||||
arg.push("}.rlib");
|
||||
arg
|
||||
}
|
||||
arg.push("}");
|
||||
arg
|
||||
}
|
||||
}));
|
||||
|
||||
diag.note(format!("{:?}", self.command));
|
||||
diag.note(format!("{:?}", self.command).trim_start_matches("env -i").to_owned());
|
||||
diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,18 +29,23 @@ use rustc_ast as ast;
|
|||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::lint::LintLevelSource;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
|
||||
use rustc_session::cstore::{self, CrateSource};
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_session::lint::builtin::LINKER_MESSAGES;
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
|
|
@ -200,6 +205,7 @@ pub struct CrateInfo {
|
|||
pub dependency_formats: Lrc<Dependencies>,
|
||||
pub windows_subsystem: Option<String>,
|
||||
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
|
||||
pub lint_levels: CodegenLintLevels,
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable)]
|
||||
|
|
@ -302,3 +308,19 @@ impl CodegenResults {
|
|||
Ok((codegen_results, outputs))
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of lint levels used in codegen.
|
||||
///
|
||||
/// When using `-Z link-only`, we don't have access to the tcx and must work
|
||||
/// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable.
|
||||
/// Instead, encode exactly the information we need.
|
||||
#[derive(Copy, Clone, Debug, Encodable, Decodable)]
|
||||
pub struct CodegenLintLevels {
|
||||
linker_messages: (Level, LintLevelSource),
|
||||
}
|
||||
|
||||
impl CodegenLintLevels {
|
||||
pub fn from_tcx(tcx: TyCtxt<'_>) -> Self {
|
||||
Self { linker_messages: tcx.lint_level_at_node(LINKER_MESSAGES, CRATE_HIR_ID) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ const_eval_unsized_local = unsized locals are not supported
|
|||
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
||||
const_eval_unstable_in_stable_exposed =
|
||||
const function that might be (indirectly) exposed to stable cannot use `#[feature({$gate})]`
|
||||
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
|
||||
.is_function_call = mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unstable features
|
||||
.unstable_sugg = if the {$is_function_call2 ->
|
||||
[true] caller
|
||||
*[false] function
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@ A type parameter which references `Self` in its default value was not specified.
|
|||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0393
|
||||
trait A<T=Self> {}
|
||||
trait A<T = Self> {}
|
||||
|
||||
fn together_we_will_rule_the_galaxy(son: &A) {}
|
||||
// error: the type parameter `T` must be explicitly specified in an
|
||||
// object type because its default value `Self` references the
|
||||
// type `Self`
|
||||
fn together_we_will_rule_the_galaxy(son: &dyn A) {}
|
||||
// error: the type parameter `T` must be explicitly specified
|
||||
```
|
||||
|
||||
A trait object is defined over a single, fully-defined trait. With a regular
|
||||
|
|
@ -23,7 +21,7 @@ disallowed. Making the trait concrete by explicitly specifying the value of the
|
|||
defaulted parameter will fix this issue. Fixed example:
|
||||
|
||||
```
|
||||
trait A<T=Self> {}
|
||||
trait A<T = Self> {}
|
||||
|
||||
fn together_we_will_rule_the_galaxy(son: &A<i32>) {} // Ok!
|
||||
fn together_we_will_rule_the_galaxy(son: &dyn A<i32>) {} // Ok!
|
||||
```
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ If you've expected to use a crate name:
|
|||
|
||||
```compile_fail
|
||||
use ferris_wheel::BigO;
|
||||
// error: failed to resolve: use of undeclared crate or module `ferris_wheel`
|
||||
// error: failed to resolve: use of undeclared module or unlinked crate
|
||||
```
|
||||
|
||||
Make sure the crate has been added as a dependency in `Cargo.toml`.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_error_messages::FluentArgs;
|
|||
use rustc_lint_defs::Applicability;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::ExpnData;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::source_map::{FilePathMapping, SourceMap};
|
||||
use serde::Serialize;
|
||||
use termcolor::{ColorSpec, WriteColor};
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ pub struct JsonEmitter {
|
|||
#[setters(skip)]
|
||||
dst: IntoDynSyncSend<Box<dyn Write + Send>>,
|
||||
#[setters(skip)]
|
||||
sm: Lrc<SourceMap>,
|
||||
sm: Option<Lrc<SourceMap>>,
|
||||
fluent_bundle: Option<Lrc<FluentBundle>>,
|
||||
#[setters(skip)]
|
||||
fallback_bundle: LazyFallbackBundle,
|
||||
|
|
@ -65,7 +65,7 @@ pub struct JsonEmitter {
|
|||
impl JsonEmitter {
|
||||
pub fn new(
|
||||
dst: Box<dyn Write + Send>,
|
||||
sm: Lrc<SourceMap>,
|
||||
sm: Option<Lrc<SourceMap>>,
|
||||
fallback_bundle: LazyFallbackBundle,
|
||||
pretty: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
|
|
@ -171,7 +171,7 @@ impl Emitter for JsonEmitter {
|
|||
}
|
||||
|
||||
fn source_map(&self) -> Option<&SourceMap> {
|
||||
Some(&self.sm)
|
||||
self.sm.as_deref()
|
||||
}
|
||||
|
||||
fn should_show_explain(&self) -> bool {
|
||||
|
|
@ -371,7 +371,7 @@ impl Diagnostic {
|
|||
}
|
||||
HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle))
|
||||
.short_message(short)
|
||||
.sm(Some(Lrc::clone(&je.sm)))
|
||||
.sm(je.sm.clone())
|
||||
.fluent_bundle(je.fluent_bundle.clone())
|
||||
.diagnostic_width(je.diagnostic_width)
|
||||
.macro_backtrace(je.macro_backtrace)
|
||||
|
|
@ -458,23 +458,34 @@ impl DiagnosticSpan {
|
|||
mut backtrace: impl Iterator<Item = ExpnData>,
|
||||
je: &JsonEmitter,
|
||||
) -> DiagnosticSpan {
|
||||
let start = je.sm.lookup_char_pos(span.lo());
|
||||
let empty_source_map;
|
||||
let sm = match &je.sm {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
span = rustc_span::DUMMY_SP;
|
||||
empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
empty_source_map
|
||||
.new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new());
|
||||
&empty_source_map
|
||||
}
|
||||
};
|
||||
let start = sm.lookup_char_pos(span.lo());
|
||||
// If this goes from the start of a line to the end and the replacement
|
||||
// is an empty string, increase the length to include the newline so we don't
|
||||
// leave an empty line
|
||||
if start.col.0 == 0
|
||||
&& let Some((suggestion, _)) = suggestion
|
||||
&& suggestion.is_empty()
|
||||
&& let Ok(after) = je.sm.span_to_next_source(span)
|
||||
&& let Ok(after) = sm.span_to_next_source(span)
|
||||
&& after.starts_with('\n')
|
||||
{
|
||||
span = span.with_hi(span.hi() + rustc_span::BytePos(1));
|
||||
}
|
||||
let end = je.sm.lookup_char_pos(span.hi());
|
||||
let end = sm.lookup_char_pos(span.hi());
|
||||
let backtrace_step = backtrace.next().map(|bt| {
|
||||
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
|
||||
let def_site_span = Self::from_span_full(
|
||||
je.sm.guess_head_span(bt.def_site),
|
||||
sm.guess_head_span(bt.def_site),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
|
|
@ -489,7 +500,7 @@ impl DiagnosticSpan {
|
|||
});
|
||||
|
||||
DiagnosticSpan {
|
||||
file_name: je.sm.filename_for_diagnostics(&start.file.name).to_string(),
|
||||
file_name: sm.filename_for_diagnostics(&start.file.name).to_string(),
|
||||
byte_start: start.file.original_relative_byte_pos(span.lo()).0,
|
||||
byte_end: start.file.original_relative_byte_pos(span.hi()).0,
|
||||
line_start: start.line,
|
||||
|
|
@ -559,19 +570,20 @@ impl DiagnosticSpanLine {
|
|||
/// `span` within the line.
|
||||
fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
|
||||
je.sm
|
||||
.span_to_lines(span)
|
||||
.map(|lines| {
|
||||
.as_ref()
|
||||
.and_then(|sm| {
|
||||
let lines = sm.span_to_lines(span).ok()?;
|
||||
// We can't get any lines if the source is unavailable.
|
||||
if !should_show_source_code(
|
||||
&je.ignored_directories_in_source_blocks,
|
||||
&je.sm,
|
||||
&sm,
|
||||
&lines.file,
|
||||
) {
|
||||
return vec![];
|
||||
return None;
|
||||
}
|
||||
|
||||
let sf = &*lines.file;
|
||||
lines
|
||||
let span_lines = lines
|
||||
.lines
|
||||
.iter()
|
||||
.map(|line| {
|
||||
|
|
@ -582,8 +594,9 @@ impl DiagnosticSpanLine {
|
|||
line.end_col.0 + 1,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
.collect();
|
||||
Some(span_lines)
|
||||
})
|
||||
.unwrap_or_else(|_| vec![])
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
|
|||
let output = Arc::new(Mutex::new(Vec::new()));
|
||||
let je = JsonEmitter::new(
|
||||
Box::new(Shared { data: output.clone() }),
|
||||
sm,
|
||||
Some(sm),
|
||||
fallback_bundle,
|
||||
true, // pretty
|
||||
HumanReadableErrorType::Short,
|
||||
|
|
|
|||
|
|
@ -408,11 +408,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk,
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
// crate_id is deprecated
|
||||
ungated!(
|
||||
crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
|
||||
// ABI, linking, symbols, and FFI
|
||||
ungated!(
|
||||
|
|
@ -448,7 +443,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
|
||||
// Entry point:
|
||||
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
|
||||
// Modules, prelude, and resolution:
|
||||
|
|
@ -532,7 +526,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
// RFC 2412
|
||||
gated!(
|
||||
optimize, Normal, template!(List: "size|speed"), ErrorPreceding,
|
||||
optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
|
||||
EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
|
||||
),
|
||||
|
||||
|
|
|
|||
|
|
@ -353,7 +353,13 @@ hir_analysis_missing_type_params =
|
|||
[one] reference
|
||||
*[other] references
|
||||
} to {$parameters}
|
||||
.note = because of the default `Self` reference, type parameters must be specified on object types
|
||||
.note = because the parameter {$parameterCount ->
|
||||
[one] default references
|
||||
*[other] defaults reference
|
||||
} `Self`, the {$parameterCount ->
|
||||
[one] parameter
|
||||
*[other] parameters
|
||||
} must be specified on the object type
|
||||
|
||||
hir_analysis_multiple_relaxed_default_bounds =
|
||||
type parameter has more than one relaxed default bound, only one is supported
|
||||
|
|
|
|||
|
|
@ -237,16 +237,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Skip `Self`
|
||||
.skip(1)
|
||||
.map(|(index, arg)| {
|
||||
if arg == dummy_self.into() {
|
||||
if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
let param = &generics.own_params[index];
|
||||
missing_type_params.push(param.name);
|
||||
Ty::new_misc_error(tcx).into()
|
||||
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
|
||||
let guar = self.dcx().span_delayed_bug(
|
||||
span,
|
||||
"trait object trait bounds reference `Self`",
|
||||
);
|
||||
replace_dummy_self_with_error(tcx, arg, guar)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,6 +185,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
rhs_ty: Ty<'tcx>,
|
||||
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
|
||||
) -> bool {
|
||||
if lhs_expr.span.in_derive_expansion() || rhs_expr.span.in_derive_expansion() {
|
||||
return false;
|
||||
}
|
||||
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_ty) else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,12 +69,10 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
|
|||
|
||||
lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
|
||||
lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
|
||||
lint_builtin_deprecated_attr_default_suggestion = remove this attribute
|
||||
|
||||
lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
|
||||
.msg_suggestion = {$msg}
|
||||
.default_suggestion = remove this attribute
|
||||
lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used
|
||||
lint_builtin_deref_nullptr = dereferencing a null pointer
|
||||
.label = this code causes undefined behavior when executed
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use rustc_abi::BackendRepr;
|
|||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -49,7 +49,7 @@ use rustc_trait_selection::traits::{self};
|
|||
use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
|
||||
use crate::lints::{
|
||||
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
|
||||
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr,
|
||||
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr,
|
||||
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
|
||||
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
|
||||
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
|
||||
|
|
@ -848,12 +848,6 @@ impl EarlyLintPass for DeprecatedAttr {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
|
||||
cx.emit_span_lint(DEPRECATED, attr.span, BuiltinDeprecatedAttrUsed {
|
||||
name: pprust::path_to_string(&attr.get_normal_item().path),
|
||||
suggestion: attr.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,35 @@ use crate::lints;
|
|||
|
||||
const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
|
||||
|
||||
enum FilterWellKnownNames {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
fn sort_and_truncate_possibilities(
|
||||
sess: &Session,
|
||||
mut possibilities: Vec<Symbol>,
|
||||
filter_well_known_names: FilterWellKnownNames,
|
||||
) -> (Vec<Symbol>, usize) {
|
||||
let possibilities_len = possibilities.len();
|
||||
|
||||
let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
|
||||
possibilities.len()
|
||||
} else {
|
||||
match filter_well_known_names {
|
||||
FilterWellKnownNames::Yes => {
|
||||
possibilities.retain(|cfg_name| {
|
||||
!sess.psess.check_config.well_known_names.contains(cfg_name)
|
||||
});
|
||||
}
|
||||
FilterWellKnownNames::No => {}
|
||||
};
|
||||
std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
|
||||
};
|
||||
|
||||
possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
|
||||
|
||||
let and_more = possibilities.len().saturating_sub(n_possibilities);
|
||||
let and_more = possibilities_len.saturating_sub(n_possibilities);
|
||||
possibilities.truncate(n_possibilities);
|
||||
(possibilities, and_more)
|
||||
}
|
||||
|
|
@ -198,8 +214,10 @@ pub(super) fn unexpected_cfg_name(
|
|||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let (possibilities, and_more) =
|
||||
sort_and_truncate_possibilities(sess, possibilities, FilterWellKnownNames::Yes);
|
||||
let expected_names = if !possibilities.is_empty() {
|
||||
let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
|
||||
let possibilities: Vec<_> =
|
||||
possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
|
||||
Some(lints::unexpected_cfg_name::ExpectedNames {
|
||||
|
|
@ -269,8 +287,11 @@ pub(super) fn unexpected_cfg_value(
|
|||
// for names as the possibilities could be very long
|
||||
let code_sugg = if !possibilities.is_empty() {
|
||||
let expected_values = {
|
||||
let (possibilities, and_more) =
|
||||
sort_and_truncate_possibilities(sess, possibilities.clone());
|
||||
let (possibilities, and_more) = sort_and_truncate_possibilities(
|
||||
sess,
|
||||
possibilities.clone(),
|
||||
FilterWellKnownNames::No,
|
||||
);
|
||||
lints::unexpected_cfg_value::ExpectedValues {
|
||||
name,
|
||||
have_none_possibility,
|
||||
|
|
|
|||
|
|
@ -177,19 +177,6 @@ pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_deprecated_attr_used)]
|
||||
pub(crate) struct BuiltinDeprecatedAttrUsed {
|
||||
pub name: String,
|
||||
#[suggestion(
|
||||
lint_builtin_deprecated_attr_default_suggestion,
|
||||
style = "short",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_unused_doc_comment)]
|
||||
pub(crate) struct BuiltinUnusedDocComment<'a> {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ declare_lint_pass! {
|
|||
LARGE_ASSIGNMENTS,
|
||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
LEGACY_DERIVE_HELPERS,
|
||||
LINKER_MESSAGES,
|
||||
LONG_RUNNING_CONST_EVAL,
|
||||
LOSSY_PROVENANCE_CASTS,
|
||||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||
|
|
@ -4085,6 +4086,39 @@ declare_lint! {
|
|||
"call to foreign functions or function pointers with FFI-unwind ABI"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `linker_messages` lint forwards warnings from the linker.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs CLI args, platform-specific)
|
||||
/// extern "C" {
|
||||
/// fn foo();
|
||||
/// }
|
||||
/// fn main () { unsafe { foo(); } }
|
||||
/// ```
|
||||
///
|
||||
/// On Linux, using `gcc -Wl,--warn-unresolved-symbols` as a linker, this will produce
|
||||
///
|
||||
/// ```text
|
||||
/// warning: linker stderr: rust-lld: undefined symbol: foo
|
||||
/// >>> referenced by rust_out.69edbd30df4ae57d-cgu.0
|
||||
/// >>> rust_out.rust_out.69edbd30df4ae57d-cgu.0.rcgu.o:(rust_out::main::h3a90094b06757803)
|
||||
/// |
|
||||
/// = note: `#[warn(linker_messages)]` on by default
|
||||
///
|
||||
/// warning: 1 warning emitted
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Linkers emit platform-specific and program-specific warnings that cannot be predicted in advance by the rust compiler.
|
||||
/// They are forwarded by default, but can be disabled by adding `#![allow(linker_messages)]` at the crate root.
|
||||
pub LINKER_MESSAGES,
|
||||
Warn,
|
||||
"warnings emitted at runtime by the target-specific linker program"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `named_arguments_used_positionally` lint detects cases where named arguments are only
|
||||
/// used positionally in format strings. This usage is valid but potentially very confusing.
|
||||
|
|
|
|||
|
|
@ -161,7 +161,19 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
|
|||
/// Setting for how to handle a lint.
|
||||
///
|
||||
/// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Eq,
|
||||
Ord,
|
||||
Debug,
|
||||
Hash,
|
||||
Encodable,
|
||||
Decodable,
|
||||
HashStable_Generic
|
||||
)]
|
||||
pub enum Level {
|
||||
/// The `allow` level will not issue any message.
|
||||
Allow,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::{Diag, MultiSpan};
|
||||
use rustc_hir::{HirId, ItemLocalId};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
|
||||
|
|
@ -15,7 +15,7 @@ use tracing::instrument;
|
|||
use crate::ty::TyCtxt;
|
||||
|
||||
/// How a lint level was set.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, HashStable, Debug)]
|
||||
pub enum LintLevelSource {
|
||||
/// Lint is at the default level as declared in rustc.
|
||||
Default,
|
||||
|
|
@ -173,7 +173,7 @@ impl TyCtxt<'_> {
|
|||
/// This struct represents a lint expectation and holds all required information
|
||||
/// to emit the `unfulfilled_lint_expectations` lint if it is unfulfilled after
|
||||
/// the `LateLintPass` has completed.
|
||||
#[derive(Clone, Debug, HashStable)]
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
|
||||
pub struct LintExpectation {
|
||||
/// The reason for this expectation that can optionally be added as part of
|
||||
/// the attribute. It will be displayed as part of the lint message.
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ impl CodegenFnAttrs {
|
|||
CodegenFnAttrs {
|
||||
flags: CodegenFnAttrFlags::empty(),
|
||||
inline: InlineAttr::None,
|
||||
optimize: OptimizeAttr::None,
|
||||
optimize: OptimizeAttr::Default,
|
||||
export_name: None,
|
||||
link_name: None,
|
||||
link_ordinal: None,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ mir_build_borrow_of_moved_value = borrow of moved value
|
|||
.occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait
|
||||
.value_borrowed_label = value borrowed here after move
|
||||
.suggestion = borrow this binding in the pattern to avoid moving the value
|
||||
.full_type_name = the full type name has been written to '{$path}'
|
||||
.consider_verbose = consider using `--verbose` to print the full type name to the console
|
||||
|
||||
mir_build_call_to_deprecated_safe_fn_requires_unsafe =
|
||||
call to deprecated safe function `{$function}` is unsafe and requires unsafe block
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@ pub(crate) struct IrrefutableLetPatternsWhileLet {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_borrow_of_moved_value)]
|
||||
pub(crate) struct BorrowOfMovedValue<'tcx> {
|
||||
pub(crate) struct BorrowOfMovedValue {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label(mir_build_occurs_because_label)]
|
||||
|
|
@ -798,9 +798,13 @@ pub(crate) struct BorrowOfMovedValue<'tcx> {
|
|||
#[label(mir_build_value_borrowed_label)]
|
||||
pub(crate) conflicts_ref: Vec<Span>,
|
||||
pub(crate) name: Symbol,
|
||||
pub(crate) ty: Ty<'tcx>,
|
||||
pub(crate) ty: String,
|
||||
#[suggestion(code = "ref ", applicability = "machine-applicable")]
|
||||
pub(crate) suggest_borrowing: Option<Span>,
|
||||
#[note(mir_build_full_type_name)]
|
||||
#[note(mir_build_consider_verbose)]
|
||||
pub(crate) has_path: bool,
|
||||
pub(crate) path: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -795,12 +795,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
|||
}
|
||||
});
|
||||
if !conflicts_ref.is_empty() {
|
||||
let mut path = None;
|
||||
let ty = cx.tcx.short_ty_string(ty, &mut path);
|
||||
sess.dcx().emit_err(BorrowOfMovedValue {
|
||||
binding_span: pat.span,
|
||||
conflicts_ref,
|
||||
name,
|
||||
ty,
|
||||
suggest_borrowing: Some(pat.span.shrink_to_lo()),
|
||||
has_path: path.is_some(),
|
||||
path: path.map(|p| p.display().to_string()).unwrap_or_default(),
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -116,4 +116,8 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
|||
// We may have invalidated some `cleanup` blocks so clean those up now.
|
||||
super::simplify::remove_dead_blocks(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,4 +75,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
|
|||
|
||||
body.basic_blocks_mut().extend(new_blocks);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
|
|||
|
||||
patch.apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_for_packed_drop<'tcx>(
|
||||
|
|
|
|||
|
|
@ -176,4 +176,8 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,4 +61,8 @@ impl<'tcx> crate::MirPass<'tcx> for Subtyper {
|
|||
}
|
||||
checker.patcher.apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct PointerFinder<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -72,4 +72,8 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
|
|||
decl.user_ty = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp {
|
|||
crate::simplify::remove_unused_definitions(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// `SsaLocals` computed equivalence classes between locals considering copy/move assignments.
|
||||
|
|
|
|||
|
|
@ -1688,6 +1688,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
|
|||
// Run derefer to fix Derefs that are not in the first place
|
||||
deref_finder(tcx, body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
|
|||
|
||||
instrument_function_for_coverage(tcx, mir_body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
// Don't do any inference if codegen optimizations are disabled and also MIR inlining is not
|
||||
// enabled. This ensures that we do inference even if someone only passes -Zinline-mir,
|
||||
// which is less confusing than having to also enable -Copt-level=1.
|
||||
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline)
|
||||
let inliner_will_run = pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|
||||
|| inline::ForceInline::should_run_pass_for_callee(tcx, def_id.to_def_id());
|
||||
if matches!(tcx.sess.opts.optimize, OptLevel::No) && !inliner_will_run {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn has_back_edge(
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
|
|||
let mut patch = visitor.patch;
|
||||
debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body));
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Currently, places that have their reference taken cannot be tracked. Although this would
|
||||
|
|
|
|||
|
|
@ -147,4 +147,8 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
eliminate(tcx, body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
|
|||
simplify_cfg(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct OptApplier<'tcx> {
|
||||
|
|
|
|||
|
|
@ -81,4 +81,8 @@ impl<'tcx> crate::MirPass<'tcx> for Derefer {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
deref_finder(tcx, body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,6 +240,10 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
|
|||
|
||||
trace!(round_count);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for Marker {
|
|||
}
|
||||
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
|
||||
|
|
|
|||
|
|
@ -227,6 +227,10 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
|
|||
simplify_cfg(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -150,4 +150,8 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
|
|||
elaborate_patch.apply(body);
|
||||
deref_finder(tcx, body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Records unwind edges which are known to be unreachable, because they are in `drop` terminators
|
||||
|
|
|
|||
|
|
@ -163,6 +163,10 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
|
|||
// statements.
|
||||
StorageRemover { tcx, reused_locals: state.reused_locals }.visit_body_preserves_cfg(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
newtype_index! {
|
||||
|
|
|
|||
|
|
@ -53,4 +53,8 @@ impl<'tcx> MirPass<'tcx> for ImpossiblePredicates {
|
|||
body.local_decls.raw.truncate(body.arg_count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ impl<'tcx> crate::MirPass<'tcx> for Inline {
|
|||
deref_finder(tcx, body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ForceInline;
|
||||
|
|
@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ForceInline {
|
|||
false
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let span = trace_span!("force_inline", body = %tcx.def_path_str(body.source.def_id()));
|
||||
let _guard = span.enter();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
|
|||
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct InstSimplifyContext<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
|
|||
}
|
||||
OpportunitySet::new(body, opportunities).apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -200,6 +200,10 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumSizeOpt {
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
|||
&Lint(sanity_check::SanityCheck),
|
||||
],
|
||||
None,
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
tcx.alloc_steal_mir(body)
|
||||
}
|
||||
|
|
@ -440,6 +441,7 @@ fn mir_promoted(
|
|||
&mut body,
|
||||
&[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
|
||||
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
|
||||
lint_tail_expr_drop_order::run_lint(tcx, def, &body);
|
||||
|
|
@ -473,7 +475,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
|
|||
};
|
||||
|
||||
let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
|
||||
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
|
||||
pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed);
|
||||
|
||||
body
|
||||
}
|
||||
|
|
@ -493,7 +495,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
|
|||
let is_fn_like = tcx.def_kind(def).is_fn_like();
|
||||
if is_fn_like {
|
||||
// Do not compute the mir call graph without said call graph actually being used.
|
||||
if pm::should_run_pass(tcx, &inline::Inline)
|
||||
if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
|
||||
|| inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
|
||||
{
|
||||
tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
|
||||
|
|
@ -533,6 +535,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
|
|||
&Lint(post_drop_elaboration::CheckLiveDrops),
|
||||
],
|
||||
None,
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +560,13 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&deref_separator::Derefer,
|
||||
];
|
||||
|
||||
pm::run_passes(tcx, body, passes, Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)));
|
||||
pm::run_passes(
|
||||
tcx,
|
||||
body,
|
||||
passes,
|
||||
Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the sequence of passes that lowers analysis to runtime MIR.
|
||||
|
|
@ -597,7 +606,13 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&simplify::SimplifyCfg::PreOptimizations,
|
||||
];
|
||||
|
||||
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
|
||||
pm::run_passes(
|
||||
tcx,
|
||||
body,
|
||||
passes,
|
||||
Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
|
||||
// Clear this by anticipation. Optimizations and runtime MIR have no reason to look
|
||||
// into this information, which is meant for borrowck diagnostics.
|
||||
|
|
@ -611,6 +626,15 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
WithMinOptLevel(1, x)
|
||||
}
|
||||
|
||||
let def_id = body.source.def_id();
|
||||
let optimizations = if tcx.def_kind(def_id).has_codegen_attrs()
|
||||
&& tcx.codegen_fn_attrs(def_id).optimize.do_not_optimize()
|
||||
{
|
||||
pm::Optimizations::Suppressed
|
||||
} else {
|
||||
pm::Optimizations::Allowed
|
||||
};
|
||||
|
||||
// The main optimizations that we do on MIR.
|
||||
pm::run_passes(
|
||||
tcx,
|
||||
|
|
@ -683,6 +707,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
&dump_mir::Marker("PreCodegen"),
|
||||
],
|
||||
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
|
||||
optimizations,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -325,4 +325,8 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
|
|||
lower_slice_len_call(block, slice_len_fn_item_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_item_def_id: DefId) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
|
|||
simplify_cfg(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
trait SimplifyMatch<'tcx> {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
|
|||
visitor.visit_body(body);
|
||||
body.set_mentioned_items(visitor.mentioned_items);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are
|
||||
|
|
|
|||
|
|
@ -36,4 +36,8 @@ impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
|
|||
|
||||
simplify::remove_dead_blocks(body)
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
|
|||
// The return place is always mutable.
|
||||
ret_decl.mutability = Mutability::Mut;
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// MIR that is eligible for the NRVO must fulfill two conditions:
|
||||
|
|
|
|||
|
|
@ -90,6 +90,11 @@ pub(super) trait MirPass<'tcx> {
|
|||
fn is_mir_dump_enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns `true` if this pass must be run (i.e. it is required for soundness).
|
||||
/// For passes which are strictly optimizations, this should return `false`.
|
||||
/// If this is `false`, `#[optimize(none)]` will disable the pass.
|
||||
fn is_required(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
|
||||
|
|
@ -134,6 +139,10 @@ where
|
|||
fn is_mir_dump_enabled(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
|
||||
|
|
@ -153,6 +162,19 @@ where
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
self.1.run_pass(tcx, body)
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
self.1.is_required()
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to allow non-[required] optimizations
|
||||
///
|
||||
/// [required]: MirPass::is_required
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum Optimizations {
|
||||
Suppressed,
|
||||
Allowed,
|
||||
}
|
||||
|
||||
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
|
||||
|
|
@ -163,7 +185,7 @@ pub(super) fn run_passes_no_validate<'tcx>(
|
|||
passes: &[&dyn MirPass<'tcx>],
|
||||
phase_change: Option<MirPhase>,
|
||||
) {
|
||||
run_passes_inner(tcx, body, passes, phase_change, false);
|
||||
run_passes_inner(tcx, body, passes, phase_change, false, Optimizations::Allowed);
|
||||
}
|
||||
|
||||
/// The optional `phase_change` is applied after executing all the passes, if present
|
||||
|
|
@ -172,11 +194,16 @@ pub(super) fn run_passes<'tcx>(
|
|||
body: &mut Body<'tcx>,
|
||||
passes: &[&dyn MirPass<'tcx>],
|
||||
phase_change: Option<MirPhase>,
|
||||
optimizations: Optimizations,
|
||||
) {
|
||||
run_passes_inner(tcx, body, passes, phase_change, true);
|
||||
run_passes_inner(tcx, body, passes, phase_change, true, optimizations);
|
||||
}
|
||||
|
||||
pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
|
||||
pub(super) fn should_run_pass<'tcx, P>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pass: &P,
|
||||
optimizations: Optimizations,
|
||||
) -> bool
|
||||
where
|
||||
P: MirPass<'tcx> + ?Sized,
|
||||
{
|
||||
|
|
@ -196,7 +223,8 @@ where
|
|||
);
|
||||
*polarity
|
||||
});
|
||||
overridden.unwrap_or_else(|| pass.is_enabled(tcx.sess))
|
||||
let suppressed = !pass.is_required() && matches!(optimizations, Optimizations::Suppressed);
|
||||
overridden.unwrap_or_else(|| !suppressed && pass.is_enabled(tcx.sess))
|
||||
}
|
||||
|
||||
fn run_passes_inner<'tcx>(
|
||||
|
|
@ -205,6 +233,7 @@ fn run_passes_inner<'tcx>(
|
|||
passes: &[&dyn MirPass<'tcx>],
|
||||
phase_change: Option<MirPhase>,
|
||||
validate_each: bool,
|
||||
optimizations: Optimizations,
|
||||
) {
|
||||
let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
|
||||
trace!(?overridden_passes);
|
||||
|
|
@ -243,7 +272,7 @@ fn run_passes_inner<'tcx>(
|
|||
for pass in passes {
|
||||
let name = pass.name();
|
||||
|
||||
if !should_run_pass(tcx, *pass) {
|
||||
if !should_run_pass(tcx, *pass, optimizations) {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ impl<'tcx> crate::MirPass<'tcx> for PostAnalysisNormalize {
|
|||
let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id());
|
||||
PostAnalysisNormalizeVisitor { tcx, typing_env }.visit_body_preserves_cfg(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct PostAnalysisNormalizeVisitor<'tcx> {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
|
|||
|
||||
permute(body.basic_blocks.as_mut(), &updater.map);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Rearranges the locals into *use* order.
|
||||
|
|
@ -85,6 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
|
|||
|
||||
permute(&mut body.local_decls, &updater.map);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn permute<I: rustc_index::Idx + Ord, T>(data: &mut IndexVec<I, T>, map: &IndexSlice<I, I>) {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
|
|||
let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
|
||||
self.promoted_fragments.set(promoted);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// State of a temporary during collection and promotion.
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
|
|||
debug!(def_id = ?body.source.def_id());
|
||||
while propagate_ssa(tcx, body) {}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
|
|||
|
||||
debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl RemoveNoopLandingPads {
|
||||
|
|
|
|||
|
|
@ -20,4 +20,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,4 +22,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
|
|||
block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn is_needs_drop_and_init<'tcx>(
|
||||
|
|
|
|||
|
|
@ -38,4 +38,8 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
|
|||
simplify_cfg(body);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
|
|||
replacer.visit_basic_block_data(bb, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct Replacer<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
|
|||
&add_call_guards::CriticalCallEdges,
|
||||
],
|
||||
Some(MirPhase::Runtime(RuntimePhase::Optimized)),
|
||||
pm::Optimizations::Allowed,
|
||||
);
|
||||
|
||||
return body;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
|
|||
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
|
||||
simplify_cfg(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct CfgSimplifier<'a, 'tcx> {
|
||||
|
|
@ -405,6 +409,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
|
|||
body.local_decls.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn remove_unused_definitions<'tcx>(body: &mut Body<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -60,4 +60,8 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
|
|||
body.basic_blocks_mut()[idx].statements.insert(0, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct OptimizationFinder<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,10 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Identify all locals that are not eligible for SROA.
|
||||
|
|
|
|||
|
|
@ -31,4 +31,8 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
|
|||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,4 +208,8 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
|
|||
|
||||
patch.apply(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ impl crate::MirPass<'_> for UnreachablePropagation {
|
|||
body.basic_blocks_mut()[bb].statements.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether the current terminator is fully unreachable.
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct CfgChecker<'a, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -812,6 +812,9 @@ passes_unused_duplicate =
|
|||
passes_unused_empty_lints_note =
|
||||
attribute `{$name}` with an empty list has no effect
|
||||
|
||||
passes_unused_linker_warnings_note =
|
||||
the `linker_warnings` lint can only be controlled at the root of a crate that needs to be linked
|
||||
|
||||
passes_unused_multiple =
|
||||
multiple `{$name}` attributes
|
||||
.suggestion = remove this attribute
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use rustc_middle::traits::ObligationCause;
|
|||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::lint::builtin::{
|
||||
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
|
||||
|
|
@ -2327,6 +2328,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&& item.path == sym::reason
|
||||
{
|
||||
errors::UnusedNote::NoLints { name: attr.name_or_empty() }
|
||||
} else if matches!(
|
||||
attr.name_or_empty(),
|
||||
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
|
||||
) && let Some(meta) = attr.meta_item_list()
|
||||
&& meta.iter().any(|meta| {
|
||||
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
|
||||
})
|
||||
{
|
||||
if hir_id != CRATE_HIR_ID {
|
||||
match attr.style {
|
||||
ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::OuterCrateLevelAttr,
|
||||
),
|
||||
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span,
|
||||
errors::InnerCrateLevelAttr,
|
||||
),
|
||||
};
|
||||
return;
|
||||
} else {
|
||||
let never_needs_link = self
|
||||
.tcx
|
||||
.crate_types()
|
||||
.iter()
|
||||
.all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
|
||||
if never_needs_link {
|
||||
errors::UnusedNote::LinkerWarningsBinaryCrateOnly
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if attr.name_or_empty() == sym::default_method_body_is_const {
|
||||
errors::UnusedNote::DefaultMethodBodyConst
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -802,6 +802,8 @@ pub(crate) enum UnusedNote {
|
|||
NoLints { name: Symbol },
|
||||
#[note(passes_unused_default_method_body_const_note)]
|
||||
DefaultMethodBodyConst,
|
||||
#[note(passes_unused_linker_warnings_note)]
|
||||
LinkerWarningsBinaryCrateOnly,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use rustc_session::lint::builtin::{
|
|||
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||
};
|
||||
use rustc_session::lint::{AmbiguityErrorDiag, BuiltinLintDiag};
|
||||
use rustc_session::utils::was_invoked_from_cargo;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
|
@ -800,7 +801,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
err.multipart_suggestion(msg, suggestions, applicability);
|
||||
}
|
||||
|
||||
if let Some(ModuleOrUniformRoot::Module(module)) = module
|
||||
&& let Some(module) = module.opt_def_id()
|
||||
&& let Some(segment) = segment
|
||||
|
|
@ -2034,13 +2034,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
(format!("`_` is not a valid crate or module name"), None)
|
||||
} else if self.tcx.sess.is_rust_2015() {
|
||||
(
|
||||
format!("you might be missing crate `{ident}`"),
|
||||
format!("use of unresolved module or unlinked crate `{ident}`"),
|
||||
Some((
|
||||
vec![(
|
||||
self.current_crate_outer_attr_insert_span,
|
||||
format!("extern crate {ident};\n"),
|
||||
)],
|
||||
format!("consider importing the `{ident}` crate"),
|
||||
if was_invoked_from_cargo() {
|
||||
format!(
|
||||
"if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
|
||||
to add it to your `Cargo.toml` and import it in your code",
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"you might be missing a crate named `{ident}`, add it to your \
|
||||
project and import it in your code",
|
||||
)
|
||||
},
|
||||
Applicability::MaybeIncorrect,
|
||||
)),
|
||||
)
|
||||
|
|
@ -2219,7 +2229,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let descr = binding.res().descr();
|
||||
(format!("{descr} `{ident}` is not a crate or module"), suggestion)
|
||||
} else {
|
||||
(format!("use of undeclared crate or module `{ident}`"), suggestion)
|
||||
let suggestion = if suggestion.is_some() {
|
||||
suggestion
|
||||
} else if was_invoked_from_cargo() {
|
||||
Some((
|
||||
vec![],
|
||||
format!(
|
||||
"if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
|
||||
to add it to your `Cargo.toml`",
|
||||
),
|
||||
Applicability::MaybeIncorrect,
|
||||
))
|
||||
} else {
|
||||
Some((
|
||||
vec![],
|
||||
format!("you might be missing a crate named `{ident}`",),
|
||||
Applicability::MaybeIncorrect,
|
||||
))
|
||||
};
|
||||
(format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -895,13 +895,16 @@ fn default_emitter(
|
|||
}
|
||||
t => t,
|
||||
};
|
||||
|
||||
let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
|
||||
|
||||
match sopts.error_format {
|
||||
config::ErrorOutputType::HumanReadable(kind, color_config) => {
|
||||
let short = kind.short();
|
||||
|
||||
if let HumanReadableErrorType::AnnotateSnippet = kind {
|
||||
let emitter = AnnotateSnippetEmitter::new(
|
||||
Some(source_map),
|
||||
source_map,
|
||||
bundle,
|
||||
fallback_bundle,
|
||||
short,
|
||||
|
|
@ -911,7 +914,7 @@ fn default_emitter(
|
|||
} else {
|
||||
let emitter = HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
|
||||
.fluent_bundle(bundle)
|
||||
.sm(Some(source_map))
|
||||
.sm(source_map)
|
||||
.short_message(short)
|
||||
.teach(sopts.unstable_opts.teach)
|
||||
.diagnostic_width(sopts.diagnostic_width)
|
||||
|
|
@ -1442,7 +1445,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
|
|||
config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
|
||||
Box::new(JsonEmitter::new(
|
||||
Box::new(io::BufWriter::new(io::stderr())),
|
||||
Lrc::new(SourceMap::new(FilePathMapping::empty())),
|
||||
Some(Lrc::new(SourceMap::new(FilePathMapping::empty()))),
|
||||
fallback_bundle,
|
||||
pretty,
|
||||
json_rendered,
|
||||
|
|
|
|||
|
|
@ -707,7 +707,6 @@ symbols! {
|
|||
coverage,
|
||||
coverage_attribute,
|
||||
cr,
|
||||
crate_id,
|
||||
crate_in_paths,
|
||||
crate_local,
|
||||
crate_name,
|
||||
|
|
@ -1189,6 +1188,7 @@ symbols! {
|
|||
link_section,
|
||||
linkage,
|
||||
linker,
|
||||
linker_messages,
|
||||
lint_reasons,
|
||||
literal,
|
||||
load,
|
||||
|
|
@ -1389,7 +1389,6 @@ symbols! {
|
|||
no_mangle,
|
||||
no_sanitize,
|
||||
no_stack_check,
|
||||
no_start,
|
||||
no_std,
|
||||
nomem,
|
||||
non_ascii_idents,
|
||||
|
|
|
|||
|
|
@ -302,18 +302,28 @@ impl<'f> Drop for VaListImpl<'f> {
|
|||
}
|
||||
}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
/// Destroy the arglist `ap` after initialization with `va_start` or
|
||||
/// `va_copy`.
|
||||
#[rustc_nounwind]
|
||||
fn va_end(ap: &mut VaListImpl<'_>);
|
||||
|
||||
/// Copies the current location of arglist `src` to the arglist `dst`.
|
||||
#[rustc_nounwind]
|
||||
fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
|
||||
|
||||
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
|
||||
/// argument `ap` points to.
|
||||
#[rustc_nounwind]
|
||||
fn va_arg<T: sealed_trait::VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
|
||||
/// Destroy the arglist `ap` after initialization with `va_start` or
|
||||
/// `va_copy`.
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_intrinsic_must_be_overridden]
|
||||
#[rustc_nounwind]
|
||||
unsafe fn va_end(_ap: &mut VaListImpl<'_>) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Copies the current location of arglist `src` to the arglist `dst`.
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_intrinsic_must_be_overridden]
|
||||
#[rustc_nounwind]
|
||||
unsafe fn va_copy<'f>(_dest: *mut VaListImpl<'f>, _src: &VaListImpl<'f>) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
|
||||
/// argument `ap` points to.
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_intrinsic_must_be_overridden]
|
||||
#[rustc_nounwind]
|
||||
unsafe fn va_arg<T: sealed_trait::VaArgSafe>(_ap: &mut VaListImpl<'_>) -> T {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3252,18 +3252,26 @@ impl<B: BufRead> Iterator for Lines<B> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create anonymous pipe that is close-on-exec and blocking.
|
||||
/// Create an anonymous pipe that is close-on-exec and blocking.
|
||||
///
|
||||
/// # Behavior
|
||||
///
|
||||
/// A pipe is a synchronous, unidirectional data channel between two or more processes, like an
|
||||
/// interprocess [`mpsc`](crate::sync::mpsc) provided by the OS. In particular:
|
||||
/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
|
||||
/// typically used to communicate between two or more separate processes, as there are better,
|
||||
/// faster ways to communicate within a single process.
|
||||
///
|
||||
/// In particular:
|
||||
///
|
||||
/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
|
||||
/// * A write on a [`PipeWriter`] blocks when the pipe is full.
|
||||
/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
|
||||
/// returns EOF.
|
||||
/// * [`PipeReader`] can be shared, but only one process will consume the data in the pipe.
|
||||
/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
|
||||
/// writes (above a target-specific threshold) may have their data interleaved.
|
||||
/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
|
||||
/// given byte will only get consumed by one reader. There are no guarantees about data
|
||||
/// interleaving.
|
||||
/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
|
||||
///
|
||||
/// # Capacity
|
||||
///
|
||||
|
|
@ -3301,8 +3309,6 @@ impl<B: BufRead> Iterator for Lines<B> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
/// [pipe]: https://man7.org/linux/man-pages/man2/pipe.2.html
|
||||
/// [CreatePipe]: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
|
||||
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
|
||||
#[unstable(feature = "anonymous_pipe", issue = "127154")]
|
||||
#[inline]
|
||||
|
|
@ -3310,12 +3316,12 @@ pub fn pipe() -> Result<(PipeReader, PipeWriter)> {
|
|||
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
|
||||
}
|
||||
|
||||
/// Read end of the anonymous pipe.
|
||||
/// Read end of an anonymous pipe.
|
||||
#[unstable(feature = "anonymous_pipe", issue = "127154")]
|
||||
#[derive(Debug)]
|
||||
pub struct PipeReader(pub(crate) AnonPipe);
|
||||
|
||||
/// Write end of the anonymous pipe.
|
||||
/// Write end of an anonymous pipe.
|
||||
#[unstable(feature = "anonymous_pipe", issue = "127154")]
|
||||
#[derive(Debug)]
|
||||
pub struct PipeWriter(pub(crate) AnonPipe);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue