mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +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_macros",
|
||||
"rustc_serialize",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
"stable_deref_trait",
|
||||
"stacker",
|
||||
@ -4826,6 +4827,7 @@ dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
"rustc_hir_typeck",
|
||||
@ -4950,6 +4952,7 @@ dependencies = [
|
||||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
"rustc_index",
|
||||
@ -5335,6 +5338,7 @@ dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_feature",
|
||||
"rustc_fs_util",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
@ -361,12 +361,12 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
.join(sess);
|
||||
|
||||
sess.time("llvm_dump_timing_file", || {
|
||||
if sess.opts.unstable_opts.llvm_time_trace {
|
||||
sess.time("llvm_dump_timing_file", || {
|
||||
let file_name = outputs.with_extension("llvm_timings.json");
|
||||
llvm_util::time_trace_profiler_finish(&file_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok((codegen_results, work_products))
|
||||
}
|
||||
|
@ -786,6 +786,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||
total_codegen_time,
|
||||
start_rss.unwrap(),
|
||||
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_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
serde_json = "1.0.59"
|
||||
smallvec = { version = "1.8.1", features = [
|
||||
"const_generics",
|
||||
"union",
|
||||
|
@ -56,7 +56,7 @@ fn test_three_sccs() {
|
||||
assert_eq!(sccs.scc(1), 0);
|
||||
assert_eq!(sccs.scc(2), 0);
|
||||
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(2), &[0]);
|
||||
}
|
||||
@ -113,7 +113,7 @@ fn test_find_state_2() {
|
||||
assert_eq!(sccs.scc(2), 0);
|
||||
assert_eq!(sccs.scc(3), 0);
|
||||
assert_eq!(sccs.scc(4), 0);
|
||||
assert_eq!(sccs.successors(0), &[]);
|
||||
assert_eq!(sccs.successors(0), &[] as &[usize]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -138,7 +138,7 @@ fn test_find_state_3() {
|
||||
assert_eq!(sccs.scc(3), 0);
|
||||
assert_eq!(sccs.scc(4), 0);
|
||||
assert_eq!(sccs.scc(5), 1);
|
||||
assert_eq!(sccs.successors(0), &[]);
|
||||
assert_eq!(sccs.successors(0), &[] as &[usize]);
|
||||
assert_eq!(sccs.successors(1), &[0]);
|
||||
}
|
||||
|
||||
|
@ -27,11 +27,11 @@ fn successors() {
|
||||
let graph = create_graph();
|
||||
assert_eq!(graph.successors(0), &[1]);
|
||||
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(4), &[]);
|
||||
assert_eq!(graph.successors(4), &[] as &[usize]);
|
||||
assert_eq!(graph.successors(5), &[1]);
|
||||
assert_eq!(graph.successors(6), &[]);
|
||||
assert_eq!(graph.successors(6), &[] as &[usize]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -97,6 +97,7 @@ use std::time::{Duration, Instant};
|
||||
pub use measureme::EventId;
|
||||
use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
|
||||
use parking_lot::RwLock;
|
||||
use serde_json::json;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
bitflags::bitflags! {
|
||||
@ -145,6 +146,15 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
|
||||
/// Something that uniquely identifies a query invocation.
|
||||
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
|
||||
/// boundaries at will.
|
||||
#[derive(Clone)]
|
||||
@ -158,14 +168,14 @@ pub struct SelfProfilerRef {
|
||||
// actually enabled.
|
||||
event_filter_mask: EventFilter,
|
||||
|
||||
// Print verbose generic activities to stderr?
|
||||
print_verbose_generic_activities: bool,
|
||||
// Print verbose generic activities to stderr.
|
||||
print_verbose_generic_activities: Option<TimePassesFormat>,
|
||||
}
|
||||
|
||||
impl SelfProfilerRef {
|
||||
pub fn new(
|
||||
profiler: Option<Arc<SelfProfiler>>,
|
||||
print_verbose_generic_activities: bool,
|
||||
print_verbose_generic_activities: Option<TimePassesFormat>,
|
||||
) -> SelfProfilerRef {
|
||||
// If there is no SelfProfiler then the filter mask is set to NONE,
|
||||
// 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
|
||||
/// stderr if the compiler is invoked with -Ztime-passes.
|
||||
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.
|
||||
@ -221,11 +232,14 @@ impl SelfProfilerRef {
|
||||
where
|
||||
A: Borrow<str> + Into<String>,
|
||||
{
|
||||
let message = self
|
||||
let message_and_format = self
|
||||
.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
|
||||
@ -703,17 +717,32 @@ impl<'a> TimingGuard<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
struct VerboseInfo {
|
||||
start_time: Instant,
|
||||
start_rss: Option<usize>,
|
||||
message: String,
|
||||
format: TimePassesFormat,
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub struct VerboseTimingGuard<'a> {
|
||||
start_and_message: Option<(Instant, Option<usize>, String)>,
|
||||
info: Option<VerboseInfo>,
|
||||
_guard: TimingGuard<'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 {
|
||||
_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<'_> {
|
||||
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 dur = start_time.elapsed();
|
||||
print_time_passes_entry(message, dur, start_rss, end_rss);
|
||||
let dur = info.start_time.elapsed();
|
||||
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,
|
||||
start_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
|
||||
// measured RSS.
|
||||
let is_notable = || {
|
||||
|
@ -20,7 +20,9 @@ pub extern crate rustc_plugin_impl as plugin;
|
||||
|
||||
use rustc_ast as ast;
|
||||
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_errors::registry::{InvalidErrorCode, Registry};
|
||||
use rustc_errors::{
|
||||
@ -161,7 +163,7 @@ pub trait Callbacks {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TimePassesCallbacks {
|
||||
time_passes: bool,
|
||||
time_passes: Option<TimePassesFormat>,
|
||||
}
|
||||
|
||||
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"
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -1354,9 +1357,9 @@ pub fn main() -> ! {
|
||||
RunCompiler::new(&args, &mut callbacks).run()
|
||||
});
|
||||
|
||||
if callbacks.time_passes {
|
||||
if let Some(format) = callbacks.time_passes {
|
||||
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)
|
||||
|
@ -160,6 +160,8 @@ declare_features! (
|
||||
(active, intrinsics, "1.0.0", None, None),
|
||||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||
(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.
|
||||
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
|
||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||
@ -432,8 +434,6 @@ declare_features! (
|
||||
(active, large_assignments, "1.52.0", Some(83518), None),
|
||||
/// Allows `if/while p && let q = r && ...` chains.
|
||||
(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.
|
||||
(active, lint_reasons, "1.31.0", Some(54503), None),
|
||||
/// Give access to additional metadata about declarative macro meta-variables.
|
||||
|
@ -1,10 +1,11 @@
|
||||
#![feature(absolute_path)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::fs;
|
||||
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
|
||||
// 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 {
|
||||
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_object_overlap(tcx, impl_def_id, trait_ref);
|
||||
|
||||
tcx.sess.time("unsafety_checking", || unsafety::check_item(tcx, impl_def_id));
|
||||
tcx.sess.time("orphan_checking", || tcx.ensure().orphan_check_impl(impl_def_id));
|
||||
unsafety::check_item(tcx, impl_def_id);
|
||||
tcx.ensure().orphan_check_impl(impl_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::{base_n, flock};
|
||||
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_span::Symbol;
|
||||
|
||||
@ -223,7 +223,7 @@ pub fn prepare_session_directory(
|
||||
// because, on windows, long paths can cause problems;
|
||||
// canonicalization inserts this weird prefix that makes windows
|
||||
// tolerate long paths.
|
||||
let crate_dir = match crate_dir.canonicalize() {
|
||||
let crate_dir = match try_canonicalize(&crate_dir) {
|
||||
Ok(v) => v,
|
||||
Err(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
|
||||
/// into the '\\?\' format, which supports much longer paths.
|
||||
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,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
||||
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<()> {
|
||||
let canonicalized = match std_fs::canonicalize(p) {
|
||||
let canonicalized = match try_canonicalize(p) {
|
||||
Ok(canonicalized) => canonicalized,
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
|
||||
Err(err) => return Err(err),
|
||||
|
@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_borrowck = { path = "../rustc_borrowck" }
|
||||
rustc_builtin_macros = { path = "../rustc_builtin_macros" }
|
||||
rustc_expand = { path = "../rustc_expand" }
|
||||
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
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_errors::PResult;
|
||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
|
||||
use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
|
||||
use rustc_metadata::creader::CStore;
|
||||
@ -408,12 +409,12 @@ where
|
||||
}
|
||||
|
||||
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() {
|
||||
return false;
|
||||
}
|
||||
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()
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
use crate::interface::parse_cfgspecs;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::profiling::TimePassesFormat;
|
||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||
use rustc_session::config::rustc_optgroups;
|
||||
use rustc_session::config::Input;
|
||||
@ -699,6 +700,7 @@ fn test_unstable_options_tracking_hash() {
|
||||
untracked!(threads, 99);
|
||||
untracked!(time_llvm_passes, true);
|
||||
untracked!(time_passes, true);
|
||||
untracked!(time_passes_format, TimePassesFormat::Json);
|
||||
untracked!(trace_macros, true);
|
||||
untracked!(track_diagnostics, true);
|
||||
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}`
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
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.
|
||||
decorate(db)
|
||||
|
@ -74,7 +74,6 @@ mod opaque_hidden_inferred_bound;
|
||||
mod pass_by_value;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod reexports;
|
||||
mod traits;
|
||||
mod types;
|
||||
mod unused;
|
||||
@ -112,7 +111,6 @@ use noop_method_call::*;
|
||||
use opaque_hidden_inferred_bound::*;
|
||||
use pass_by_value::*;
|
||||
use redundant_semicolon::*;
|
||||
use reexports::*;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
use unused::*;
|
||||
@ -244,7 +242,6 @@ late_lint_methods!(
|
||||
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
||||
MapUnitFn: MapUnitFn,
|
||||
UselessAnonymousReexport: UselessAnonymousReexport,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
@ -1528,11 +1528,3 @@ pub struct UnusedAllocationDiag;
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_allocation_mut)]
|
||||
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! {
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// that are used by other parts of the compiler.
|
||||
@ -3337,6 +3376,7 @@ declare_lint_pass! {
|
||||
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
||||
IMPLIED_BOUNDS_ENTAILMENT,
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
AMBIGUOUS_GLOB_REEXPORTS,
|
||||
]
|
||||
}
|
||||
|
||||
@ -3968,14 +4008,9 @@ declare_lint! {
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (need FFI)
|
||||
/// #![feature(ffi_unwind_calls)]
|
||||
/// ```rust
|
||||
/// #![feature(c_unwind)]
|
||||
///
|
||||
/// # mod impl {
|
||||
/// # #[no_mangle]
|
||||
/// # pub fn "C-unwind" fn foo() {}
|
||||
/// # }
|
||||
/// #![warn(ffi_unwind_calls)]
|
||||
///
|
||||
/// extern "C-unwind" {
|
||||
/// fn foo();
|
||||
|
@ -529,6 +529,16 @@ pub enum BuiltinLintDiagnostics {
|
||||
vis_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
|
||||
|
@ -18,6 +18,7 @@ rustc_attr = { path = "../rustc_attr" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
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::sync::MetadataRef;
|
||||
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_session::config::{self, CrateType};
|
||||
use rustc_session::cstore::{CrateSource, MetadataLoader};
|
||||
use rustc_session::filesearch::FileSearch;
|
||||
@ -236,7 +237,7 @@ use snap::read::FrameDecoder;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Read, Result as IoResult, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{cmp, fmt, fs};
|
||||
use std::{cmp, fmt};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CrateLocator<'a> {
|
||||
@ -441,7 +442,7 @@ impl<'a> CrateLocator<'a> {
|
||||
info!("lib candidate: {}", spf.path.display());
|
||||
|
||||
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) {
|
||||
continue;
|
||||
};
|
||||
@ -636,7 +637,7 @@ impl<'a> CrateLocator<'a> {
|
||||
// as well.
|
||||
if let Some((prev, _)) = &ret {
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
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::BuiltinLintDiagnostics;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
struct UnusedImport<'a> {
|
||||
@ -58,6 +59,7 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
||||
base_use_tree: Option<&'a ast::UseTree>,
|
||||
base_id: ast::NodeId,
|
||||
item_span: Span,
|
||||
base_use_is_pub: bool,
|
||||
}
|
||||
|
||||
struct ExternCrateToLint {
|
||||
@ -110,6 +112,35 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
||||
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> {
|
||||
@ -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
|
||||
// because this means that they were generated in some fashion by the
|
||||
// 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) => {
|
||||
self.extern_crate_items.push(ExternCrateToLint {
|
||||
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);
|
||||
}
|
||||
|
||||
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 items.is_empty() {
|
||||
self.unused_import(self.base_id).add(id);
|
||||
@ -300,6 +337,7 @@ impl Resolver<'_, '_> {
|
||||
base_use_tree: None,
|
||||
base_id: ast::DUMMY_NODE_ID,
|
||||
item_span: DUMMY_SP,
|
||||
base_use_is_pub: false,
|
||||
};
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
|
||||
|
@ -4,6 +4,7 @@ use rustc_ast::visit;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::Crate;
|
||||
use rustc_ast::EnumDef;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
@ -70,11 +71,11 @@ impl Resolver<'_, '_> {
|
||||
impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
||||
/// Fills the `Resolver::effective_visibilities` table with public & exported items
|
||||
/// 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>(
|
||||
r: &'r mut Resolver<'a, 'tcx>,
|
||||
krate: &'c Crate,
|
||||
) {
|
||||
) -> FxHashSet<Interned<'a, NameBinding<'a>>> {
|
||||
let mut visitor = EffectiveVisibilitiesVisitor {
|
||||
r,
|
||||
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;
|
||||
|
||||
let mut exported_ambiguities = FxHashSet::default();
|
||||
|
||||
// Update visibilities for import def ids. These are not used during the
|
||||
// `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
|
||||
// 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.
|
||||
for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
|
||||
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
|
||||
if !binding.is_ambiguity() {
|
||||
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);
|
||||
|
||||
exported_ambiguities
|
||||
}
|
||||
|
||||
/// Update effective visibilities of bindings in the given module,
|
||||
@ -115,12 +124,14 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
||||
let resolutions = self.r.resolutions(module);
|
||||
|
||||
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() {
|
||||
if !binding.is_ambiguity() {
|
||||
// Set the given effective visibility level to `Level::Direct` and
|
||||
// sets the rest of the `use` chain to `Level::Reexported` until
|
||||
// we hit the actual exported item.
|
||||
let mut parent_id = ParentId::Def(module_id);
|
||||
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
|
||||
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind
|
||||
{
|
||||
let binding_id = ImportId::new_unchecked(binding);
|
||||
self.update_import(binding_id, parent_id);
|
||||
|
||||
@ -131,6 +142,27 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
|
||||
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);
|
||||
}
|
||||
} 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::span_bug;
|
||||
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_span::edit_distance::find_best_match_for_name;
|
||||
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)>) {
|
||||
if errors.is_empty() {
|
||||
return;
|
||||
|
@ -1475,9 +1475,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||
self.tcx.sess.time("resolve_crate", || {
|
||||
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)
|
||||
});
|
||||
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("late_resolve_crate", || self.late_resolve_crate(krate));
|
||||
self.tcx.sess.time("resolve_main", || self.resolve_main());
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! A module for searching for libraries
|
||||
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
@ -125,7 +126,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
|
||||
let target = crate::config::host_triple();
|
||||
let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
|
||||
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 {
|
||||
// use `parent` twice to chop off the file name and then also the
|
||||
// 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> {
|
||||
// Follow symlinks. If the resolved path is relative, make it absolute.
|
||||
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
|
||||
// gcc chokes on verbatim paths which fs::canonicalize generates
|
||||
// so we try to avoid those kinds of paths.
|
||||
|
@ -4,6 +4,7 @@ use crate::early_error;
|
||||
use crate::lint;
|
||||
use crate::search_paths::SearchPath;
|
||||
use crate::utils::NativeLib;
|
||||
use rustc_data_structures::profiling::TimePassesFormat;
|
||||
use rustc_errors::{LanguageIdentifier, TerminalUrl};
|
||||
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
|
||||
use rustc_target::spec::{
|
||||
@ -365,6 +366,7 @@ mod desc {
|
||||
pub const parse_number: &str = "a number";
|
||||
pub const parse_opt_number: &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_panic_strategy: &str = "either `unwind` or `abort`";
|
||||
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
|
||||
@ -829,6 +831,21 @@ mod parse {
|
||||
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 {
|
||||
match v {
|
||||
None => true,
|
||||
@ -1709,6 +1726,8 @@ options! {
|
||||
"measure time of each LLVM pass (default: no)"),
|
||||
time_passes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"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],
|
||||
"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")]
|
||||
|
@ -1453,7 +1453,10 @@ pub fn build_session(
|
||||
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") {
|
||||
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::session::Session;
|
||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
impl Session {
|
||||
@ -98,7 +99,7 @@ pub struct CanonicalizedPath {
|
||||
|
||||
impl CanonicalizedPath {
|
||||
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 {
|
||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
||||
bitflags = "1.2.1"
|
||||
tracing = "0.1"
|
||||
serde_json = "1.0.59"
|
||||
rustc_fs_util = { path = "../rustc_fs_util" }
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
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::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use serde_json::Value;
|
||||
@ -2949,7 +2950,7 @@ impl TargetTriple {
|
||||
|
||||
/// Creates a target triple from the passed target path.
|
||||
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| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
|
@ -1356,6 +1356,31 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} 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
|
||||
// for example, `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,
|
||||
};
|
||||
|
||||
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 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 {
|
||||
vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
|
||||
} else {
|
||||
|
@ -370,7 +370,7 @@ pub enum ErrorKind {
|
||||
|
||||
// "Unusual" error kinds which do not correspond simply to (sets
|
||||
// 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.
|
||||
///
|
||||
@ -882,6 +882,13 @@ impl 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
|
||||
///
|
||||
/// ```
|
||||
@ -892,7 +899,8 @@ impl Error {
|
||||
/// }
|
||||
///
|
||||
/// 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());
|
||||
/// // Will print "AddrInUse".
|
||||
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
|
||||
|
@ -45,6 +45,36 @@ impl Lint {
|
||||
fn check_style(&self) -> Result<(), Box<dyn Error>> {
|
||||
for &expected in &["### Example", "### Explanation", "{{produces}}"] {
|
||||
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;
|
||||
}
|
||||
if !self.doc_contains(expected) {
|
||||
@ -392,23 +422,20 @@ impl<'a> LintExtractor<'a> {
|
||||
.filter(|line| line.starts_with('{'))
|
||||
.map(serde_json::from_str)
|
||||
.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()
|
||||
.find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
|
||||
{
|
||||
Some(msg) => {
|
||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
||||
Ok(rendered.to_string())
|
||||
}
|
||||
None => {
|
||||
match msgs.iter().find(
|
||||
|msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
|
||||
) {
|
||||
Some(msg) => {
|
||||
let rendered = msg["rendered"].as_str().expect("rendered field should exist");
|
||||
Ok(rendered.to_string())
|
||||
}
|
||||
None => {
|
||||
.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())
|
||||
.collect();
|
||||
if matches.is_empty() {
|
||||
// Some lints override their code to something else (E0566).
|
||||
// Try to find something that looks like it could be our lint.
|
||||
let matches: Vec<_> = msgs.iter().filter(|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();
|
||||
if matches.is_empty() {
|
||||
let rendered: Vec<&str> =
|
||||
msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
|
||||
let non_json: Vec<&str> =
|
||||
@ -420,9 +447,11 @@ impl<'a> LintExtractor<'a> {
|
||||
rendered.join("\n")
|
||||
)
|
||||
.into())
|
||||
} else {
|
||||
Ok(matches.join("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(matches.join("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,6 +183,7 @@
|
||||
-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-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 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)
|
||||
|
@ -4,7 +4,6 @@ error[E0658]: link cfg is unstable
|
||||
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
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
|
||||
mod m1 {
|
||||
pub fn f() {}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
||||
#![allow(unused, nonstandard_style)]
|
||||
mod m {
|
||||
|
||||
mod p {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
||||
#![allow(unused, nonstandard_style)]
|
||||
mod m {
|
||||
|
||||
mod p {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
||||
#![allow(unused, nonstandard_style)]
|
||||
mod m {
|
||||
#[macro_export]
|
||||
macro_rules! nu {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused, nonstandard_style, useless_anonymous_reexport)]
|
||||
#![allow(unused, nonstandard_style)]
|
||||
mod m {
|
||||
#[macro_export]
|
||||
macro_rules! nu {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![feature(decl_macro)]
|
||||
#![allow(ambiguous_glob_reexports)]
|
||||
|
||||
macro_rules! define_exported { () => {
|
||||
#[macro_export]
|
||||
|
@ -1,12 +1,12 @@
|
||||
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!();
|
||||
| ^^^^^^^^ 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: `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 | | () => ()
|
||||
@ -16,7 +16,7 @@ LL | | }
|
||||
LL | define_exported!();
|
||||
| ------------------ in this macro invocation
|
||||
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::*;
|
||||
| ^^^^^^^^^
|
||||
@ -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)
|
||||
|
||||
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!();
|
||||
| ^^^^^ 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: `panic` could refer to a macro from prelude
|
||||
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 | | () => ()
|
||||
@ -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)
|
||||
|
||||
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!();
|
||||
| ^^^^^^^ 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: `include` could refer to a macro from prelude
|
||||
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 | | () => ()
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![deny(useless_anonymous_reexport)]
|
||||
#![deny(unused_imports)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
mod my_mod {
|
||||
@ -9,13 +9,11 @@ mod my_mod {
|
||||
}
|
||||
|
||||
pub use self::my_mod::Foo as _;
|
||||
pub use self::my_mod::TyFoo as _;
|
||||
pub use self::my_mod::Bar as _; //~ ERROR
|
||||
pub use self::my_mod::TyBar as _; //~ ERROR
|
||||
pub use self::my_mod::{Bar as _}; //~ ERROR
|
||||
pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR
|
||||
pub use self::my_mod::{Bar as _, TyBar as _};
|
||||
//~^ ERROR
|
||||
//~| ERROR
|
||||
pub use self::my_mod::TyFoo as _; //~ ERROR unused import
|
||||
pub use self::my_mod::Bar as _; //~ ERROR unused import
|
||||
pub use self::my_mod::TyBar as _; //~ ERROR unused import
|
||||
pub use self::my_mod::{Bar as _}; //~ ERROR unused import
|
||||
pub use self::my_mod::{Bar as _, Foo as _}; //~ ERROR unused import
|
||||
pub use self::my_mod::{Bar as _, TyBar as _}; //~ ERROR unused imports
|
||||
#[allow(unused_imports)]
|
||||
use self::my_mod::TyBar as _;
|
||||
|
@ -1,55 +1,44 @@
|
||||
error: useless anonymous re-export
|
||||
--> $DIR/anonymous-reexport.rs:13:1
|
||||
error: unused import: `self::my_mod::TyFoo as _`
|
||||
--> $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
|
||||
--> $DIR/anonymous-reexport.rs:1:9
|
||||
|
|
||||
LL | #![deny(useless_anonymous_reexport)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #![deny(unused_imports)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: useless anonymous re-export
|
||||
--> $DIR/anonymous-reexport.rs:14:1
|
||||
error: unused import: `self::my_mod::Bar as _`
|
||||
--> $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 _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= 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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
||||
|
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