mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 01:13:11 +00:00
Auto merge of #109538 - matthiaskrgr:rollup-ct58npj, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #106964 (Clarify `Error::last_os_error` can be weird) - #107718 (Add `-Z time-passes-format` to allow specifying a JSON output for `-Z time-passes`) - #107880 (Lint ambiguous glob re-exports) - #108549 (Remove issue number for `link_cfg`) - #108588 (Fix the ffi_unwind_calls lint documentation) - #109231 (Add `try_canonicalize` to `rustc_fs_util` and use it over `fs::canonicalize`) - #109472 (Add parentheses properly for method calls) - #109487 (Move useless_anynous_reexport lint into unused_imports) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1459b3128e
@ -4523,6 +4523,7 @@ dependencies = [
|
|||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
"serde_json",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"stacker",
|
"stacker",
|
||||||
@ -4826,6 +4827,7 @@ dependencies = [
|
|||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
|
"rustc_fs_util",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_analysis",
|
"rustc_hir_analysis",
|
||||||
"rustc_hir_typeck",
|
"rustc_hir_typeck",
|
||||||
@ -4950,6 +4952,7 @@ dependencies = [
|
|||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fs_util",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_hir_pretty",
|
"rustc_hir_pretty",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
@ -5335,6 +5338,7 @@ dependencies = [
|
|||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_fs_util",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||||||
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||||
.join(sess);
|
.join(sess);
|
||||||
|
|
||||||
sess.time("llvm_dump_timing_file", || {
|
if sess.opts.unstable_opts.llvm_time_trace {
|
||||||
if sess.opts.unstable_opts.llvm_time_trace {
|
sess.time("llvm_dump_timing_file", || {
|
||||||
let file_name = outputs.with_extension("llvm_timings.json");
|
let file_name = outputs.with_extension("llvm_timings.json");
|
||||||
llvm_util::time_trace_profiler_finish(&file_name);
|
llvm_util::time_trace_profiler_finish(&file_name);
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
Ok((codegen_results, work_products))
|
Ok((codegen_results, work_products))
|
||||||
}
|
}
|
||||||
|
@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||||||
total_codegen_time,
|
total_codegen_time,
|
||||||
start_rss.unwrap(),
|
start_rss.unwrap(),
|
||||||
end_rss,
|
end_rss,
|
||||||
|
tcx.sess.opts.unstable_opts.time_passes_format,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ rustc-hash = "1.1.0"
|
|||||||
rustc_index = { path = "../rustc_index", package = "rustc_index" }
|
rustc_index = { path = "../rustc_index", package = "rustc_index" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_serialize = { path = "../rustc_serialize" }
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
|
serde_json = "1.0.59"
|
||||||
smallvec = { version = "1.8.1", features = [
|
smallvec = { version = "1.8.1", features = [
|
||||||
"const_generics",
|
"const_generics",
|
||||||
"union",
|
"union",
|
||||||
|
@ -56,7 +56,7 @@ fn test_three_sccs() {
|
|||||||
assert_eq!(sccs.scc(1), 0);
|
assert_eq!(sccs.scc(1), 0);
|
||||||
assert_eq!(sccs.scc(2), 0);
|
assert_eq!(sccs.scc(2), 0);
|
||||||
assert_eq!(sccs.scc(3), 2);
|
assert_eq!(sccs.scc(3), 2);
|
||||||
assert_eq!(sccs.successors(0), &[]);
|
assert_eq!(sccs.successors(0), &[] as &[usize]);
|
||||||
assert_eq!(sccs.successors(1), &[0]);
|
assert_eq!(sccs.successors(1), &[0]);
|
||||||
assert_eq!(sccs.successors(2), &[0]);
|
assert_eq!(sccs.successors(2), &[0]);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ fn test_find_state_2() {
|
|||||||
assert_eq!(sccs.scc(2), 0);
|
assert_eq!(sccs.scc(2), 0);
|
||||||
assert_eq!(sccs.scc(3), 0);
|
assert_eq!(sccs.scc(3), 0);
|
||||||
assert_eq!(sccs.scc(4), 0);
|
assert_eq!(sccs.scc(4), 0);
|
||||||
assert_eq!(sccs.successors(0), &[]);
|
assert_eq!(sccs.successors(0), &[] as &[usize]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -138,7 +138,7 @@ fn test_find_state_3() {
|
|||||||
assert_eq!(sccs.scc(3), 0);
|
assert_eq!(sccs.scc(3), 0);
|
||||||
assert_eq!(sccs.scc(4), 0);
|
assert_eq!(sccs.scc(4), 0);
|
||||||
assert_eq!(sccs.scc(5), 1);
|
assert_eq!(sccs.scc(5), 1);
|
||||||
assert_eq!(sccs.successors(0), &[]);
|
assert_eq!(sccs.successors(0), &[] as &[usize]);
|
||||||
assert_eq!(sccs.successors(1), &[0]);
|
assert_eq!(sccs.successors(1), &[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,11 +27,11 @@ fn successors() {
|
|||||||
let graph = create_graph();
|
let graph = create_graph();
|
||||||
assert_eq!(graph.successors(0), &[1]);
|
assert_eq!(graph.successors(0), &[1]);
|
||||||
assert_eq!(graph.successors(1), &[2, 3]);
|
assert_eq!(graph.successors(1), &[2, 3]);
|
||||||
assert_eq!(graph.successors(2), &[]);
|
assert_eq!(graph.successors(2), &[] as &[usize]);
|
||||||
assert_eq!(graph.successors(3), &[4]);
|
assert_eq!(graph.successors(3), &[4]);
|
||||||
assert_eq!(graph.successors(4), &[]);
|
assert_eq!(graph.successors(4), &[] as &[usize]);
|
||||||
assert_eq!(graph.successors(5), &[1]);
|
assert_eq!(graph.successors(5), &[1]);
|
||||||
assert_eq!(graph.successors(6), &[]);
|
assert_eq!(graph.successors(6), &[] as &[usize]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
|
|||||||
pub use measureme::EventId;
|
pub use measureme::EventId;
|
||||||
use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
|
use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use serde_json::json;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
|
|||||||
/// Something that uniquely identifies a query invocation.
|
/// Something that uniquely identifies a query invocation.
|
||||||
pub struct QueryInvocationId(pub u32);
|
pub struct QueryInvocationId(pub u32);
|
||||||
|
|
||||||
|
/// Which format to use for `-Z time-passes`
|
||||||
|
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||||
|
pub enum TimePassesFormat {
|
||||||
|
/// Emit human readable text
|
||||||
|
Text,
|
||||||
|
/// Emit structured JSON
|
||||||
|
Json,
|
||||||
|
}
|
||||||
|
|
||||||
/// A reference to the SelfProfiler. It can be cloned and sent across thread
|
/// A reference to the SelfProfiler. It can be cloned and sent across thread
|
||||||
/// boundaries at will.
|
/// boundaries at will.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
|
|||||||
// actually enabled.
|
// actually enabled.
|
||||||
event_filter_mask: EventFilter,
|
event_filter_mask: EventFilter,
|
||||||
|
|
||||||
// Print verbose generic activities to stderr?
|
// Print verbose generic activities to stderr.
|
||||||
print_verbose_generic_activities: bool,
|
print_verbose_generic_activities: Option<TimePassesFormat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelfProfilerRef {
|
impl SelfProfilerRef {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
profiler: Option<Arc<SelfProfiler>>,
|
profiler: Option<Arc<SelfProfiler>>,
|
||||||
print_verbose_generic_activities: bool,
|
print_verbose_generic_activities: Option<TimePassesFormat>,
|
||||||
) -> SelfProfilerRef {
|
) -> SelfProfilerRef {
|
||||||
// If there is no SelfProfiler then the filter mask is set to NONE,
|
// If there is no SelfProfiler then the filter mask is set to NONE,
|
||||||
// ensuring that nothing ever tries to actually access it.
|
// ensuring that nothing ever tries to actually access it.
|
||||||
@ -207,9 +217,10 @@ impl SelfProfilerRef {
|
|||||||
/// a measureme event, "verbose" generic activities also print a timing entry to
|
/// a measureme event, "verbose" generic activities also print a timing entry to
|
||||||
/// stderr if the compiler is invoked with -Ztime-passes.
|
/// stderr if the compiler is invoked with -Ztime-passes.
|
||||||
pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
|
pub fn verbose_generic_activity(&self, event_label: &'static str) -> VerboseTimingGuard<'_> {
|
||||||
let message = self.print_verbose_generic_activities.then(|| event_label.to_owned());
|
let message_and_format =
|
||||||
|
self.print_verbose_generic_activities.map(|format| (event_label.to_owned(), format));
|
||||||
|
|
||||||
VerboseTimingGuard::start(message, self.generic_activity(event_label))
|
VerboseTimingGuard::start(message_and_format, self.generic_activity(event_label))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `verbose_generic_activity`, but with an extra arg.
|
/// Like `verbose_generic_activity`, but with an extra arg.
|
||||||
@ -221,11 +232,14 @@ impl SelfProfilerRef {
|
|||||||
where
|
where
|
||||||
A: Borrow<str> + Into<String>,
|
A: Borrow<str> + Into<String>,
|
||||||
{
|
{
|
||||||
let message = self
|
let message_and_format = self
|
||||||
.print_verbose_generic_activities
|
.print_verbose_generic_activities
|
||||||
.then(|| format!("{}({})", event_label, event_arg.borrow()));
|
.map(|format| (format!("{}({})", event_label, event_arg.borrow()), format));
|
||||||
|
|
||||||
VerboseTimingGuard::start(message, self.generic_activity_with_arg(event_label, event_arg))
|
VerboseTimingGuard::start(
|
||||||
|
message_and_format,
|
||||||
|
self.generic_activity_with_arg(event_label, event_arg),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start profiling a generic activity. Profiling continues until the
|
/// Start profiling a generic activity. Profiling continues until the
|
||||||
@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VerboseInfo {
|
||||||
|
start_time: Instant,
|
||||||
|
start_rss: Option<usize>,
|
||||||
|
message: String,
|
||||||
|
format: TimePassesFormat,
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct VerboseTimingGuard<'a> {
|
pub struct VerboseTimingGuard<'a> {
|
||||||
start_and_message: Option<(Instant, Option<usize>, String)>,
|
info: Option<VerboseInfo>,
|
||||||
_guard: TimingGuard<'a>,
|
_guard: TimingGuard<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VerboseTimingGuard<'a> {
|
impl<'a> VerboseTimingGuard<'a> {
|
||||||
pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self {
|
pub fn start(
|
||||||
|
message_and_format: Option<(String, TimePassesFormat)>,
|
||||||
|
_guard: TimingGuard<'a>,
|
||||||
|
) -> Self {
|
||||||
VerboseTimingGuard {
|
VerboseTimingGuard {
|
||||||
_guard,
|
_guard,
|
||||||
start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)),
|
info: message_and_format.map(|(message, format)| VerboseInfo {
|
||||||
|
start_time: Instant::now(),
|
||||||
|
start_rss: get_resident_set_size(),
|
||||||
|
message,
|
||||||
|
format,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -726,10 +755,10 @@ impl<'a> VerboseTimingGuard<'a> {
|
|||||||
|
|
||||||
impl Drop for VerboseTimingGuard<'_> {
|
impl Drop for VerboseTimingGuard<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some((start_time, start_rss, ref message)) = self.start_and_message {
|
if let Some(info) = &self.info {
|
||||||
let end_rss = get_resident_set_size();
|
let end_rss = get_resident_set_size();
|
||||||
let dur = start_time.elapsed();
|
let dur = info.start_time.elapsed();
|
||||||
print_time_passes_entry(message, dur, start_rss, end_rss);
|
print_time_passes_entry(&info.message, dur, info.start_rss, end_rss, info.format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -739,7 +768,22 @@ pub fn print_time_passes_entry(
|
|||||||
dur: Duration,
|
dur: Duration,
|
||||||
start_rss: Option<usize>,
|
start_rss: Option<usize>,
|
||||||
end_rss: Option<usize>,
|
end_rss: Option<usize>,
|
||||||
|
format: TimePassesFormat,
|
||||||
) {
|
) {
|
||||||
|
match format {
|
||||||
|
TimePassesFormat::Json => {
|
||||||
|
let json = json!({
|
||||||
|
"pass": what,
|
||||||
|
"time": dur.as_secs_f64(),
|
||||||
|
"rss_start": start_rss,
|
||||||
|
"rss_end": end_rss,
|
||||||
|
});
|
||||||
|
eprintln!("time: {}", json.to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TimePassesFormat::Text => (),
|
||||||
|
}
|
||||||
|
|
||||||
// Print the pass if its duration is greater than 5 ms, or it changed the
|
// Print the pass if its duration is greater than 5 ms, or it changed the
|
||||||
// measured RSS.
|
// measured RSS.
|
||||||
let is_notable = || {
|
let is_notable = || {
|
||||||
|
@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin;
|
|||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
|
use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
|
||||||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
use rustc_data_structures::profiling::{
|
||||||
|
get_resident_set_size, print_time_passes_entry, TimePassesFormat,
|
||||||
|
};
|
||||||
use rustc_data_structures::sync::SeqCst;
|
use rustc_data_structures::sync::SeqCst;
|
||||||
use rustc_errors::registry::{InvalidErrorCode, Registry};
|
use rustc_errors::registry::{InvalidErrorCode, Registry};
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
@ -161,7 +163,7 @@ pub trait Callbacks {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TimePassesCallbacks {
|
pub struct TimePassesCallbacks {
|
||||||
time_passes: bool,
|
time_passes: Option<TimePassesFormat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Callbacks for TimePassesCallbacks {
|
impl Callbacks for TimePassesCallbacks {
|
||||||
@ -171,7 +173,8 @@ impl Callbacks for TimePassesCallbacks {
|
|||||||
// If a --print=... option has been given, we don't print the "total"
|
// If a --print=... option has been given, we don't print the "total"
|
||||||
// time because it will mess up the --print output. See #64339.
|
// time because it will mess up the --print output. See #64339.
|
||||||
//
|
//
|
||||||
self.time_passes = config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes;
|
self.time_passes = (config.opts.prints.is_empty() && config.opts.unstable_opts.time_passes)
|
||||||
|
.then(|| config.opts.unstable_opts.time_passes_format);
|
||||||
config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
|
config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1354,9 +1357,9 @@ pub fn main() -> ! {
|
|||||||
RunCompiler::new(&args, &mut callbacks).run()
|
RunCompiler::new(&args, &mut callbacks).run()
|
||||||
});
|
});
|
||||||
|
|
||||||
if callbacks.time_passes {
|
if let Some(format) = callbacks.time_passes {
|
||||||
let end_rss = get_resident_set_size();
|
let end_rss = get_resident_set_size();
|
||||||
print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
|
print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
process::exit(exit_code)
|
process::exit(exit_code)
|
||||||
|
@ -160,6 +160,8 @@ declare_features! (
|
|||||||
(active, intrinsics, "1.0.0", None, None),
|
(active, intrinsics, "1.0.0", None, None),
|
||||||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||||
(active, lang_items, "1.0.0", None, None),
|
(active, lang_items, "1.0.0", None, None),
|
||||||
|
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
|
||||||
|
(active, link_cfg, "1.14.0", None, None),
|
||||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||||
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
|
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
|
||||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||||
@ -432,8 +434,6 @@ declare_features! (
|
|||||||
(active, large_assignments, "1.52.0", Some(83518), None),
|
(active, large_assignments, "1.52.0", Some(83518), None),
|
||||||
/// Allows `if/while p && let q = r && ...` chains.
|
/// Allows `if/while p && let q = r && ...` chains.
|
||||||
(active, let_chains, "1.37.0", Some(53667), None),
|
(active, let_chains, "1.37.0", Some(53667), None),
|
||||||
/// Allows `#[link(..., cfg(..))]`.
|
|
||||||
(active, link_cfg, "1.14.0", Some(37406), None),
|
|
||||||
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
|
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
|
||||||
(active, lint_reasons, "1.31.0", Some(54503), None),
|
(active, lint_reasons, "1.31.0", Some(54503), None),
|
||||||
/// Give access to additional metadata about declarative macro meta-variables.
|
/// Give access to additional metadata about declarative macro meta-variables.
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
#![feature(absolute_path)]
|
||||||
#![deny(rustc::untranslatable_diagnostic)]
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{absolute, Path, PathBuf};
|
||||||
|
|
||||||
// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
|
// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
|
||||||
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
|
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
|
||||||
@ -91,3 +92,8 @@ pub fn path_to_c_string(p: &Path) -> CString {
|
|||||||
pub fn path_to_c_string(p: &Path) -> CString {
|
pub fn path_to_c_string(p: &Path) -> CString {
|
||||||
CString::new(p.to_str().unwrap()).unwrap()
|
CString::new(p.to_str().unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
|
||||||
|
fs::canonicalize(&path).or_else(|_| absolute(&path))
|
||||||
|
}
|
||||||
|
@ -133,8 +133,8 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
|
|||||||
check_impl(tcx, impl_def_id, trait_ref);
|
check_impl(tcx, impl_def_id, trait_ref);
|
||||||
check_object_overlap(tcx, impl_def_id, trait_ref);
|
check_object_overlap(tcx, impl_def_id, trait_ref);
|
||||||
|
|
||||||
tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id));
|
unsafety::check_item(tcx, impl_def_id);
|
||||||
tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id));
|
tcx.ensure().orphan_check_impl(impl_def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
builtin::check_trait(tcx, def_id);
|
builtin::check_trait(tcx, def_id);
|
||||||
|
@ -108,7 +108,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||||||
use rustc_data_structures::svh::Svh;
|
use rustc_data_structures::svh::Svh;
|
||||||
use rustc_data_structures::{base_n, flock};
|
use rustc_data_structures::{base_n, flock};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_fs_util::{link_or_copy, LinkOrCopy};
|
use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
|
||||||
use rustc_session::{Session, StableCrateId};
|
use rustc_session::{Session, StableCrateId};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ pub fn prepare_session_directory(
|
|||||||
// because, on windows, long paths can cause problems;
|
// because, on windows, long paths can cause problems;
|
||||||
// canonicalization inserts this weird prefix that makes windows
|
// canonicalization inserts this weird prefix that makes windows
|
||||||
// tolerate long paths.
|
// tolerate long paths.
|
||||||
let crate_dir = match crate_dir.canonicalize() {
|
let crate_dir = match try_canonicalize(&crate_dir) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
|
return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
|
||||||
@ -867,7 +867,7 @@ fn all_except_most_recent(
|
|||||||
/// before passing it to std::fs::remove_dir_all(). This will convert the path
|
/// before passing it to std::fs::remove_dir_all(). This will convert the path
|
||||||
/// into the '\\?\' format, which supports much longer paths.
|
/// into the '\\?\' format, which supports much longer paths.
|
||||||
fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
|
fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
|
||||||
let canonicalized = match std_fs::canonicalize(p) {
|
let canonicalized = match try_canonicalize(p) {
|
||||||
Ok(canonicalized) => canonicalized,
|
Ok(canonicalized) => canonicalized,
|
||||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
@ -877,7 +877,7 @@ fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn safe_remove_file(p: &Path) -> io::Result<()> {
|
fn safe_remove_file(p: &Path) -> io::Result<()> {
|
||||||
let canonicalized = match std_fs::canonicalize(p) {
|
let canonicalized = match try_canonicalize(p) {
|
||||||
Ok(canonicalized) => canonicalized,
|
Ok(canonicalized) => canonicalized,
|
||||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
|
@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" }
|
|||||||
rustc_borrowck = { path = "../rustc_borrowck" }
|
rustc_borrowck = { path = "../rustc_borrowck" }
|
||||||
rustc_builtin_macros = { path = "../rustc_builtin_macros" }
|
rustc_builtin_macros = { path = "../rustc_builtin_macros" }
|
||||||
rustc_expand = { path = "../rustc_expand" }
|
rustc_expand = { path = "../rustc_expand" }
|
||||||
|
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_parse = { path = "../rustc_parse" }
|
rustc_parse = { path = "../rustc_parse" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
|
@ -11,6 +11,7 @@ use rustc_data_structures::steal::Steal;
|
|||||||
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
|
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||||
|
use rustc_fs_util::try_canonicalize;
|
||||||
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
|
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
|
||||||
use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
|
use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
|
||||||
use rustc_metadata::creader::CStore;
|
use rustc_metadata::creader::CStore;
|
||||||
@ -408,12 +409,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
|
fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
|
||||||
let input_path = input_path.canonicalize().ok();
|
let input_path = try_canonicalize(input_path).ok();
|
||||||
if input_path.is_none() {
|
if input_path.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let check = |output_path: &PathBuf| {
|
let check = |output_path: &PathBuf| {
|
||||||
if output_path.canonicalize().ok() == input_path { Some(()) } else { None }
|
if try_canonicalize(output_path).ok() == input_path { Some(()) } else { None }
|
||||||
};
|
};
|
||||||
check_output(output_paths, check).is_some()
|
check_output(output_paths, check).is_some()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
use crate::interface::parse_cfgspecs;
|
use crate::interface::parse_cfgspecs;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_data_structures::profiling::TimePassesFormat;
|
||||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||||
use rustc_session::config::rustc_optgroups;
|
use rustc_session::config::rustc_optgroups;
|
||||||
use rustc_session::config::Input;
|
use rustc_session::config::Input;
|
||||||
@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() {
|
|||||||
untracked!(threads, 99);
|
untracked!(threads, 99);
|
||||||
untracked!(time_llvm_passes, true);
|
untracked!(time_llvm_passes, true);
|
||||||
untracked!(time_passes, true);
|
untracked!(time_passes, true);
|
||||||
|
untracked!(time_passes_format, TimePassesFormat::Json);
|
||||||
untracked!(trace_macros, true);
|
untracked!(trace_macros, true);
|
||||||
untracked!(track_diagnostics, true);
|
untracked!(track_diagnostics, true);
|
||||||
untracked!(trim_diagnostic_paths, false);
|
untracked!(trim_diagnostic_paths, false);
|
||||||
|
@ -508,6 +508,3 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
|
|||||||
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
|
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
|
||||||
|
|
||||||
lint_opaque_hidden_inferred_bound_sugg = add this bound
|
lint_opaque_hidden_inferred_bound_sugg = add this bound
|
||||||
|
|
||||||
lint_useless_anonymous_reexport = useless anonymous re-export
|
|
||||||
.note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}`
|
|
||||||
|
@ -910,6 +910,10 @@ pub trait LintContext: Sized {
|
|||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
BuiltinLintDiagnostics::AmbiguousGlobReexports { name, namespace, first_reexport_span, duplicate_reexport_span } => {
|
||||||
|
db.span_label(first_reexport_span, format!("the name `{}` in the {} namespace is first re-exported here", name, namespace));
|
||||||
|
db.span_label(duplicate_reexport_span, format!("but the name `{}` in the {} namespace is also re-exported here", name, namespace));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Rewrap `db`, and pass control to the user.
|
// Rewrap `db`, and pass control to the user.
|
||||||
decorate(db)
|
decorate(db)
|
||||||
|
@ -74,7 +74,6 @@ mod opaque_hidden_inferred_bound;
|
|||||||
mod pass_by_value;
|
mod pass_by_value;
|
||||||
mod passes;
|
mod passes;
|
||||||
mod redundant_semicolon;
|
mod redundant_semicolon;
|
||||||
mod reexports;
|
|
||||||
mod traits;
|
mod traits;
|
||||||
mod types;
|
mod types;
|
||||||
mod unused;
|
mod unused;
|
||||||
@ -112,7 +111,6 @@ use noop_method_call::*;
|
|||||||
use opaque_hidden_inferred_bound::*;
|
use opaque_hidden_inferred_bound::*;
|
||||||
use pass_by_value::*;
|
use pass_by_value::*;
|
||||||
use redundant_semicolon::*;
|
use redundant_semicolon::*;
|
||||||
use reexports::*;
|
|
||||||
use traits::*;
|
use traits::*;
|
||||||
use types::*;
|
use types::*;
|
||||||
use unused::*;
|
use unused::*;
|
||||||
@ -244,7 +242,6 @@ late_lint_methods!(
|
|||||||
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||||
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
||||||
MapUnitFn: MapUnitFn,
|
MapUnitFn: MapUnitFn,
|
||||||
UselessAnonymousReexport: UselessAnonymousReexport,
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -1528,11 +1528,3 @@ pub struct UnusedAllocationDiag;
|
|||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_unused_allocation_mut)]
|
#[diag(lint_unused_allocation_mut)]
|
||||||
pub struct UnusedAllocationMutDiag;
|
pub struct UnusedAllocationMutDiag;
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(lint_useless_anonymous_reexport)]
|
|
||||||
#[note]
|
|
||||||
pub struct UselessAnonymousReexportDiag {
|
|
||||||
pub article: &'static str,
|
|
||||||
pub desc: &'static str,
|
|
||||||
}
|
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
use crate::lints::UselessAnonymousReexportDiag;
|
|
||||||
use crate::{LateContext, LateLintPass, LintContext};
|
|
||||||
use rustc_hir::def::DefKind;
|
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
use rustc_hir::{Item, ItemKind, UseKind};
|
|
||||||
use rustc_middle::ty::Visibility;
|
|
||||||
use rustc_span::symbol::kw;
|
|
||||||
use rustc_span::Span;
|
|
||||||
|
|
||||||
declare_lint! {
|
|
||||||
/// The `useless_anonymous_reexport` lint checks if anonymous re-exports
|
|
||||||
/// are re-exports of traits.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
///
|
|
||||||
/// ```rust,compile_fail
|
|
||||||
/// #![deny(useless_anonymous_reexport)]
|
|
||||||
///
|
|
||||||
/// mod sub {
|
|
||||||
/// pub struct Bar;
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// pub use self::sub::Bar as _;
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// {{produces}}
|
|
||||||
///
|
|
||||||
/// ### Explanation
|
|
||||||
///
|
|
||||||
/// Anonymous re-exports are only useful if it's a re-export of a trait
|
|
||||||
/// in case you want to give access to it. If you re-export any other kind,
|
|
||||||
/// you won't be able to use it since its name won't be accessible.
|
|
||||||
pub USELESS_ANONYMOUS_REEXPORT,
|
|
||||||
Warn,
|
|
||||||
"useless anonymous re-export"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
|
|
||||||
|
|
||||||
fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
|
|
||||||
let article = cx.tcx.def_descr_article(def_id);
|
|
||||||
let desc = cx.tcx.def_descr(def_id);
|
|
||||||
cx.emit_spanned_lint(
|
|
||||||
USELESS_ANONYMOUS_REEXPORT,
|
|
||||||
span,
|
|
||||||
UselessAnonymousReexportDiag { article, desc },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
|
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
|
||||||
if let ItemKind::Use(path, kind) = item.kind &&
|
|
||||||
!matches!(kind, UseKind::Glob) &&
|
|
||||||
item.ident.name == kw::Underscore &&
|
|
||||||
// We only want re-exports. If it's just a `use X;`, then we ignore it.
|
|
||||||
match cx.tcx.local_visibility(item.owner_id.def_id) {
|
|
||||||
Visibility::Public => true,
|
|
||||||
Visibility::Restricted(level) => {
|
|
||||||
level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
|
|
||||||
match cx.tcx.def_kind(def_id) {
|
|
||||||
DefKind::Trait | DefKind::TraitAlias => {}
|
|
||||||
DefKind::TyAlias => {
|
|
||||||
let ty = cx.tcx.type_of(def_id);
|
|
||||||
if !ty.0.is_trait() {
|
|
||||||
emit_err(cx, item.span, def_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
emit_err(cx, item.span, def_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3230,6 +3230,45 @@ declare_lint! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `ambiguous_glob_reexports` lint detects cases where names re-exported via globs
|
||||||
|
/// collide. Downstream users trying to use the same name re-exported from multiple globs
|
||||||
|
/// will receive a warning pointing out redefinition of the same name.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,compile_fail
|
||||||
|
/// #![deny(ambiguous_glob_reexports)]
|
||||||
|
/// pub mod foo {
|
||||||
|
/// pub type X = u8;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// pub mod bar {
|
||||||
|
/// pub type Y = u8;
|
||||||
|
/// pub type X = u8;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// pub use foo::*;
|
||||||
|
/// pub use bar::*;
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// pub fn main() {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// This was previously accepted but it could silently break a crate's downstream users code.
|
||||||
|
/// For example, if `foo::*` and `bar::*` were re-exported before `bar::X` was added to the
|
||||||
|
/// re-exports, down stream users could use `this_crate::X` without problems. However, adding
|
||||||
|
/// `bar::X` would cause compilation errors in downstream crates because `X` is defined
|
||||||
|
/// multiple times in the same namespace of `this_crate`.
|
||||||
|
pub AMBIGUOUS_GLOB_REEXPORTS,
|
||||||
|
Warn,
|
||||||
|
"ambiguous glob re-exports",
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// that are used by other parts of the compiler.
|
/// that are used by other parts of the compiler.
|
||||||
@ -3337,6 +3376,7 @@ declare_lint_pass! {
|
|||||||
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
||||||
IMPLIED_BOUNDS_ENTAILMENT,
|
IMPLIED_BOUNDS_ENTAILMENT,
|
||||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||||
|
AMBIGUOUS_GLOB_REEXPORTS,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3968,14 +4008,9 @@ declare_lint! {
|
|||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust,ignore (need FFI)
|
/// ```rust
|
||||||
/// #![feature(ffi_unwind_calls)]
|
|
||||||
/// #![feature(c_unwind)]
|
/// #![feature(c_unwind)]
|
||||||
///
|
/// #![warn(ffi_unwind_calls)]
|
||||||
/// # mod impl {
|
|
||||||
/// # #[no_mangle]
|
|
||||||
/// # pub fn "C-unwind" fn foo() {}
|
|
||||||
/// # }
|
|
||||||
///
|
///
|
||||||
/// extern "C-unwind" {
|
/// extern "C-unwind" {
|
||||||
/// fn foo();
|
/// fn foo();
|
||||||
|
@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics {
|
|||||||
vis_span: Span,
|
vis_span: Span,
|
||||||
ident_span: Span,
|
ident_span: Span,
|
||||||
},
|
},
|
||||||
|
AmbiguousGlobReexports {
|
||||||
|
/// The name for which collision(s) have occurred.
|
||||||
|
name: String,
|
||||||
|
/// The name space for whihc the collision(s) occurred in.
|
||||||
|
namespace: String,
|
||||||
|
/// Span where the name is first re-exported.
|
||||||
|
first_reexport_span: Span,
|
||||||
|
/// Span where the same name is also re-exported.
|
||||||
|
duplicate_reexport_span: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lints that are buffered up early on in the `Session` before the
|
/// Lints that are buffered up early on in the `Session` before the
|
||||||
|
@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
|
|||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
|
@ -222,6 +222,7 @@ use rustc_data_structures::owning_ref::OwningRef;
|
|||||||
use rustc_data_structures::svh::Svh;
|
use rustc_data_structures::svh::Svh;
|
||||||
use rustc_data_structures::sync::MetadataRef;
|
use rustc_data_structures::sync::MetadataRef;
|
||||||
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
|
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
|
||||||
|
use rustc_fs_util::try_canonicalize;
|
||||||
use rustc_session::config::{self, CrateType};
|
use rustc_session::config::{self, CrateType};
|
||||||
use rustc_session::cstore::{CrateSource, MetadataLoader};
|
use rustc_session::cstore::{CrateSource, MetadataLoader};
|
||||||
use rustc_session::filesearch::FileSearch;
|
use rustc_session::filesearch::FileSearch;
|
||||||
@ -236,7 +237,7 @@ use snap::read::FrameDecoder;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::{Read, Result as IoResult, Write};
|
use std::io::{Read, Result as IoResult, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{cmp, fmt, fs};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct CrateLocator<'a> {
|
pub(crate) struct CrateLocator<'a> {
|
||||||
@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> {
|
|||||||
info!("lib candidate: {}", spf.path.display());
|
info!("lib candidate: {}", spf.path.display());
|
||||||
|
|
||||||
let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
|
let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
|
||||||
let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
|
let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
|
||||||
if seen_paths.contains(&path) {
|
if seen_paths.contains(&path) {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> {
|
|||||||
// as well.
|
// as well.
|
||||||
if let Some((prev, _)) = &ret {
|
if let Some((prev, _)) = &ret {
|
||||||
let sysroot = self.sysroot;
|
let sysroot = self.sysroot;
|
||||||
let sysroot = sysroot.canonicalize().unwrap_or_else(|_| sysroot.to_path_buf());
|
let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
|
||||||
if prev.starts_with(&sysroot) {
|
if prev.starts_with(&sysroot) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor};
|
|||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::{pluralize, MultiSpan};
|
use rustc_errors::{pluralize, MultiSpan};
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
|
use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
struct UnusedImport<'a> {
|
struct UnusedImport<'a> {
|
||||||
@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|||||||
base_use_tree: Option<&'a ast::UseTree>,
|
base_use_tree: Option<&'a ast::UseTree>,
|
||||||
base_id: ast::NodeId,
|
base_id: ast::NodeId,
|
||||||
item_span: Span,
|
item_span: Span,
|
||||||
|
base_use_is_pub: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExternCrateToLint {
|
struct ExternCrateToLint {
|
||||||
@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|||||||
unused: Default::default(),
|
unused: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_import_as_underscore(&mut self, item: &ast::UseTree, id: ast::NodeId) {
|
||||||
|
match item.kind {
|
||||||
|
ast::UseTreeKind::Simple(Some(ident)) => {
|
||||||
|
if ident.name == kw::Underscore
|
||||||
|
&& !self
|
||||||
|
.r
|
||||||
|
.import_res_map
|
||||||
|
.get(&id)
|
||||||
|
.map(|per_ns| {
|
||||||
|
per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
|
||||||
|
matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
self.unused_import(self.base_id).add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_imports_as_underscore(&mut self, items: &[(ast::UseTree, ast::NodeId)]) {
|
||||||
|
for (item, id) in items {
|
||||||
|
self.check_import_as_underscore(item, *id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
||||||
@ -119,7 +150,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|||||||
// whether they're used or not. Also ignore imports with a dummy span
|
// whether they're used or not. Also ignore imports with a dummy span
|
||||||
// because this means that they were generated in some fashion by the
|
// because this means that they were generated in some fashion by the
|
||||||
// compiler and we don't need to consider them.
|
// compiler and we don't need to consider them.
|
||||||
ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
|
ast::ItemKind::Use(..) if item.span.is_dummy() => return,
|
||||||
|
ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(),
|
||||||
ast::ItemKind::ExternCrate(orig_name) => {
|
ast::ItemKind::ExternCrate(orig_name) => {
|
||||||
self.extern_crate_items.push(ExternCrateToLint {
|
self.extern_crate_items.push(ExternCrateToLint {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
@ -146,6 +178,11 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|||||||
self.base_use_tree = Some(use_tree);
|
self.base_use_tree = Some(use_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.base_use_is_pub {
|
||||||
|
self.check_import_as_underscore(use_tree, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
|
||||||
if items.is_empty() {
|
if items.is_empty() {
|
||||||
self.unused_import(self.base_id).add(id);
|
self.unused_import(self.base_id).add(id);
|
||||||
@ -300,6 +337,7 @@ impl Resolver<'_, '_> {
|
|||||||
base_use_tree: None,
|
base_use_tree: None,
|
||||||
base_id: ast::DUMMY_NODE_ID,
|
base_id: ast::DUMMY_NODE_ID,
|
||||||
item_span: DUMMY_SP,
|
item_span: DUMMY_SP,
|
||||||
|
base_use_is_pub: false,
|
||||||
};
|
};
|
||||||
visit::walk_crate(&mut visitor, krate);
|
visit::walk_crate(&mut visitor, krate);
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use rustc_ast::visit;
|
|||||||
use rustc_ast::visit::Visitor;
|
use rustc_ast::visit::Visitor;
|
||||||
use rustc_ast::Crate;
|
use rustc_ast::Crate;
|
||||||
use rustc_ast::EnumDef;
|
use rustc_ast::EnumDef;
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||||
@ -70,11 +71,11 @@ impl Resolver<'_, '_> {
|
|||||||
impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
||||||
/// Fills the `Resolver::effective_visibilities` table with public & exported items
|
/// Fills the `Resolver::effective_visibilities` table with public & exported items
|
||||||
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
|
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
|
||||||
/// need access to a TyCtxt for that.
|
/// need access to a TyCtxt for that. Returns the set of ambiguous re-exports.
|
||||||
pub(crate) fn compute_effective_visibilities<'c>(
|
pub(crate) fn compute_effective_visibilities<'c>(
|
||||||
r: &'r mut Resolver<'a, 'tcx>,
|
r: &'r mut Resolver<'a, 'tcx>,
|
||||||
krate: &'c Crate,
|
krate: &'c Crate,
|
||||||
) {
|
) -> FxHashSet<Interned<'a, NameBinding<'a>>> {
|
||||||
let mut visitor = EffectiveVisibilitiesVisitor {
|
let mut visitor = EffectiveVisibilitiesVisitor {
|
||||||
r,
|
r,
|
||||||
def_effective_visibilities: Default::default(),
|
def_effective_visibilities: Default::default(),
|
||||||
@ -93,18 +94,26 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
visitor.r.effective_visibilities = visitor.def_effective_visibilities;
|
visitor.r.effective_visibilities = visitor.def_effective_visibilities;
|
||||||
|
|
||||||
|
let mut exported_ambiguities = FxHashSet::default();
|
||||||
|
|
||||||
// Update visibilities for import def ids. These are not used during the
|
// Update visibilities for import def ids. These are not used during the
|
||||||
// `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
|
// `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
|
||||||
// information, but are used by later passes. Effective visibility of an import def id
|
// information, but are used by later passes. Effective visibility of an import def id
|
||||||
// is the maximum value among visibilities of bindings corresponding to that def id.
|
// is the maximum value among visibilities of bindings corresponding to that def id.
|
||||||
for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
|
for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
|
||||||
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
|
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
|
||||||
if let Some(node_id) = import.id() {
|
if !binding.is_ambiguity() {
|
||||||
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
|
if let Some(node_id) = import.id() {
|
||||||
|
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
|
||||||
|
}
|
||||||
|
} else if binding.ambiguity.is_some() && eff_vis.is_public_at_level(Level::Reexported) {
|
||||||
|
exported_ambiguities.insert(*binding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
|
info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
|
||||||
|
|
||||||
|
exported_ambiguities
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update effective visibilities of bindings in the given module,
|
/// Update effective visibilities of bindings in the given module,
|
||||||
@ -115,21 +124,44 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
|||||||
let resolutions = self.r.resolutions(module);
|
let resolutions = self.r.resolutions(module);
|
||||||
|
|
||||||
for (_, name_resolution) in resolutions.borrow().iter() {
|
for (_, name_resolution) in resolutions.borrow().iter() {
|
||||||
if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
|
if let Some(mut binding) = name_resolution.borrow().binding() {
|
||||||
// Set the given effective visibility level to `Level::Direct` and
|
if !binding.is_ambiguity() {
|
||||||
// sets the rest of the `use` chain to `Level::Reexported` until
|
// Set the given effective visibility level to `Level::Direct` and
|
||||||
// we hit the actual exported item.
|
// sets the rest of the `use` chain to `Level::Reexported` until
|
||||||
let mut parent_id = ParentId::Def(module_id);
|
// we hit the actual exported item.
|
||||||
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
|
let mut parent_id = ParentId::Def(module_id);
|
||||||
let binding_id = ImportId::new_unchecked(binding);
|
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
|
||||||
self.update_import(binding_id, parent_id);
|
{
|
||||||
|
let binding_id = ImportId::new_unchecked(binding);
|
||||||
|
self.update_import(binding_id, parent_id);
|
||||||
|
|
||||||
parent_id = ParentId::Import(binding_id);
|
parent_id = ParentId::Import(binding_id);
|
||||||
binding = nested_binding;
|
binding = nested_binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
|
if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
|
||||||
self.update_def(def_id, binding.vis.expect_local(), parent_id);
|
self.update_def(def_id, binding.vis.expect_local(), parent_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Put the root ambiguity binding and all reexports leading to it into the
|
||||||
|
// table. They are used by the `ambiguous_glob_reexports` lint. For all
|
||||||
|
// bindings added to the table here `is_ambiguity` returns true.
|
||||||
|
let mut parent_id = ParentId::Def(module_id);
|
||||||
|
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
|
||||||
|
{
|
||||||
|
let binding_id = ImportId::new_unchecked(binding);
|
||||||
|
self.update_import(binding_id, parent_id);
|
||||||
|
|
||||||
|
if binding.ambiguity.is_some() {
|
||||||
|
// Stop at the root ambiguity, further bindings in the chain should not
|
||||||
|
// be reexported because the root ambiguity blocks any access to them.
|
||||||
|
// (Those further bindings are most likely not ambiguities themselves.)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_id = ParentId::Import(binding_id);
|
||||||
|
binding = nested_binding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,9 @@ use rustc_hir::def::{self, DefKind, PartialRes};
|
|||||||
use rustc_middle::metadata::ModChild;
|
use rustc_middle::metadata::ModChild;
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
|
use rustc_session::lint::builtin::{
|
||||||
|
AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
|
||||||
|
};
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::hygiene::LocalExpnId;
|
use rustc_span::hygiene::LocalExpnId;
|
||||||
@ -510,6 +512,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn check_reexport_ambiguities(
|
||||||
|
&mut self,
|
||||||
|
exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
|
||||||
|
) {
|
||||||
|
for module in self.arenas.local_modules().iter() {
|
||||||
|
module.for_each_child(self, |this, ident, ns, binding| {
|
||||||
|
if let NameBindingKind::Import { import, .. } = binding.kind
|
||||||
|
&& let Some((amb_binding, _)) = binding.ambiguity
|
||||||
|
&& binding.res() != Res::Err
|
||||||
|
&& exported_ambiguities.contains(&Interned::new_unchecked(binding))
|
||||||
|
{
|
||||||
|
this.lint_buffer.buffer_lint_with_diagnostic(
|
||||||
|
AMBIGUOUS_GLOB_REEXPORTS,
|
||||||
|
import.root_id,
|
||||||
|
import.root_span,
|
||||||
|
"ambiguous glob re-exports",
|
||||||
|
BuiltinLintDiagnostics::AmbiguousGlobReexports {
|
||||||
|
name: ident.to_string(),
|
||||||
|
namespace: ns.descr().to_string(),
|
||||||
|
first_reexport_span: import.root_span,
|
||||||
|
duplicate_reexport_span: amb_binding.span,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
|
fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
|
||||||
if errors.is_empty() {
|
if errors.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -1475,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||||
self.tcx.sess.time("resolve_crate", || {
|
self.tcx.sess.time("resolve_crate", || {
|
||||||
self.tcx.sess.time("finalize_imports", || self.finalize_imports());
|
self.tcx.sess.time("finalize_imports", || self.finalize_imports());
|
||||||
self.tcx.sess.time("compute_effective_visibilities", || {
|
let exported_ambiguities = self.tcx.sess.time("compute_effective_visibilities", || {
|
||||||
EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
|
EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
|
||||||
});
|
});
|
||||||
|
self.tcx.sess.time("check_reexport_ambiguities", || {
|
||||||
|
self.check_reexport_ambiguities(exported_ambiguities)
|
||||||
|
});
|
||||||
self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
|
self.tcx.sess.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
|
||||||
self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
|
self.tcx.sess.time("late_resolve_crate", || self.late_resolve_crate(krate));
|
||||||
self.tcx.sess.time("resolve_main", || self.resolve_main());
|
self.tcx.sess.time("resolve_main", || self.resolve_main());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! A module for searching for libraries
|
//! A module for searching for libraries
|
||||||
|
|
||||||
|
use rustc_fs_util::try_canonicalize;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -125,7 +126,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
|
|||||||
let target = crate::config::host_triple();
|
let target = crate::config::host_triple();
|
||||||
let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
|
let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
|
||||||
smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
|
smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
|
||||||
let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string()));
|
let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string()));
|
||||||
if let Ok(dll) = path {
|
if let Ok(dll) = path {
|
||||||
// use `parent` twice to chop off the file name and then also the
|
// use `parent` twice to chop off the file name and then also the
|
||||||
// directory containing the dll which should be either `lib` or `bin`.
|
// directory containing the dll which should be either `lib` or `bin`.
|
||||||
@ -160,7 +161,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
|
|||||||
pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
|
pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
|
||||||
// Follow symlinks. If the resolved path is relative, make it absolute.
|
// Follow symlinks. If the resolved path is relative, make it absolute.
|
||||||
fn canonicalize(path: PathBuf) -> PathBuf {
|
fn canonicalize(path: PathBuf) -> PathBuf {
|
||||||
let path = fs::canonicalize(&path).unwrap_or(path);
|
let path = try_canonicalize(&path).unwrap_or(path);
|
||||||
// See comments on this target function, but the gist is that
|
// See comments on this target function, but the gist is that
|
||||||
// gcc chokes on verbatim paths which fs::canonicalize generates
|
// gcc chokes on verbatim paths which fs::canonicalize generates
|
||||||
// so we try to avoid those kinds of paths.
|
// so we try to avoid those kinds of paths.
|
||||||
|
@ -4,6 +4,7 @@ use crate::early_error;
|
|||||||
use crate::lint;
|
use crate::lint;
|
||||||
use crate::search_paths::SearchPath;
|
use crate::search_paths::SearchPath;
|
||||||
use crate::utils::NativeLib;
|
use crate::utils::NativeLib;
|
||||||
|
use rustc_data_structures::profiling::TimePassesFormat;
|
||||||
use rustc_errors::{LanguageIdentifier, TerminalUrl};
|
use rustc_errors::{LanguageIdentifier, TerminalUrl};
|
||||||
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
|
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
@ -365,6 +366,7 @@ mod desc {
|
|||||||
pub const parse_number: &str = "a number";
|
pub const parse_number: &str = "a number";
|
||||||
pub const parse_opt_number: &str = parse_number;
|
pub const parse_opt_number: &str = parse_number;
|
||||||
pub const parse_threads: &str = parse_number;
|
pub const parse_threads: &str = parse_number;
|
||||||
|
pub const parse_time_passes_format: &str = "`text` (default) or `json`";
|
||||||
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
|
||||||
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
|
||||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||||
@ -829,6 +831,21 @@ mod parse {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
|
||||||
|
match v {
|
||||||
|
None => true,
|
||||||
|
Some("json") => {
|
||||||
|
*slot = TimePassesFormat::Json;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some("text") => {
|
||||||
|
*slot = TimePassesFormat::Text;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
|
pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
|
||||||
match v {
|
match v {
|
||||||
None => true,
|
None => true,
|
||||||
@ -1709,6 +1726,8 @@ options! {
|
|||||||
"measure time of each LLVM pass (default: no)"),
|
"measure time of each LLVM pass (default: no)"),
|
||||||
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"measure time of each rustc pass (default: no)"),
|
"measure time of each rustc pass (default: no)"),
|
||||||
|
time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
|
||||||
|
"the format to use for -Z time-passes (`text` (default) or `json`)"),
|
||||||
tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
|
tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
|
||||||
"sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
|
"sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
|
||||||
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
|
#[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
|
||||||
|
@ -1453,7 +1453,10 @@ pub fn build_session(
|
|||||||
CguReuseTracker::new_disabled()
|
CguReuseTracker::new_disabled()
|
||||||
};
|
};
|
||||||
|
|
||||||
let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes);
|
let prof = SelfProfilerRef::new(
|
||||||
|
self_profiler,
|
||||||
|
sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
|
||||||
|
);
|
||||||
|
|
||||||
let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
|
let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
|
||||||
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
|
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||||
|
use rustc_fs_util::try_canonicalize;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
@ -98,7 +99,7 @@ pub struct CanonicalizedPath {
|
|||||||
|
|
||||||
impl CanonicalizedPath {
|
impl CanonicalizedPath {
|
||||||
pub fn new(path: &Path) -> Self {
|
pub fn new(path: &Path) -> Self {
|
||||||
Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() }
|
Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonicalized(&self) -> &PathBuf {
|
pub fn canonicalized(&self) -> &PathBuf {
|
||||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
serde_json = "1.0.59"
|
serde_json = "1.0.59"
|
||||||
|
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||||
rustc_abi = { path = "../rustc_abi" }
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
@ -40,6 +40,7 @@ use crate::json::{Json, ToJson};
|
|||||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||||
use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
|
use rustc_fs_util::try_canonicalize;
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@ -2949,7 +2950,7 @@ impl TargetTriple {
|
|||||||
|
|
||||||
/// Creates a target triple from the passed target path.
|
/// Creates a target triple from the passed target path.
|
||||||
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
|
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
|
||||||
let canonicalized_path = path.canonicalize()?;
|
let canonicalized_path = try_canonicalize(path)?;
|
||||||
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
|
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::InvalidInput,
|
io::ErrorKind::InvalidInput,
|
||||||
|
@ -1356,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
|
||||||
|
let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
|
||||||
|
let sugg_msg = &format!(
|
||||||
|
"consider{} borrowing here",
|
||||||
|
if is_mut { " mutably" } else { "" }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Issue #109436, we need to add parentheses properly for method calls
|
||||||
|
// for example, `foo.into()` should be `(&foo).into()`
|
||||||
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(
|
||||||
|
self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)),
|
||||||
|
) {
|
||||||
|
if snippet == "." {
|
||||||
|
err.multipart_suggestion_verbose(
|
||||||
|
sugg_msg,
|
||||||
|
vec![
|
||||||
|
(span.shrink_to_lo(), format!("({}", sugg_prefix)),
|
||||||
|
(span.shrink_to_hi(), ")".to_string()),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Issue #104961, we need to add parentheses properly for compond expressions
|
// Issue #104961, we need to add parentheses properly for compond expressions
|
||||||
// for example, `x.starts_with("hi".to_string() + "you")`
|
// for example, `x.starts_with("hi".to_string() + "you")`
|
||||||
// should be `x.starts_with(&("hi".to_string() + "you"))`
|
// should be `x.starts_with(&("hi".to_string() + "you"))`
|
||||||
@ -1372,14 +1397,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
|
|
||||||
let span = if needs_parens { span } else { span.shrink_to_lo() };
|
let span = if needs_parens { span } else { span.shrink_to_lo() };
|
||||||
let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
|
|
||||||
let sugg_msg = &format!(
|
|
||||||
"consider{} borrowing here",
|
|
||||||
if is_mut { " mutably" } else { "" }
|
|
||||||
);
|
|
||||||
|
|
||||||
let suggestions = if !needs_parens {
|
let suggestions = if !needs_parens {
|
||||||
vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
|
vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
|
||||||
} else {
|
} else {
|
||||||
|
@ -370,7 +370,7 @@ pub enum ErrorKind {
|
|||||||
|
|
||||||
// "Unusual" error kinds which do not correspond simply to (sets
|
// "Unusual" error kinds which do not correspond simply to (sets
|
||||||
// of) OS error codes, should be added just above this comment.
|
// of) OS error codes, should be added just above this comment.
|
||||||
// `Other` and `Uncategorised` should remain at the end:
|
// `Other` and `Uncategorized` should remain at the end:
|
||||||
//
|
//
|
||||||
/// A custom error that does not fall under any other I/O error kind.
|
/// A custom error that does not fall under any other I/O error kind.
|
||||||
///
|
///
|
||||||
@ -882,6 +882,13 @@ impl Error {
|
|||||||
|
|
||||||
/// Returns the corresponding [`ErrorKind`] for this error.
|
/// Returns the corresponding [`ErrorKind`] for this error.
|
||||||
///
|
///
|
||||||
|
/// This may be a value set by Rust code constructing custom `io::Error`s,
|
||||||
|
/// or if this `io::Error` was sourced from the operating system,
|
||||||
|
/// it will be a value inferred from the system's error encoding.
|
||||||
|
/// See [`last_os_error`] for more details.
|
||||||
|
///
|
||||||
|
/// [`last_os_error`]: Error::last_os_error
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -892,7 +899,8 @@ impl Error {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// // Will print "Uncategorized".
|
/// // As no error has (visibly) occurred, this may print anything!
|
||||||
|
/// // It likely prints a placeholder for unidentified (non-)errors.
|
||||||
/// print_error(Error::last_os_error());
|
/// print_error(Error::last_os_error());
|
||||||
/// // Will print "AddrInUse".
|
/// // Will print "AddrInUse".
|
||||||
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
|
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
|
||||||
|
@ -45,6 +45,36 @@ impl Lint {
|
|||||||
fn check_style(&self) -> Result<(), Box<dyn Error>> {
|
fn check_style(&self) -> Result<(), Box<dyn Error>> {
|
||||||
for &expected in &["### Example", "### Explanation", "{{produces}}"] {
|
for &expected in &["### Example", "### Explanation", "{{produces}}"] {
|
||||||
if expected == "{{produces}}" && self.is_ignored() {
|
if expected == "{{produces}}" && self.is_ignored() {
|
||||||
|
if self.doc_contains("{{produces}}") {
|
||||||
|
return Err(format!(
|
||||||
|
"the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\
|
||||||
|
\n\
|
||||||
|
The documentation generator cannot generate the example output when the \
|
||||||
|
example is ignored.\n\
|
||||||
|
Manually include the sample output below the example. For example:\n\
|
||||||
|
\n\
|
||||||
|
/// ```rust,ignore (needs command line option)\n\
|
||||||
|
/// #[cfg(widnows)]\n\
|
||||||
|
/// fn foo() {{}}\n\
|
||||||
|
/// ```\n\
|
||||||
|
///\n\
|
||||||
|
/// This will produce:\n\
|
||||||
|
/// \n\
|
||||||
|
/// ```text\n\
|
||||||
|
/// warning: unknown condition name used\n\
|
||||||
|
/// --> lint_example.rs:1:7\n\
|
||||||
|
/// |\n\
|
||||||
|
/// 1 | #[cfg(widnows)]\n\
|
||||||
|
/// | ^^^^^^^\n\
|
||||||
|
/// |\n\
|
||||||
|
/// = note: `#[warn(unexpected_cfgs)]` on by default\n\
|
||||||
|
/// ```\n\
|
||||||
|
\n\
|
||||||
|
Replacing the output with the text of the example you \
|
||||||
|
compiled manually yourself.\n\
|
||||||
|
"
|
||||||
|
).into());
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !self.doc_contains(expected) {
|
if !self.doc_contains(expected) {
|
||||||
@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> {
|
|||||||
..,
|
..,
|
||||||
&format!(
|
&format!(
|
||||||
"This will produce:\n\
|
"This will produce:\n\
|
||||||
\n\
|
\n\
|
||||||
```text\n\
|
```text\n\
|
||||||
{}\
|
{}\
|
||||||
```",
|
```",
|
||||||
output
|
output
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -392,37 +422,36 @@ impl<'a> LintExtractor<'a> {
|
|||||||
.filter(|line| line.starts_with('{'))
|
.filter(|line| line.starts_with('{'))
|
||||||
.map(serde_json::from_str)
|
.map(serde_json::from_str)
|
||||||
.collect::<Result<Vec<serde_json::Value>, _>>()?;
|
.collect::<Result<Vec<serde_json::Value>, _>>()?;
|
||||||
match msgs
|
// First try to find the messages with the `code` field set to our lint.
|
||||||
|
let matches: Vec<_> = msgs
|
||||||
.iter()
|
.iter()
|
||||||
.find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
|
.filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
|
||||||
{
|
.map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
|
||||||
Some(msg) => {
|
.collect();
|
||||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
if matches.is_empty() {
|
||||||
Ok(rendered.to_string())
|
// Some lints override their code to something else (E0566).
|
||||||
}
|
// Try to find something that looks like it could be our lint.
|
||||||
None => {
|
let matches: Vec<_> = msgs.iter().filter(|msg|
|
||||||
match msgs.iter().find(
|
matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)))
|
||||||
|msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
|
.map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
|
||||||
) {
|
.collect();
|
||||||
Some(msg) => {
|
if matches.is_empty() {
|
||||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
let rendered: Vec<&str> =
|
||||||
Ok(rendered.to_string())
|
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
|
||||||
}
|
let non_json: Vec<&str> =
|
||||||
None => {
|
stderr.lines().filter(|line| !line.starts_with('{')).collect();
|
||||||
let rendered: Vec<&str> =
|
Err(format!(
|
||||||
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
|
"did not find lint `{}` in output of example, got:\n{}\n{}",
|
||||||
let non_json: Vec<&str> =
|
name,
|
||||||
stderr.lines().filter(|line| !line.starts_with('{')).collect();
|
non_json.join("\n"),
|
||||||
Err(format!(
|
rendered.join("\n")
|
||||||
"did not find lint `{}` in output of example, got:\n{}\n{}",
|
)
|
||||||
name,
|
.into())
|
||||||
non_json.join("\n"),
|
} else {
|
||||||
rendered.join("\n")
|
Ok(matches.join("\n"))
|
||||||
)
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(matches.join("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@
|
|||||||
-Z threads=val -- use a thread pool with N threads
|
-Z threads=val -- use a thread pool with N threads
|
||||||
-Z time-llvm-passes=val -- measure time of each LLVM pass (default: no)
|
-Z time-llvm-passes=val -- measure time of each LLVM pass (default: no)
|
||||||
-Z time-passes=val -- measure time of each rustc pass (default: no)
|
-Z time-passes=val -- measure time of each rustc pass (default: no)
|
||||||
|
-Z time-passes-format=val -- the format to use for -Z time-passes (`text` (default) or `json`)
|
||||||
-Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
|
-Z tiny-const-eval-limit=val -- sets a tiny, non-configurable limit for const eval; useful for compiler tests
|
||||||
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
|
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
|
||||||
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
|
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
|
||||||
|
@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable
|
|||||||
LL | #[link(name = "foo", cfg(foo))]
|
LL | #[link(name = "foo", cfg(foo))]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: see issue #37406 <https://github.com/rust-lang/rust/issues/37406> for more information
|
|
||||||
= help: add `#![feature(link_cfg)]` to the crate attributes to enable
|
= help: add `#![feature(link_cfg)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![allow(ambiguous_glob_reexports)]
|
||||||
|
|
||||||
mod m1 {
|
mod m1 {
|
||||||
pub fn f() {}
|
pub fn f() {}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// run-rustfix
|
// run-rustfix
|
||||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
#![allow(unused, nonstandard_style)]
|
||||||
mod m {
|
mod m {
|
||||||
|
|
||||||
mod p {
|
mod p {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// run-rustfix
|
// run-rustfix
|
||||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
#![allow(unused, nonstandard_style)]
|
||||||
mod m {
|
mod m {
|
||||||
|
|
||||||
mod p {
|
mod p {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// run-rustfix
|
// run-rustfix
|
||||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
#![allow(unused, nonstandard_style)]
|
||||||
mod m {
|
mod m {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! nu {
|
macro_rules! nu {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// run-rustfix
|
// run-rustfix
|
||||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
#![allow(unused, nonstandard_style)]
|
||||||
mod m {
|
mod m {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! nu {
|
macro_rules! nu {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
#![allow(ambiguous_glob_reexports)]
|
||||||
|
|
||||||
macro_rules! define_exported { () => {
|
macro_rules! define_exported { () => {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
error[E0659]: `exported` is ambiguous
|
error[E0659]: `exported` is ambiguous
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:28:1
|
--> $DIR/local-modularized-tricky-fail-1.rs:29:1
|
||||||
|
|
|
|
||||||
LL | exported!();
|
LL | exported!();
|
||||||
| ^^^^^^^^ ambiguous name
|
| ^^^^^^^^ ambiguous name
|
||||||
|
|
|
|
||||||
= note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
|
= note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
|
||||||
note: `exported` could refer to the macro defined here
|
note: `exported` could refer to the macro defined here
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:5:5
|
--> $DIR/local-modularized-tricky-fail-1.rs:6:5
|
||||||
|
|
|
|
||||||
LL | / macro_rules! exported {
|
LL | / macro_rules! exported {
|
||||||
LL | | () => ()
|
LL | | () => ()
|
||||||
@ -16,7 +16,7 @@ LL | | }
|
|||||||
LL | define_exported!();
|
LL | define_exported!();
|
||||||
| ------------------ in this macro invocation
|
| ------------------ in this macro invocation
|
||||||
note: `exported` could also refer to the macro imported here
|
note: `exported` could also refer to the macro imported here
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:22:5
|
--> $DIR/local-modularized-tricky-fail-1.rs:23:5
|
||||||
|
|
|
|
||||||
LL | use inner1::*;
|
LL | use inner1::*;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -24,7 +24,7 @@ LL | use inner1::*;
|
|||||||
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0659]: `panic` is ambiguous
|
error[E0659]: `panic` is ambiguous
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:35:5
|
--> $DIR/local-modularized-tricky-fail-1.rs:36:5
|
||||||
|
|
|
|
||||||
LL | panic!();
|
LL | panic!();
|
||||||
| ^^^^^ ambiguous name
|
| ^^^^^ ambiguous name
|
||||||
@ -32,7 +32,7 @@ LL | panic!();
|
|||||||
= note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
|
= note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
|
||||||
= note: `panic` could refer to a macro from prelude
|
= note: `panic` could refer to a macro from prelude
|
||||||
note: `panic` could also refer to the macro defined here
|
note: `panic` could also refer to the macro defined here
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:11:5
|
--> $DIR/local-modularized-tricky-fail-1.rs:12:5
|
||||||
|
|
|
|
||||||
LL | / macro_rules! panic {
|
LL | / macro_rules! panic {
|
||||||
LL | | () => ()
|
LL | | () => ()
|
||||||
@ -45,7 +45,7 @@ LL | define_panic!();
|
|||||||
= note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0659]: `include` is ambiguous
|
error[E0659]: `include` is ambiguous
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:46:1
|
--> $DIR/local-modularized-tricky-fail-1.rs:47:1
|
||||||
|
|
|
|
||||||
LL | include!();
|
LL | include!();
|
||||||
| ^^^^^^^ ambiguous name
|
| ^^^^^^^ ambiguous name
|
||||||
@ -53,7 +53,7 @@ LL | include!();
|
|||||||
= note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
|
= note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
|
||||||
= note: `include` could refer to a macro from prelude
|
= note: `include` could refer to a macro from prelude
|
||||||
note: `include` could also refer to the macro defined here
|
note: `include` could also refer to the macro defined here
|
||||||
--> $DIR/local-modularized-tricky-fail-1.rs:17:5
|
--> $DIR/local-modularized-tricky-fail-1.rs:18:5
|
||||||
|
|
|
|
||||||
LL | / macro_rules! include {
|
LL | / macro_rules! include {
|
||||||
LL | | () => ()
|
LL | | () => ()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![deny(useless_anonymous_reexport)]
|
#![deny(unused_imports)]
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
mod my_mod {
|
mod my_mod {
|
||||||
@ -9,13 +9,11 @@ mod my_mod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub use self::my_mod::Foo as _;
|
pub use self::my_mod::Foo as _;
|
||||||
pub use self::my_mod::TyFoo as _;
|
pub use self::my_mod::TyFoo as _; //~ ERROR unused import
|
||||||
pub use self::my_mod::Bar as _; //~ ERROR
|
pub use self::my_mod::Bar as _; //~ ERROR unused import
|
||||||
pub use self::my_mod::TyBar as _; //~ ERROR
|
pub use self::my_mod::TyBar as _; //~ ERROR unused import
|
||||||
pub use self::my_mod::{Bar as _}; //~ ERROR
|
pub use self::my_mod::{Bar as _}; //~ ERROR unused import
|
||||||
pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR
|
pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import
|
||||||
pub use self::my_mod::{Bar as _, TyBar as _};
|
pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports
|
||||||
//~^ ERROR
|
|
||||||
//~| ERROR
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use self::my_mod::TyBar as _;
|
use self::my_mod::TyBar as _;
|
||||||
|
@ -1,55 +1,44 @@
|
|||||||
error: useless anonymous re-export
|
error: unused import: `self::my_mod::TyFoo as _`
|
||||||
--> $DIR/anonymous-reexport.rs:13:1
|
--> $DIR/anonymous-reexport.rs:12:9
|
||||||
|
|
|
|
||||||
LL | pub use self::my_mod::Bar as _;
|
LL | pub use self::my_mod::TyFoo as _;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `struct`
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/anonymous-reexport.rs:1:9
|
--> $DIR/anonymous-reexport.rs:1:9
|
||||||
|
|
|
|
||||||
LL | #![deny(useless_anonymous_reexport)]
|
LL | #![deny(unused_imports)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: useless anonymous re-export
|
error: unused import: `self::my_mod::Bar as _`
|
||||||
--> $DIR/anonymous-reexport.rs:14:1
|
--> $DIR/anonymous-reexport.rs:13:9
|
||||||
|
|
|
||||||
|
LL | pub use self::my_mod::Bar as _;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unused import: `self::my_mod::TyBar as _`
|
||||||
|
--> $DIR/anonymous-reexport.rs:14:9
|
||||||
|
|
|
|
||||||
LL | pub use self::my_mod::TyBar as _;
|
LL | pub use self::my_mod::TyBar as _;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `type alias`
|
|
||||||
|
|
||||||
error: useless anonymous re-export
|
error: unused import: `Bar as _`
|
||||||
--> $DIR/anonymous-reexport.rs:15:24
|
--> $DIR/anonymous-reexport.rs:15:24
|
||||||
|
|
|
|
||||||
LL | pub use self::my_mod::{Bar as _};
|
LL | pub use self::my_mod::{Bar as _};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `struct`
|
|
||||||
|
|
||||||
error: useless anonymous re-export
|
error: unused import: `Bar as _`
|
||||||
--> $DIR/anonymous-reexport.rs:16:24
|
--> $DIR/anonymous-reexport.rs:16:24
|
||||||
|
|
|
|
||||||
LL | pub use self::my_mod::{Bar as _, Foo as _};
|
LL | pub use self::my_mod::{Bar as _, Foo as _};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `struct`
|
|
||||||
|
|
||||||
error: useless anonymous re-export
|
error: unused imports: `Bar as _`, `TyBar as _`
|
||||||
--> $DIR/anonymous-reexport.rs:17:24
|
--> $DIR/anonymous-reexport.rs:17:24
|
||||||
|
|
|
|
||||||
LL | pub use self::my_mod::{Bar as _, TyBar as _};
|
LL | pub use self::my_mod::{Bar as _, TyBar as _};
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^ ^^^^^^^^^^
|
||||||
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `struct`
|
|
||||||
|
|
||||||
error: useless anonymous re-export
|
|
||||||
--> $DIR/anonymous-reexport.rs:17:34
|
|
||||||
|
|
|
||||||
LL | pub use self::my_mod::{Bar as _, TyBar as _};
|
|
||||||
| ^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: only anonymous re-exports of traits are useful, this is a `type alias`
|
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
33
tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
Normal file
33
tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#![deny(ambiguous_glob_reexports)]
|
||||||
|
|
||||||
|
pub mod foo {
|
||||||
|
pub type X = u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod bar {
|
||||||
|
pub type X = u8;
|
||||||
|
pub type Y = u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use foo::*;
|
||||||
|
//~^ ERROR ambiguous glob re-exports
|
||||||
|
pub use bar::*;
|
||||||
|
|
||||||
|
mod ambiguous {
|
||||||
|
mod m1 { pub type A = u8; }
|
||||||
|
mod m2 { pub type A = u8; }
|
||||||
|
pub use self::m1::*;
|
||||||
|
//~^ ERROR ambiguous glob re-exports
|
||||||
|
pub use self::m2::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod single {
|
||||||
|
pub use ambiguous::A;
|
||||||
|
//~^ ERROR `A` is ambiguous
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod glob {
|
||||||
|
pub use ambiguous::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {}
|
@ -0,0 +1,47 @@
|
|||||||
|
error[E0659]: `A` is ambiguous
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24
|
||||||
|
|
|
||||||
|
LL | pub use ambiguous::A;
|
||||||
|
| ^ ambiguous name
|
||||||
|
|
|
||||||
|
= note: ambiguous because of multiple glob imports of a name in the same module
|
||||||
|
note: `A` could refer to the type alias imported here
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
|
||||||
|
|
|
||||||
|
LL | pub use self::m1::*;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
= help: consider adding an explicit import of `A` to disambiguate
|
||||||
|
note: `A` could also refer to the type alias imported here
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13
|
||||||
|
|
|
||||||
|
LL | pub use self::m2::*;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
= help: consider adding an explicit import of `A` to disambiguate
|
||||||
|
|
||||||
|
error: ambiguous glob re-exports
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:12:9
|
||||||
|
|
|
||||||
|
LL | pub use foo::*;
|
||||||
|
| ^^^^^^ the name `X` in the type namespace is first re-exported here
|
||||||
|
LL |
|
||||||
|
LL | pub use bar::*;
|
||||||
|
| ------ but the name `X` in the type namespace is also re-exported here
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(ambiguous_glob_reexports)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: ambiguous glob re-exports
|
||||||
|
--> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13
|
||||||
|
|
|
||||||
|
LL | pub use self::m1::*;
|
||||||
|
| ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here
|
||||||
|
LL |
|
||||||
|
LL | pub use self::m2::*;
|
||||||
|
| ----------- but the name `A` in the type namespace is also re-exported here
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0659`.
|
13
tests/ui/suggestions/issue-109436.rs
Normal file
13
tests/ui/suggestions/issue-109436.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
struct Foo;
|
||||||
|
struct Bar;
|
||||||
|
|
||||||
|
impl From<&Foo> for Bar {
|
||||||
|
fn from(foo: &Foo) -> Bar {
|
||||||
|
Bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = Foo;
|
||||||
|
let b: Bar = foo.into(); //~ ERROR E0277
|
||||||
|
}
|
15
tests/ui/suggestions/issue-109436.stderr
Normal file
15
tests/ui/suggestions/issue-109436.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error[E0277]: the trait bound `Foo: Into<_>` is not satisfied
|
||||||
|
--> $DIR/issue-109436.rs:12:22
|
||||||
|
|
|
||||||
|
LL | let b: Bar = foo.into();
|
||||||
|
| ^^^^ the trait `~const Into<_>` is not implemented for `Foo`
|
||||||
|
|
|
||||||
|
= note: required for `Foo` to implement `Into<Bar>`
|
||||||
|
help: consider borrowing here
|
||||||
|
|
|
||||||
|
LL | let b: Bar = (&foo).into();
|
||||||
|
| ++ +
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user