Merge from rustc
This commit is contained in:
commit
817b75042a
233 changed files with 3326 additions and 1220 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -2222,6 +2222,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_ast::{self as ast, AttrItem, AttrStyle};
|
|||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate {
|
||||
pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(
|
||||
parse_sess,
|
||||
|
|
@ -36,6 +36,4 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -
|
|||
start_span.to(end_span),
|
||||
));
|
||||
}
|
||||
|
||||
krate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,14 +43,14 @@ struct CollectProcMacros<'a> {
|
|||
}
|
||||
|
||||
pub fn inject(
|
||||
krate: &mut ast::Crate,
|
||||
sess: &Session,
|
||||
resolver: &mut dyn ResolverExpand,
|
||||
mut krate: ast::Crate,
|
||||
is_proc_macro_crate: bool,
|
||||
has_proc_macro_decls: bool,
|
||||
is_test_crate: bool,
|
||||
handler: &rustc_errors::Handler,
|
||||
) -> ast::Crate {
|
||||
) {
|
||||
let ecfg = ExpansionConfig::default("proc_macro".to_string());
|
||||
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
|
||||
|
||||
|
|
@ -64,22 +64,20 @@ pub fn inject(
|
|||
};
|
||||
|
||||
if has_proc_macro_decls || is_proc_macro_crate {
|
||||
visit::walk_crate(&mut collect, &krate);
|
||||
visit::walk_crate(&mut collect, krate);
|
||||
}
|
||||
let macros = collect.macros;
|
||||
|
||||
if !is_proc_macro_crate {
|
||||
return krate;
|
||||
return;
|
||||
}
|
||||
|
||||
if is_test_crate {
|
||||
return krate;
|
||||
return;
|
||||
}
|
||||
|
||||
let decls = mk_decls(&mut cx, ¯os);
|
||||
krate.items.push(decls);
|
||||
|
||||
krate
|
||||
}
|
||||
|
||||
impl<'a> CollectProcMacros<'a> {
|
||||
|
|
|
|||
|
|
@ -9,17 +9,19 @@ use rustc_span::DUMMY_SP;
|
|||
use thin_vec::thin_vec;
|
||||
|
||||
pub fn inject(
|
||||
mut krate: ast::Crate,
|
||||
krate: &mut ast::Crate,
|
||||
pre_configured_attrs: &[ast::Attribute],
|
||||
resolver: &mut dyn ResolverExpand,
|
||||
sess: &Session,
|
||||
) -> ast::Crate {
|
||||
) -> usize {
|
||||
let orig_num_items = krate.items.len();
|
||||
let edition = sess.parse_sess.edition;
|
||||
|
||||
// the first name in this list is the crate name of the crate with the prelude
|
||||
let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
|
||||
return krate;
|
||||
} else if attr::contains_name(&krate.attrs, sym::no_std) {
|
||||
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
|
||||
let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
|
||||
return 0;
|
||||
} else if attr::contains_name(pre_configured_attrs, sym::no_std) {
|
||||
if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
|
||||
&[sym::core]
|
||||
} else {
|
||||
&[sym::core, sym::compiler_builtins]
|
||||
|
|
@ -88,6 +90,5 @@ pub fn inject(
|
|||
);
|
||||
|
||||
krate.items.insert(0, use_item);
|
||||
|
||||
krate
|
||||
krate.items.len() - orig_num_items
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ struct TestCtxt<'a> {
|
|||
|
||||
/// Traverse the crate, collecting all the test functions, eliding any
|
||||
/// existing main functions, and synthesizing a main test harness
|
||||
pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
|
||||
pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) {
|
||||
let span_diagnostic = sess.diagnostic();
|
||||
let panic_strategy = sess.panic_strategy();
|
||||
let platform_panic_strategy = sess.target.panic_strategy;
|
||||
|
|
|
|||
|
|
@ -709,6 +709,10 @@ fn codegen_stmt<'tcx>(
|
|||
let operand = codegen_operand(fx, operand);
|
||||
operand.coerce_dyn_star(fx, lval);
|
||||
}
|
||||
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
|
||||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue_transmute(fx, operand);
|
||||
}
|
||||
Rvalue::Discriminant(place) => {
|
||||
let place = codegen_place(fx, place);
|
||||
let value = place.to_cvalue(fx);
|
||||
|
|
|
|||
|
|
@ -557,16 +557,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
fx.bcx.ins().band(ptr, mask);
|
||||
}
|
||||
|
||||
sym::transmute => {
|
||||
intrinsic_args!(fx, args => (from); intrinsic);
|
||||
|
||||
if ret.layout().abi.is_uninhabited() {
|
||||
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info);
|
||||
return;
|
||||
}
|
||||
|
||||
ret.write_cvalue_transmute(fx, from);
|
||||
}
|
||||
sym::write_bytes | sym::volatile_set_memory => {
|
||||
intrinsic_args!(fx, args => (dst, val, count); intrinsic);
|
||||
let val = val.load_scalar(fx);
|
||||
|
|
|
|||
|
|
@ -189,6 +189,15 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
path.push(lib_name);
|
||||
path
|
||||
};
|
||||
// dlltool target architecture args from:
|
||||
// https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
|
||||
let (dlltool_target_arch, dlltool_target_bitness) = match sess.target.arch.as_ref() {
|
||||
"x86_64" => ("i386:x86-64", "--64"),
|
||||
"x86" => ("i386", "--32"),
|
||||
"aarch64" => ("arm64", "--64"),
|
||||
"arm" => ("arm", "--32"),
|
||||
_ => panic!("unsupported arch {}", sess.target.arch),
|
||||
};
|
||||
let result = std::process::Command::new(dlltool)
|
||||
.args([
|
||||
"-d",
|
||||
|
|
@ -197,6 +206,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
lib_name,
|
||||
"-l",
|
||||
output_path.to_str().unwrap(),
|
||||
"-m",
|
||||
dlltool_target_arch,
|
||||
"-f",
|
||||
dlltool_target_bitness,
|
||||
"--no-leading-underscore",
|
||||
"--temp-prefix",
|
||||
temp_prefix.to_str().unwrap(),
|
||||
|
|
@ -422,24 +435,22 @@ fn find_binutils_dlltool(sess: &Session) -> OsString {
|
|||
return dlltool_path.clone().into_os_string();
|
||||
}
|
||||
|
||||
let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
|
||||
// We are cross-compiling, so we need the tool with the prefix matching our target
|
||||
if sess.target.arch == "x86" {
|
||||
"i686-w64-mingw32-dlltool"
|
||||
} else {
|
||||
"x86_64-w64-mingw32-dlltool"
|
||||
}
|
||||
let tool_name: OsString = if sess.host.options.is_like_windows {
|
||||
// If we're compiling on Windows, always use "dlltool.exe".
|
||||
"dlltool.exe"
|
||||
} else {
|
||||
// We are not cross-compiling, so we just want `dlltool`
|
||||
"dlltool"
|
||||
// On other platforms, use the architecture-specific name.
|
||||
match sess.target.arch.as_ref() {
|
||||
"x86_64" => "x86_64-w64-mingw32-dlltool",
|
||||
"x86" => "i686-w64-mingw32-dlltool",
|
||||
"aarch64" => "aarch64-w64-mingw32-dlltool",
|
||||
|
||||
// For non-standard architectures (e.g., aarch32) fallback to "dlltool".
|
||||
_ => "dlltool",
|
||||
}
|
||||
}
|
||||
.into();
|
||||
|
||||
if sess.host.options.is_like_windows {
|
||||
// If we're compiling on Windows, add the .exe suffix
|
||||
tool_name.push(".exe");
|
||||
}
|
||||
|
||||
// NOTE: it's not clear how useful it is to explicitly search PATH.
|
||||
for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
|
||||
let full_path = dir.join(&tool_name);
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
_ => bug!("unknown intrinsic '{}'", name),
|
||||
_ => bug!("unknown intrinsic '{}' -- should it have been lowered earlier?", name),
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,6 +133,9 @@ pub fn get_linker<'a>(
|
|||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
|
||||
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
|
||||
Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
|
||||
LinkerFlavor::Gnu(cc, _)
|
||||
| LinkerFlavor::Darwin(cc, _)
|
||||
|
|
@ -1474,6 +1477,177 @@ impl<'a> L4Bender<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Linker for AIX.
|
||||
pub struct AixLinker<'a> {
|
||||
cmd: Command,
|
||||
sess: &'a Session,
|
||||
hinted_static: bool,
|
||||
}
|
||||
|
||||
impl<'a> AixLinker<'a> {
|
||||
pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
|
||||
AixLinker { cmd: cmd, sess: sess, hinted_static: false }
|
||||
}
|
||||
|
||||
fn hint_static(&mut self) {
|
||||
if !self.hinted_static {
|
||||
self.cmd.arg("-bstatic");
|
||||
self.hinted_static = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn hint_dynamic(&mut self) {
|
||||
if self.hinted_static {
|
||||
self.cmd.arg("-bdynamic");
|
||||
self.hinted_static = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {
|
||||
self.cmd.arg("-bM:SRE");
|
||||
self.cmd.arg("-bnoentry");
|
||||
// FIXME: Use CreateExportList utility to create export list
|
||||
// and remove -bexpfull.
|
||||
self.cmd.arg("-bexpfull");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Linker for AixLinker<'a> {
|
||||
fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
|
||||
self.hint_dynamic();
|
||||
self.cmd.arg(format!("-l{}", lib));
|
||||
}
|
||||
|
||||
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
|
||||
self.hint_static();
|
||||
self.cmd.arg(format!("-l{}", lib));
|
||||
}
|
||||
|
||||
fn link_rlib(&mut self, lib: &Path) {
|
||||
self.hint_static();
|
||||
self.cmd.arg(lib);
|
||||
}
|
||||
|
||||
fn include_path(&mut self, path: &Path) {
|
||||
self.cmd.arg("-L").arg(path);
|
||||
}
|
||||
|
||||
fn framework_path(&mut self, _: &Path) {
|
||||
bug!("frameworks are not supported on AIX");
|
||||
}
|
||||
|
||||
fn output_filename(&mut self, path: &Path) {
|
||||
self.cmd.arg("-o").arg(path);
|
||||
}
|
||||
|
||||
fn add_object(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn full_relro(&mut self) {}
|
||||
|
||||
fn partial_relro(&mut self) {}
|
||||
|
||||
fn no_relro(&mut self) {}
|
||||
|
||||
fn cmd(&mut self) -> &mut Command {
|
||||
&mut self.cmd
|
||||
}
|
||||
|
||||
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
|
||||
match output_kind {
|
||||
LinkOutputKind::DynamicDylib => {
|
||||
self.hint_dynamic();
|
||||
self.build_dylib(out_filename);
|
||||
}
|
||||
LinkOutputKind::StaticDylib => {
|
||||
self.hint_static();
|
||||
self.build_dylib(out_filename);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
|
||||
self.hint_dynamic();
|
||||
self.cmd.arg(format!("-l{}", lib));
|
||||
}
|
||||
|
||||
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
|
||||
bug!("frameworks not supported on AIX");
|
||||
}
|
||||
|
||||
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
|
||||
self.hint_static();
|
||||
let lib = find_native_static_library(lib, verbatim, search_path, &self.sess);
|
||||
self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
|
||||
}
|
||||
|
||||
fn link_whole_rlib(&mut self, lib: &Path) {
|
||||
self.hint_static();
|
||||
self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
|
||||
}
|
||||
|
||||
fn gc_sections(&mut self, _keep_metadata: bool) {
|
||||
self.cmd.arg("-bgc");
|
||||
}
|
||||
|
||||
fn no_gc_sections(&mut self) {
|
||||
self.cmd.arg("-bnogc");
|
||||
}
|
||||
|
||||
fn optimize(&mut self) {}
|
||||
|
||||
fn pgo_gen(&mut self) {}
|
||||
|
||||
fn control_flow_guard(&mut self) {}
|
||||
|
||||
fn debuginfo(&mut self, strip: Strip, _: &[PathBuf]) {
|
||||
match strip {
|
||||
Strip::None => {}
|
||||
// FIXME: -s strips the symbol table, line number information
|
||||
// and relocation information.
|
||||
Strip::Debuginfo | Strip::Symbols => {
|
||||
self.cmd.arg("-s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn no_crt_objects(&mut self) {}
|
||||
|
||||
fn no_default_libraries(&mut self) {}
|
||||
|
||||
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
|
||||
let path = tmpdir.join("list.exp");
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
// TODO: use llvm-nm to generate export list.
|
||||
for symbol in symbols {
|
||||
debug!(" _{}", symbol);
|
||||
writeln!(f, " {}", symbol)?;
|
||||
}
|
||||
};
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to write export file: {}", e));
|
||||
}
|
||||
self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, _subsystem: &str) {}
|
||||
|
||||
fn reset_per_library_state(&mut self) {
|
||||
self.hint_dynamic();
|
||||
}
|
||||
|
||||
fn linker_plugin_lto(&mut self) {}
|
||||
|
||||
fn add_eh_frame_header(&mut self) {}
|
||||
|
||||
fn add_no_exec(&mut self) {}
|
||||
|
||||
fn add_as_needed(&mut self) {}
|
||||
}
|
||||
|
||||
fn for_each_exported_symbols_include_dep<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
crate_type: CrateType,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::{sym, Symbol};
|
||||
|
|
@ -769,23 +769,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
None => bx.fn_abi_of_fn_ptr(sig, extra_args),
|
||||
};
|
||||
|
||||
if intrinsic == Some(sym::transmute) {
|
||||
return if let Some(target) = target {
|
||||
self.codegen_transmute(bx, &args[0], destination);
|
||||
helper.funclet_br(self, bx, target, mergeable_succ)
|
||||
} else {
|
||||
// If we are trying to transmute to an uninhabited type,
|
||||
// it is likely there is no allotted destination. In fact,
|
||||
// transmuting to an uninhabited type is UB, which means
|
||||
// we can do what we like. Here, we declare that transmuting
|
||||
// into an uninhabited type is impossible, so anything following
|
||||
// it must be unreachable.
|
||||
assert_eq!(fn_abi.ret.layout.abi, abi::Abi::Uninhabited);
|
||||
bx.unreachable();
|
||||
MergingSucc::False
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(merging_succ) = self.codegen_panic_intrinsic(
|
||||
&helper,
|
||||
bx,
|
||||
|
|
@ -828,7 +811,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
match intrinsic {
|
||||
None | Some(sym::drop_in_place) => {}
|
||||
Some(sym::copy_nonoverlapping) => unreachable!(),
|
||||
Some(intrinsic) => {
|
||||
let dest = match ret_dest {
|
||||
_ if fn_abi.ret.is_indirect() => llargs[0],
|
||||
|
|
@ -1739,71 +1721,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir::Place<'tcx>) {
|
||||
if let Some(index) = dst.as_local() {
|
||||
match self.locals[index] {
|
||||
LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place),
|
||||
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
|
||||
LocalRef::Operand(None) => {
|
||||
let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
|
||||
assert!(!dst_layout.ty.has_erasable_regions());
|
||||
let place = PlaceRef::alloca(bx, dst_layout);
|
||||
place.storage_live(bx);
|
||||
self.codegen_transmute_into(bx, src, place);
|
||||
let op = bx.load_operand(place);
|
||||
place.storage_dead(bx);
|
||||
self.locals[index] = LocalRef::Operand(Some(op));
|
||||
self.debug_introduce_local(bx, index);
|
||||
}
|
||||
LocalRef::Operand(Some(op)) => {
|
||||
assert!(op.layout.is_zst(), "assigning to initialized SSAtemp");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let dst = self.codegen_place(bx, dst.as_ref());
|
||||
self.codegen_transmute_into(bx, src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
fn codegen_transmute_into(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
src: &mir::Operand<'tcx>,
|
||||
dst: PlaceRef<'tcx, Bx::Value>,
|
||||
) {
|
||||
let src = self.codegen_operand(bx, src);
|
||||
|
||||
// Special-case transmutes between scalars as simple bitcasts.
|
||||
match (src.layout.abi, dst.layout.abi) {
|
||||
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
|
||||
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
|
||||
let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
|
||||
let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
|
||||
if src_is_ptr == dst_is_ptr {
|
||||
assert_eq!(src.layout.size, dst.layout.size);
|
||||
|
||||
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
|
||||
// conversions allow handling `bool`s the same as `u8`s.
|
||||
let src = bx.from_immediate(src.immediate());
|
||||
// LLVM also doesn't like `bitcast`s between pointers in different address spaces.
|
||||
let src_as_dst = if src_is_ptr {
|
||||
bx.pointercast(src, bx.backend_type(dst.layout))
|
||||
} else {
|
||||
bx.bitcast(src, bx.backend_type(dst.layout))
|
||||
};
|
||||
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let llty = bx.backend_type(src.layout);
|
||||
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
|
||||
let align = src.layout.align.abi.min(dst.align);
|
||||
src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, align));
|
||||
}
|
||||
|
||||
// Stores the return value of a function call into it's final location.
|
||||
fn store_return(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
|
|||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
|
||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::abi::{self, VariantIdx};
|
||||
|
||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
#[instrument(level = "trace", skip(self, bx))]
|
||||
|
|
@ -72,6 +72,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
|
||||
let src = self.codegen_operand(bx, operand);
|
||||
self.codegen_transmute(bx, src, dest);
|
||||
}
|
||||
|
||||
mir::Rvalue::Repeat(ref elem, count) => {
|
||||
let cg_elem = self.codegen_operand(bx, elem);
|
||||
|
||||
|
|
@ -143,6 +148,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn codegen_transmute(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
src: OperandRef<'tcx, Bx::Value>,
|
||||
dst: PlaceRef<'tcx, Bx::Value>,
|
||||
) {
|
||||
// The MIR validator enforces no unsized transmutes.
|
||||
debug_assert!(src.layout.is_sized());
|
||||
debug_assert!(dst.layout.is_sized());
|
||||
|
||||
if src.layout.size != dst.layout.size
|
||||
|| src.layout.abi == abi::Abi::Uninhabited
|
||||
|| dst.layout.abi == abi::Abi::Uninhabited
|
||||
{
|
||||
// In all of these cases it's UB to run this transmute, but that's
|
||||
// known statically so might as well trap for it, rather than just
|
||||
// making it unreachable.
|
||||
bx.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
let size_in_bytes = src.layout.size.bytes();
|
||||
if size_in_bytes == 0 {
|
||||
// Nothing to write
|
||||
return;
|
||||
}
|
||||
|
||||
match src.val {
|
||||
OperandValue::Ref(src_llval, meta, src_align) => {
|
||||
debug_assert_eq!(meta, None);
|
||||
// For a place-to-place transmute, call `memcpy` directly so that
|
||||
// both arguments get the best-available alignment information.
|
||||
let bytes = bx.cx().const_usize(size_in_bytes);
|
||||
let flags = MemFlags::empty();
|
||||
bx.memcpy(dst.llval, dst.align, src_llval, src_align, bytes, flags);
|
||||
}
|
||||
OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
|
||||
// When we have immediate(s), the alignment of the source is irrelevant,
|
||||
// so we can store them using the destination's alignment.
|
||||
let llty = bx.backend_type(src.layout);
|
||||
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
|
||||
src.val.store(bx, PlaceRef::new_sized_aligned(cast_ptr, src.layout, dst.align));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_rvalue_unsized(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
|
|
@ -344,6 +395,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
};
|
||||
OperandValue::Immediate(newval)
|
||||
}
|
||||
mir::CastKind::Transmute => {
|
||||
bug!("Transmute operand {:?} in `codegen_rvalue_operand`", operand);
|
||||
}
|
||||
};
|
||||
OperandRef { val, layout: cast }
|
||||
}
|
||||
|
|
@ -673,6 +727,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
|
||||
match *rvalue {
|
||||
mir::Rvalue::Cast(mir::CastKind::Transmute, ..) =>
|
||||
// FIXME: Now that transmute is an Rvalue, it would be nice if
|
||||
// it could create `Immediate`s for scalars, where possible.
|
||||
false,
|
||||
mir::Rvalue::Ref(..) |
|
||||
mir::Rvalue::CopyForDeref(..) |
|
||||
mir::Rvalue::AddressOf(..) |
|
||||
|
|
|
|||
|
|
@ -133,6 +133,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
bug!()
|
||||
}
|
||||
}
|
||||
|
||||
Transmute => {
|
||||
assert!(src.layout.is_sized());
|
||||
assert!(dest.layout.is_sized());
|
||||
if src.layout.size != dest.layout.size {
|
||||
throw_ub_format!(
|
||||
"transmuting from {}-byte type to {}-byte type: `{}` -> `{}`",
|
||||
src.layout.size.bytes(),
|
||||
dest.layout.size.bytes(),
|
||||
src.layout.ty,
|
||||
dest.layout.ty,
|
||||
);
|
||||
}
|
||||
|
||||
self.copy_op(src, dest, /*allow_transmute*/ true)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// First handle intrinsics without return place.
|
||||
let ret = match ret {
|
||||
None => match intrinsic_name {
|
||||
sym::transmute => throw_ub_format!("transmuting to uninhabited type"),
|
||||
sym::abort => M::abort(self, "the program aborted execution".to_owned())?,
|
||||
// Unsupported diverging intrinsic.
|
||||
_ => return Ok(false),
|
||||
|
|
@ -411,9 +410,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.exact_div(&val, &size, dest)?;
|
||||
}
|
||||
|
||||
sym::transmute => {
|
||||
self.copy_op(&args[0], dest, /*allow_transmute*/ true)?;
|
||||
}
|
||||
sym::assert_inhabited
|
||||
| sym::assert_zero_valid
|
||||
| sym::assert_mem_uninitialized_valid => {
|
||||
|
|
|
|||
|
|
@ -621,6 +621,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
if let MirPhase::Runtime(..) = self.mir_phase {
|
||||
// Unlike `mem::transmute`, a MIR `Transmute` is well-formed
|
||||
// for any two `Sized` types, just potentially UB to run.
|
||||
|
||||
if !op_ty.is_sized(self.tcx, self.param_env) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
|
||||
);
|
||||
}
|
||||
if !target_type.is_sized(self.tcx, self.param_env) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot transmute to non-`Sized` type {target_type:?}"),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Transmute is not supported in non-runtime phase {:?}.",
|
||||
self.mir_phase
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::Repeat(_, _)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -353,7 +356,7 @@ fn run_compiler(
|
|||
|
||||
{
|
||||
let plugins = queries.register_plugins()?;
|
||||
let (_, lint_store) = &*plugins.borrow();
|
||||
let (.., lint_store) = &*plugins.borrow();
|
||||
|
||||
// Lint plugins are registered; now we can process command line flags.
|
||||
if sess.opts.describe_lints {
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1002,6 +1002,7 @@ pub struct ExpansionData {
|
|||
pub struct ExtCtxt<'a> {
|
||||
pub sess: &'a Session,
|
||||
pub ecfg: expand::ExpansionConfig<'a>,
|
||||
pub num_standard_library_imports: usize,
|
||||
pub reduced_recursion_limit: Option<Limit>,
|
||||
pub root_path: PathBuf,
|
||||
pub resolver: &'a mut dyn ResolverExpand,
|
||||
|
|
@ -1030,6 +1031,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
ExtCtxt {
|
||||
sess,
|
||||
ecfg,
|
||||
num_standard_library_imports: 0,
|
||||
reduced_recursion_limit: None,
|
||||
resolver,
|
||||
lint_store,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ use rustc_session::Session;
|
|||
use rustc_span::edition::{Edition, ALL_EDITIONS};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// A folder that strips out items that do not belong in the current configuration.
|
||||
pub struct StripUnconfigured<'a> {
|
||||
|
|
@ -37,7 +36,7 @@ pub struct StripUnconfigured<'a> {
|
|||
pub lint_node_id: NodeId,
|
||||
}
|
||||
|
||||
fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
|
||||
pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
fn feature_removed(sess: &Session, span: Span, reason: Option<&str>) {
|
||||
sess.emit_err(FeatureRemoved {
|
||||
span,
|
||||
|
|
@ -191,39 +190,16 @@ fn get_features(sess: &Session, krate_attrs: &[ast::Attribute]) -> Features {
|
|||
features
|
||||
}
|
||||
|
||||
/// `cfg_attr`-process the crate's attributes and compute the crate's features.
|
||||
pub fn features(
|
||||
sess: &Session,
|
||||
mut krate: ast::Crate,
|
||||
lint_node_id: NodeId,
|
||||
) -> (ast::Crate, Features) {
|
||||
let mut strip_unconfigured =
|
||||
StripUnconfigured { sess, features: None, config_tokens: false, lint_node_id };
|
||||
|
||||
let unconfigured_attrs = krate.attrs.clone();
|
||||
let diag = &sess.parse_sess.span_diagnostic;
|
||||
let err_count = diag.err_count();
|
||||
let features = match strip_unconfigured.configure_krate_attrs(krate.attrs) {
|
||||
None => {
|
||||
// The entire crate is unconfigured.
|
||||
krate.attrs = ast::AttrVec::new();
|
||||
krate.items = ThinVec::new();
|
||||
Features::default()
|
||||
}
|
||||
Some(attrs) => {
|
||||
krate.attrs = attrs;
|
||||
let features = get_features(sess, &krate.attrs);
|
||||
if err_count == diag.err_count() {
|
||||
// Avoid reconfiguring malformed `cfg_attr`s.
|
||||
strip_unconfigured.features = Some(&features);
|
||||
// Run configuration again, this time with features available
|
||||
// so that we can perform feature-gating.
|
||||
strip_unconfigured.configure_krate_attrs(unconfigured_attrs);
|
||||
}
|
||||
features
|
||||
}
|
||||
pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec {
|
||||
let strip_unconfigured = StripUnconfigured {
|
||||
sess,
|
||||
features: None,
|
||||
config_tokens: false,
|
||||
lint_node_id: ast::CRATE_NODE_ID,
|
||||
};
|
||||
(krate, features)
|
||||
let attrs: ast::AttrVec =
|
||||
attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
|
||||
if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
@ -254,11 +230,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn configure_krate_attrs(&self, mut attrs: ast::AttrVec) -> Option<ast::AttrVec> {
|
||||
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
|
||||
self.in_cfg(&attrs).then_some(attrs)
|
||||
}
|
||||
|
||||
/// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`.
|
||||
/// This is only used during the invocation of `derive` proc-macros,
|
||||
/// which require that we cfg-expand their entire input.
|
||||
|
|
@ -281,7 +252,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
.iter()
|
||||
.flat_map(|tree| match tree.clone() {
|
||||
AttrTokenTree::Attributes(mut data) => {
|
||||
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
|
||||
data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
|
||||
|
||||
if self.in_cfg(&data.attrs) {
|
||||
data.tokens = LazyAttrTokenStream::new(
|
||||
|
|
@ -319,12 +290,16 @@ impl<'a> StripUnconfigured<'a> {
|
|||
/// the syntax of any `cfg_attr` is incorrect.
|
||||
fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) {
|
||||
node.visit_attrs(|attrs| {
|
||||
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
|
||||
attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
|
||||
});
|
||||
}
|
||||
|
||||
fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
|
||||
if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] }
|
||||
fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> {
|
||||
if attr.has_name(sym::cfg_attr) {
|
||||
self.expand_cfg_attr(attr, true)
|
||||
} else {
|
||||
vec![attr.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse and expand a single `cfg_attr` attribute into a list of attributes
|
||||
|
|
@ -334,9 +309,9 @@ impl<'a> StripUnconfigured<'a> {
|
|||
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
|
||||
/// is in the original source file. Gives a compiler error if the syntax of
|
||||
/// the attribute is incorrect.
|
||||
pub(crate) fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
|
||||
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
|
||||
let Some((cfg_predicate, expanded_attrs)) =
|
||||
rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) else {
|
||||
rustc_parse::parse_cfg_attr(attr, &self.sess.parse_sess) else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
|
|
@ -365,10 +340,10 @@ impl<'a> StripUnconfigured<'a> {
|
|||
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
|
||||
expanded_attrs
|
||||
.into_iter()
|
||||
.flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item)))
|
||||
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(attr, item)))
|
||||
.collect()
|
||||
} else {
|
||||
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect()
|
||||
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(attr, item)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,9 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
|||
) -> Result<Self::OutputTy, Self> {
|
||||
Ok(noop_flat_map(node, collector))
|
||||
}
|
||||
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
|
||||
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
|
||||
}
|
||||
}
|
||||
|
||||
impl InvocationCollectorNode for P<ast::Item> {
|
||||
|
|
@ -1378,6 +1381,11 @@ impl InvocationCollectorNode for ast::Crate {
|
|||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_crate(self, visitor)
|
||||
}
|
||||
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
|
||||
self.attrs.clear();
|
||||
// Standard prelude imports are left in the crate for backward compatibility.
|
||||
self.items.truncate(collector.cx.num_standard_library_imports);
|
||||
}
|
||||
}
|
||||
|
||||
impl InvocationCollectorNode for P<ast::Ty> {
|
||||
|
|
@ -1688,7 +1696,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
res
|
||||
}
|
||||
|
||||
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: ast::Attribute, pos: usize) {
|
||||
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
|
||||
node.visit_attrs(|attrs| {
|
||||
// Repeated `insert` calls is inefficient, but the number of
|
||||
// insertions is almost always 0 or 1 in practice.
|
||||
|
|
@ -1712,7 +1720,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
Default::default()
|
||||
}
|
||||
sym::cfg_attr => {
|
||||
self.expand_cfg_attr(&mut node, attr, pos);
|
||||
self.expand_cfg_attr(&mut node, &attr, pos);
|
||||
continue;
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -1756,11 +1764,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
continue;
|
||||
}
|
||||
|
||||
self.cx.emit_err(RemoveNodeNotSupported { span, descr: Node::descr() });
|
||||
node.expand_cfg_false(self, span);
|
||||
continue;
|
||||
}
|
||||
sym::cfg_attr => {
|
||||
self.expand_cfg_attr(node, attr, pos);
|
||||
self.expand_cfg_attr(node, &attr, pos);
|
||||
continue;
|
||||
}
|
||||
_ => visit_clobber(node, |node| {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1336,7 +1336,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
|
||||
},
|
||||
ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(_, _, _)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
|
|
@ -97,12 +97,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(simp) = simplify_type(
|
||||
self.tcx,
|
||||
self_ty,
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) {
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
||||
} else {
|
||||
bug!("unexpected self type: {:?}", self_ty);
|
||||
|
|
@ -162,12 +157,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(simp) = simplify_type(
|
||||
self.tcx,
|
||||
ty,
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) {
|
||||
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
|
||||
} else {
|
||||
bug!("unexpected primitive type: {:?}", ty);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ fn trait_predicate_kind<'tcx>(
|
|||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
// N.B., this predicate is created by breaking down a
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_hir::def::Res;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_span::{self, symbol::kw, Span};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
|
@ -25,17 +25,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
|
||||
_ => ty::List::empty(),
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs.to_vec(),
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
|
||||
pred.projection_ty.substs.to_vec()
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(arg, ty)) => {
|
||||
vec![ty.into(), arg.into()]
|
||||
}
|
||||
ty::PredicateKind::ConstEvaluatable(e) => vec![e.into()],
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
|
||||
predicate_substs.types().find_map(|ty| {
|
||||
ty.walk().find_map(|arg| {
|
||||
let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| {
|
||||
predicate_substs.iter().find_map(|arg| {
|
||||
arg.walk().find_map(|arg| {
|
||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Param(param_ty) = ty.kind()
|
||||
&& matches(param_ty)
|
||||
&& let ty::Param(param_ty) = *ty.kind()
|
||||
&& matches(ty::ParamTerm::Ty(param_ty))
|
||||
{
|
||||
Some(arg)
|
||||
} else if let ty::GenericArgKind::Const(ct) = arg.unpack()
|
||||
&& let ty::ConstKind::Param(param_ct) = ct.kind()
|
||||
&& matches(ty::ParamTerm::Const(param_ct))
|
||||
{
|
||||
Some(arg)
|
||||
} else {
|
||||
|
|
@ -47,21 +58,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Prefer generics that are local to the fn item, since these are likely
|
||||
// to be the cause of the unsatisfied predicate.
|
||||
let mut param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
|
||||
let mut param_to_point_at = find_param_matching(&|param_term| {
|
||||
self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) == def_id
|
||||
});
|
||||
// Fall back to generic that isn't local to the fn item. This will come
|
||||
// from a trait or impl, for example.
|
||||
let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
|
||||
self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
|
||||
&& param_ty.name != rustc_span::symbol::kw::SelfUpper
|
||||
let mut fallback_param_to_point_at = find_param_matching(&|param_term| {
|
||||
self.tcx.parent(generics.param_at(param_term.index(), self.tcx).def_id) != def_id
|
||||
&& !matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper)
|
||||
});
|
||||
// Finally, the `Self` parameter is possibly the reason that the predicate
|
||||
// is unsatisfied. This is less likely to be true for methods, because
|
||||
// method probe means that we already kinda check that the predicates due
|
||||
// to the `Self` type are true.
|
||||
let mut self_param_to_point_at =
|
||||
find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
|
||||
let mut self_param_to_point_at = find_param_matching(
|
||||
&|param_term| matches!(param_term, ty::ParamTerm::Ty(ty) if ty.name == kw::SelfUpper),
|
||||
);
|
||||
|
||||
// Finally, for ambiguity-related errors, we actually want to look
|
||||
// for a parameter that is the source of the inference type left
|
||||
|
|
@ -225,14 +237,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
|
||||
let Some((index, _)) = own_substs
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
|
||||
.enumerate()
|
||||
.find(|(_, arg)| **arg == param_to_point_at) else { return false };
|
||||
let Some(arg) = segment
|
||||
.args()
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
|
||||
.nth(index) else { return false; };
|
||||
error.obligation.cause.span = arg
|
||||
.span()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
|||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::fast_reject::TreatProjections;
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
||||
use rustc_middle::ty::AssocItem;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
|
|
@ -701,7 +700,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
|
||||
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey) else {
|
||||
let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else {
|
||||
bug!("unexpected incoherent type: {:?}", self_ty)
|
||||
};
|
||||
for &impl_def_id in self.tcx.incoherent_impls(simp) {
|
||||
|
|
@ -838,7 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ use rustc_infer::infer::{
|
|||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::traits::util::supertraits;
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::fast_reject::TreatProjections;
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
||||
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
|
@ -1524,7 +1523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.into_iter()
|
||||
.any(|info| self.associated_value(info.def_id, item_name).is_some());
|
||||
let found_assoc = |ty: Ty<'tcx>| {
|
||||
simplify_type(tcx, ty, TreatParams::AsCandidateKey, TreatProjections::AsCandidateKey)
|
||||
simplify_type(tcx, ty, TreatParams::AsCandidateKey)
|
||||
.and_then(|simp| {
|
||||
tcx.incoherent_impls(simp)
|
||||
.iter()
|
||||
|
|
@ -2653,12 +2652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// FIXME: Even though negative bounds are not implemented, we could maybe handle
|
||||
// cases where a positive bound implies a negative impl.
|
||||
(candidates, Vec::new())
|
||||
} else if let Some(simp_rcvr_ty) = simplify_type(
|
||||
self.tcx,
|
||||
rcvr_ty,
|
||||
TreatParams::ForLookup,
|
||||
TreatProjections::ForLookup,
|
||||
) {
|
||||
} else if let Some(simp_rcvr_ty) =
|
||||
simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup)
|
||||
{
|
||||
let mut potential_candidates = Vec::new();
|
||||
let mut explicitly_negative = Vec::new();
|
||||
for candidate in candidates {
|
||||
|
|
@ -2671,12 +2667,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
.any(|imp_did| {
|
||||
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
|
||||
let imp_simp = simplify_type(
|
||||
self.tcx,
|
||||
imp.self_ty(),
|
||||
TreatParams::ForLookup,
|
||||
TreatProjections::ForLookup,
|
||||
);
|
||||
let imp_simp =
|
||||
simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
|
||||
imp_simp.map_or(false, |s| s == simp_rcvr_ty)
|
||||
})
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
(_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
|
||||
if self.tcx.trait_solver_next() =>
|
||||
{
|
||||
relation.register_type_equate_obligation(a, b);
|
||||
relation.register_type_relate_obligation(a, b);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
|
|
@ -842,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
|
|||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
|
||||
ty::PredicateKind::AliasEq(a.into(), b.into())
|
||||
ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
|
||||
} else {
|
||||
ty::PredicateKind::ConstEquate(a, b)
|
||||
})]);
|
||||
}
|
||||
|
||||
/// Register an obligation that both types must be equal to each other.
|
||||
///
|
||||
/// If they aren't equal then the relation doesn't hold.
|
||||
fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
|
||||
/// Register an obligation that both types must be related to each other according to
|
||||
/// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
self.alias_relate_direction(),
|
||||
))]);
|
||||
}
|
||||
|
||||
/// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
|
||||
/// of the relation.
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
|
||||
}
|
||||
|
||||
fn int_unification_error<'tcx>(
|
||||
|
|
|
|||
|
|
@ -210,4 +210,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
|||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,4 +155,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
|||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations)
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): This isn't right, I think?
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -711,6 +711,34 @@ where
|
|||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.delegate.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
|
||||
}
|
||||
|
||||
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
|
||||
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
// a :> b is b <: a
|
||||
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
|
||||
b.into(),
|
||||
a.into(),
|
||||
ty::AliasRelationDirection::Subtype,
|
||||
),
|
||||
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
|
||||
a.into(),
|
||||
b.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
// FIXME(deferred_projection_equality): Implement this when we trigger it.
|
||||
// Probably just need to do nothing here.
|
||||
ty::Variance::Bivariant => unreachable!(),
|
||||
})]);
|
||||
}
|
||||
}
|
||||
|
||||
/// When we encounter a binder like `for<..> fn(..)`, we actually have
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub fn explicit_outlives_bounds<'tcx>(
|
|||
ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::WellFormed(..)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// completely change the normalization routine with the new solver.
|
||||
//
|
||||
// The new solver correctly handles projection equality so this hack
|
||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
|
||||
// is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
|
||||
// not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
|
||||
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
|
||||
return projection_ty.to_ty(self.tcx);
|
||||
|
|
|
|||
|
|
@ -236,4 +236,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
|
||||
self.fields.register_obligations(obligations);
|
||||
}
|
||||
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
ty::AliasRelationDirection::Subtype
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
// Nothing to elaborate
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(..) => {
|
||||
ty::PredicateKind::AliasRelate(..) => {
|
||||
// No
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use crate::interface::{Compiler, Result};
|
|||
use crate::proc_macro_decls;
|
||||
use crate::util;
|
||||
|
||||
use ast::CRATE_NODE_ID;
|
||||
use rustc_ast::{self as ast, visit};
|
||||
use rustc_borrowck as mir_borrowck;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
|
|
@ -12,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;
|
||||
|
|
@ -76,22 +76,14 @@ pub fn register_plugins<'a>(
|
|||
sess: &'a Session,
|
||||
metadata_loader: &'a dyn MetadataLoader,
|
||||
register_lints: impl Fn(&Session, &mut LintStore),
|
||||
mut krate: ast::Crate,
|
||||
pre_configured_attrs: &[ast::Attribute],
|
||||
crate_name: Symbol,
|
||||
) -> Result<(ast::Crate, LintStore)> {
|
||||
krate = sess.time("attributes_injection", || {
|
||||
rustc_builtin_macros::cmdline_attrs::inject(
|
||||
krate,
|
||||
&sess.parse_sess,
|
||||
&sess.opts.unstable_opts.crate_attr,
|
||||
)
|
||||
});
|
||||
|
||||
let (krate, features) = rustc_expand::config::features(sess, krate, CRATE_NODE_ID);
|
||||
) -> Result<LintStore> {
|
||||
// these need to be set "early" so that expansion sees `quote` if enabled.
|
||||
let features = rustc_expand::config::features(sess, pre_configured_attrs);
|
||||
sess.init_features(features);
|
||||
|
||||
let crate_types = util::collect_crate_types(sess, &krate.attrs);
|
||||
let crate_types = util::collect_crate_types(sess, pre_configured_attrs);
|
||||
sess.init_crate_types(crate_types);
|
||||
|
||||
let stable_crate_id = StableCrateId::new(
|
||||
|
|
@ -117,8 +109,9 @@ pub fn register_plugins<'a>(
|
|||
let mut lint_store = rustc_lint::new_lint_store(sess.enable_internal_lints());
|
||||
register_lints(sess, &mut lint_store);
|
||||
|
||||
let registrars =
|
||||
sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate));
|
||||
let registrars = sess.time("plugin_loading", || {
|
||||
plugin::load::load_plugins(sess, metadata_loader, pre_configured_attrs)
|
||||
});
|
||||
sess.time("plugin_registration", || {
|
||||
let mut registry = plugin::Registry { lint_store: &mut lint_store };
|
||||
for registrar in registrars {
|
||||
|
|
@ -126,7 +119,7 @@ pub fn register_plugins<'a>(
|
|||
}
|
||||
});
|
||||
|
||||
Ok((krate, lint_store))
|
||||
Ok(lint_store)
|
||||
}
|
||||
|
||||
fn pre_expansion_lint<'a>(
|
||||
|
|
@ -173,19 +166,29 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
|
|||
/// harness if one is to be provided, injection of a dependency on the
|
||||
/// standard library and prelude, and name resolution.
|
||||
#[instrument(level = "trace", skip(krate, resolver))]
|
||||
fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) -> ast::Crate {
|
||||
fn configure_and_expand(
|
||||
mut krate: ast::Crate,
|
||||
pre_configured_attrs: &[ast::Attribute],
|
||||
resolver: &mut Resolver<'_, '_>,
|
||||
) -> ast::Crate {
|
||||
let tcx = resolver.tcx();
|
||||
let sess = tcx.sess;
|
||||
let lint_store = unerased_lint_store(tcx);
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), &krate, crate_name);
|
||||
let lint_check_node = (&krate, pre_configured_attrs);
|
||||
pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name);
|
||||
rustc_builtin_macros::register_builtin_macros(resolver);
|
||||
|
||||
krate = sess.time("crate_injection", || {
|
||||
rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess)
|
||||
let num_standard_library_imports = sess.time("crate_injection", || {
|
||||
rustc_builtin_macros::standard_library_imports::inject(
|
||||
&mut krate,
|
||||
pre_configured_attrs,
|
||||
resolver,
|
||||
sess,
|
||||
)
|
||||
});
|
||||
|
||||
util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
|
||||
util::check_attr_crate_type(sess, pre_configured_attrs, &mut resolver.lint_buffer());
|
||||
|
||||
// Expand all macros
|
||||
krate = sess.time("macro_expand_crate", || {
|
||||
|
|
@ -222,7 +225,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
|
|||
|
||||
// Create the config for macro expansion
|
||||
let features = sess.features_untracked();
|
||||
let recursion_limit = get_recursion_limit(&krate.attrs, sess);
|
||||
let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
|
||||
let cfg = rustc_expand::expand::ExpansionConfig {
|
||||
features: Some(features),
|
||||
recursion_limit,
|
||||
|
|
@ -235,6 +238,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
|
|||
|
||||
let lint_store = LintStoreExpandImpl(lint_store);
|
||||
let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
|
||||
ecx.num_standard_library_imports = num_standard_library_imports;
|
||||
// Expand macros now!
|
||||
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
|
||||
|
||||
|
|
@ -263,7 +267,7 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
|
|||
});
|
||||
|
||||
sess.time("maybe_building_test_harness", || {
|
||||
rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate)
|
||||
rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver)
|
||||
});
|
||||
|
||||
let has_proc_macro_decls = sess.time("AST_validation", || {
|
||||
|
|
@ -287,12 +291,12 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>)
|
|||
sess.emit_warning(errors::ProcMacroCratePanicAbort);
|
||||
}
|
||||
|
||||
krate = sess.time("maybe_create_a_macro_crate", || {
|
||||
sess.time("maybe_create_a_macro_crate", || {
|
||||
let is_test_crate = sess.opts.test;
|
||||
rustc_builtin_macros::proc_macro_harness::inject(
|
||||
&mut krate,
|
||||
sess,
|
||||
resolver,
|
||||
krate,
|
||||
is_proc_macro_crate,
|
||||
has_proc_macro_decls,
|
||||
is_test_crate,
|
||||
|
|
@ -356,7 +360,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
|
|||
tcx.registered_tools(()),
|
||||
Some(lint_buffer),
|
||||
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
|
||||
&**krate,
|
||||
(&**krate, &*krate.attrs),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -405,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()
|
||||
}
|
||||
|
|
@ -557,9 +561,9 @@ fn resolver_for_lowering<'tcx>(
|
|||
) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc<ast::Crate>)> {
|
||||
let arenas = Resolver::arenas();
|
||||
let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
|
||||
let krate = tcx.crate_for_resolver(()).steal();
|
||||
let mut resolver = Resolver::new(tcx, &krate, &arenas);
|
||||
let krate = configure_and_expand(krate, &mut resolver);
|
||||
let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
|
||||
let mut resolver = Resolver::new(tcx, &pre_configured_attrs, krate.spans.inner_span, &arenas);
|
||||
let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
|
||||
|
||||
// Make sure we don't mutate the cstore from here on.
|
||||
tcx.untracked().cstore.leak();
|
||||
|
|
|
|||
|
|
@ -88,8 +88,9 @@ pub struct Queries<'tcx> {
|
|||
|
||||
dep_graph_future: Query<Option<DepGraphFuture>>,
|
||||
parse: Query<ast::Crate>,
|
||||
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
|
||||
crate_name: Query<Symbol>,
|
||||
register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
|
||||
register_plugins: Query<(ast::Crate, ast::AttrVec, Lrc<LintStore>)>,
|
||||
dep_graph: Query<DepGraph>,
|
||||
// This just points to what's in `gcx_cell`.
|
||||
gcx: Query<&'tcx GlobalCtxt<'tcx>>,
|
||||
|
|
@ -106,6 +107,7 @@ impl<'tcx> Queries<'tcx> {
|
|||
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
|
||||
dep_graph_future: Default::default(),
|
||||
parse: Default::default(),
|
||||
pre_configure: Default::default(),
|
||||
crate_name: Default::default(),
|
||||
register_plugins: Default::default(),
|
||||
dep_graph: Default::default(),
|
||||
|
|
@ -133,17 +135,36 @@ impl<'tcx> Queries<'tcx> {
|
|||
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
|
||||
}
|
||||
|
||||
pub fn register_plugins(&self) -> Result<QueryResult<'_, (ast::Crate, Lrc<LintStore>)>> {
|
||||
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
|
||||
self.pre_configure.compute(|| {
|
||||
let mut krate = self.parse()?.steal();
|
||||
|
||||
let sess = self.session();
|
||||
rustc_builtin_macros::cmdline_attrs::inject(
|
||||
&mut krate,
|
||||
&sess.parse_sess,
|
||||
&sess.opts.unstable_opts.crate_attr,
|
||||
);
|
||||
|
||||
let pre_configured_attrs =
|
||||
rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
|
||||
Ok((krate, pre_configured_attrs))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register_plugins(
|
||||
&self,
|
||||
) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec, Lrc<LintStore>)>> {
|
||||
self.register_plugins.compute(|| {
|
||||
let crate_name = *self.crate_name()?.borrow();
|
||||
let krate = self.parse()?.steal();
|
||||
let (krate, pre_configured_attrs) = self.pre_configure()?.steal();
|
||||
|
||||
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
|
||||
let (krate, lint_store) = passes::register_plugins(
|
||||
let lint_store = passes::register_plugins(
|
||||
self.session(),
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
|
||||
krate,
|
||||
&pre_configured_attrs,
|
||||
crate_name,
|
||||
)?;
|
||||
|
||||
|
|
@ -154,17 +175,17 @@ impl<'tcx> Queries<'tcx> {
|
|||
// called, which happens within passes::register_plugins().
|
||||
self.dep_graph_future().ok();
|
||||
|
||||
Ok((krate, Lrc::new(lint_store)))
|
||||
Ok((krate, pre_configured_attrs, Lrc::new(lint_store)))
|
||||
})
|
||||
}
|
||||
|
||||
fn crate_name(&self) -> Result<QueryResult<'_, Symbol>> {
|
||||
self.crate_name.compute(|| {
|
||||
Ok({
|
||||
let parse_result = self.parse()?;
|
||||
let krate = parse_result.borrow();
|
||||
let pre_configure_result = self.pre_configure()?;
|
||||
let (_, pre_configured_attrs) = &*pre_configure_result.borrow();
|
||||
// parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
|
||||
find_crate_name(self.session(), &krate.attrs)
|
||||
find_crate_name(self.session(), pre_configured_attrs)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -188,7 +209,7 @@ impl<'tcx> Queries<'tcx> {
|
|||
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
|
||||
self.gcx.compute(|| {
|
||||
let crate_name = *self.crate_name()?.borrow();
|
||||
let (krate, lint_store) = self.register_plugins()?.steal();
|
||||
let (krate, pre_configured_attrs, lint_store) = self.register_plugins()?.steal();
|
||||
|
||||
let sess = self.session();
|
||||
|
||||
|
|
@ -215,7 +236,7 @@ impl<'tcx> Queries<'tcx> {
|
|||
feed.crate_name(crate_name);
|
||||
|
||||
let feed = tcx.feed_unit_query();
|
||||
feed.crate_for_resolver(tcx.arena.alloc(Steal::new(krate)));
|
||||
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
|
||||
feed.metadata_loader(
|
||||
tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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}`
|
||||
|
|
|
|||
|
|
@ -1600,7 +1600,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
|||
// Ignore projections, as they can only be global
|
||||
// if the trait bound is global
|
||||
Clause(Clause::Projection(..)) |
|
||||
AliasEq(..) |
|
||||
AliasRelate(..) |
|
||||
// Ignore bounds that a user can't type
|
||||
WellFormed(..) |
|
||||
ObjectSafe(..) |
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ pub trait EarlyCheckNode<'a>: Copy {
|
|||
'a: 'b;
|
||||
}
|
||||
|
||||
impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
|
||||
impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
|
||||
fn id(self) -> ast::NodeId {
|
||||
ast::CRATE_NODE_ID
|
||||
}
|
||||
|
|
@ -348,15 +348,15 @@ impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
|
|||
where
|
||||
'a: 'b,
|
||||
{
|
||||
&self.attrs
|
||||
&self.1
|
||||
}
|
||||
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
lint_callback!(cx, check_crate, self);
|
||||
ast_visit::walk_crate(cx, self);
|
||||
lint_callback!(cx, check_crate_post, self);
|
||||
lint_callback!(cx, check_crate, self.0);
|
||||
ast_visit::walk_crate(cx, self.0);
|
||||
lint_callback!(cx, check_crate_post, self.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ declare_lint! {
|
|||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(type_alias_impl_trait)]
|
||||
///
|
||||
/// trait Duh {}
|
||||
///
|
||||
/// impl Duh for i32 {}
|
||||
|
|
@ -41,7 +43,9 @@ declare_lint! {
|
|||
/// type Assoc = F;
|
||||
/// }
|
||||
///
|
||||
/// fn test() -> impl Trait<Assoc = impl Sized> {
|
||||
/// type Tait = impl Sized;
|
||||
///
|
||||
/// fn test() -> impl Trait<Assoc = Tait> {
|
||||
/// 42
|
||||
/// }
|
||||
/// ```
|
||||
|
|
@ -54,7 +58,7 @@ declare_lint! {
|
|||
///
|
||||
/// Although the hidden type, `i32` does satisfy this bound, we do not
|
||||
/// consider the return type to be well-formed with this lint. It can be
|
||||
/// fixed by changing `impl Sized` into `impl Sized + Send`.
|
||||
/// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`.
|
||||
pub OPAQUE_HIDDEN_INFERRED_BOUND,
|
||||
Warn,
|
||||
"detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
|
||||
|
|
@ -64,7 +68,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
|
||||
let hir::ItemKind::OpaqueTy(opaque) = &item.kind else { return; };
|
||||
let def_id = item.owner_id.def_id.to_def_id();
|
||||
let infcx = &cx.tcx.infer_ctxt().build();
|
||||
// For every projection predicate in the opaque type's explicit bounds,
|
||||
|
|
@ -81,6 +85,17 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
|||
// have opaques in them anyways.
|
||||
let Some(proj_term) = proj.term.ty() else { continue };
|
||||
|
||||
// HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"...
|
||||
if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind()
|
||||
&& cx.tcx.parent(opaque_ty.def_id) == def_id
|
||||
&& matches!(
|
||||
opaque.origin,
|
||||
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let proj_ty =
|
||||
cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs);
|
||||
// For every instance of the projection type in the bounds,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,10 +925,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
tcx.mk_adt_def(did, adt_kind, variants, repr)
|
||||
}
|
||||
|
||||
fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
|
||||
self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
|
||||
}
|
||||
|
||||
fn get_visibility(self, id: DefIndex) -> Visibility<DefId> {
|
||||
self.root
|
||||
.tables
|
||||
|
|
@ -1045,13 +1041,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
self.root.tables.optimized_mir.get(self, id).is_some()
|
||||
}
|
||||
|
||||
fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
match self.def_kind(id) {
|
||||
DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess),
|
||||
_ => panic!("Expected module, found {:?}", self.local_def_id(id)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool {
|
||||
self.root
|
||||
.tables
|
||||
|
|
|
|||
|
|
@ -490,6 +490,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
|||
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
|
||||
},
|
||||
crates: |tcx, ()| {
|
||||
// The list of loaded crates is now frozen in query cache,
|
||||
// so make sure cstore is not mutably accessed from here on.
|
||||
tcx.untracked().cstore.leak();
|
||||
tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
|
||||
},
|
||||
..*providers
|
||||
|
|
@ -537,20 +540,16 @@ impl CStore {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn get_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
|
||||
pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
|
||||
self.get_crate_data(def_id.krate).get_span(def_id.index, sess)
|
||||
}
|
||||
|
||||
pub fn def_kind(&self, def: DefId) -> DefKind {
|
||||
pub fn def_kind_untracked(&self, def: DefId) -> DefKind {
|
||||
self.get_crate_data(def.krate).def_kind(def.index)
|
||||
}
|
||||
|
||||
pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
|
||||
self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
|
||||
}
|
||||
|
||||
pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
|
||||
self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
|
||||
pub fn expn_that_defined_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
|
||||
self.get_crate_data(def_id.krate).get_expn_that_defined(def_id.index, sess)
|
||||
}
|
||||
|
||||
/// Only public-facing way to traverse all the definitions in a non-local crate.
|
||||
|
|
@ -560,14 +559,6 @@ impl CStore {
|
|||
self.get_crate_data(cnum).num_def_ids()
|
||||
}
|
||||
|
||||
pub fn item_attrs_untracked<'a>(
|
||||
&'a self,
|
||||
def_id: DefId,
|
||||
sess: &'a Session,
|
||||
) -> impl Iterator<Item = ast::Attribute> + 'a {
|
||||
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
|
||||
}
|
||||
|
||||
pub fn get_proc_macro_quoted_span_untracked(
|
||||
&self,
|
||||
cnum: CrateNum,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_middle::mir::interpret;
|
|||
use rustc_middle::query::LocalCrate;
|
||||
use rustc_middle::traits::specialization_graph;
|
||||
use rustc_middle::ty::codec::TyEncoder;
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
|
||||
use rustc_middle::util::common::to_readable_str;
|
||||
|
|
@ -1881,7 +1881,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
self.tcx,
|
||||
trait_ref.self_ty(),
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
);
|
||||
|
||||
fx_hash_map
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ macro_rules! arena_types {
|
|||
)>,
|
||||
[] output_filenames: std::sync::Arc<rustc_session::config::OutputFilenames>,
|
||||
[] metadata_loader: rustc_data_structures::steal::Steal<Box<rustc_session::cstore::MetadataLoaderDyn>>,
|
||||
[] crate_for_resolver: rustc_data_structures::steal::Steal<rustc_ast::ast::Crate>,
|
||||
[] crate_for_resolver: rustc_data_structures::steal::Steal<(rustc_ast::Crate, rustc_ast::AttrVec)>,
|
||||
[] resolutions: rustc_middle::ty::ResolverGlobalCtxt,
|
||||
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult,
|
||||
[decode] code_region: rustc_middle::mir::coverage::CodeRegion,
|
||||
|
|
|
|||
|
|
@ -1967,7 +1967,8 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
| CastKind::PtrToPtr
|
||||
| CastKind::Pointer(_)
|
||||
| CastKind::PointerFromExposedAddress
|
||||
| CastKind::DynStar,
|
||||
| CastKind::DynStar
|
||||
| CastKind::Transmute,
|
||||
_,
|
||||
_,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1156,6 +1156,13 @@ pub enum CastKind {
|
|||
IntToFloat,
|
||||
PtrToPtr,
|
||||
FnPtrToPtr,
|
||||
/// Reinterpret the bits of the input as a different type.
|
||||
///
|
||||
/// MIR is well-formed if the input and output types have different sizes,
|
||||
/// but running a transmute between differently-sized types is UB.
|
||||
///
|
||||
/// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`].
|
||||
Transmute,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
|
|
|
|||
|
|
@ -2116,7 +2116,7 @@ rustc_queries! {
|
|||
desc { "raw operations for metadata file access" }
|
||||
}
|
||||
|
||||
query crate_for_resolver((): ()) -> &'tcx Steal<rustc_ast::ast::Crate> {
|
||||
query crate_for_resolver((): ()) -> &'tcx Steal<(rustc_ast::Crate, rustc_ast::AttrVec)> {
|
||||
feedable
|
||||
no_hash
|
||||
desc { "the ast before macro expansion and name resolution" }
|
||||
|
|
|
|||
|
|
@ -56,7 +56,15 @@ pub enum TreatParams {
|
|||
AsCandidateKey,
|
||||
/// Treat parameters as placeholders in the given environment. This is the
|
||||
/// correct mode for *lookup*, as during candidate selection.
|
||||
///
|
||||
/// This also treats projections with inference variables as infer vars
|
||||
/// since they could be further normalized.
|
||||
ForLookup,
|
||||
/// Treat parameters as placeholders in the given environment. This is the
|
||||
/// correct mode for *lookup*, as during candidate selection.
|
||||
///
|
||||
/// N.B. during deep rejection, this acts identically to `ForLookup`.
|
||||
NextSolverLookup,
|
||||
}
|
||||
|
||||
/// During fast-rejection, we have the choice of treating projection types
|
||||
|
|
@ -64,13 +72,6 @@ pub enum TreatParams {
|
|||
/// to be normalized/rigid.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum TreatProjections {
|
||||
/// In candidates, we may be able to normalize the projection
|
||||
/// after instantiating the candidate and equating it with a goal.
|
||||
///
|
||||
/// We must assume that the `impl<T> Trait<T> for <T as Id>::This`
|
||||
/// can apply to all self types so we don't return a simplified type
|
||||
/// for `<T as Id>::This`.
|
||||
AsCandidateKey,
|
||||
/// In the old solver we don't try to normalize projections
|
||||
/// when looking up impls and only access them by using the
|
||||
/// current self type. This means that if the self type is
|
||||
|
|
@ -107,7 +108,6 @@ pub fn simplify_type<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
treat_params: TreatParams,
|
||||
treat_projections: TreatProjections,
|
||||
) -> Option<SimplifiedType> {
|
||||
match *ty.kind() {
|
||||
ty::Bool => Some(BoolSimplifiedType),
|
||||
|
|
@ -136,13 +136,20 @@ pub fn simplify_type<'tcx>(
|
|||
ty::FnPtr(f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())),
|
||||
ty::Placeholder(..) => Some(PlaceholderSimplifiedType),
|
||||
ty::Param(_) => match treat_params {
|
||||
TreatParams::ForLookup => Some(PlaceholderSimplifiedType),
|
||||
TreatParams::ForLookup | TreatParams::NextSolverLookup => {
|
||||
Some(PlaceholderSimplifiedType)
|
||||
}
|
||||
TreatParams::AsCandidateKey => None,
|
||||
},
|
||||
ty::Alias(..) => match treat_projections {
|
||||
TreatProjections::ForLookup if !ty.needs_infer() => Some(PlaceholderSimplifiedType),
|
||||
TreatProjections::NextSolverLookup => Some(PlaceholderSimplifiedType),
|
||||
TreatProjections::AsCandidateKey | TreatProjections::ForLookup => None,
|
||||
ty::Alias(..) => match treat_params {
|
||||
// When treating `ty::Param` as a placeholder, projections also
|
||||
// don't unify with anything else as long as they are fully normalized.
|
||||
//
|
||||
// We will have to be careful with lazy normalization here.
|
||||
// FIXME(lazy_normalization): This is probably not right...
|
||||
TreatParams::ForLookup if !ty.has_non_region_infer() => Some(PlaceholderSimplifiedType),
|
||||
TreatParams::NextSolverLookup => Some(PlaceholderSimplifiedType),
|
||||
TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
|
||||
},
|
||||
ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)),
|
||||
ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None,
|
||||
|
|
@ -310,7 +317,7 @@ impl DeepRejectCtxt {
|
|||
// Depending on the value of `treat_obligation_params`, we either
|
||||
// treat generic parameters like placeholders or like inference variables.
|
||||
ty::Param(_) => match self.treat_obligation_params {
|
||||
TreatParams::ForLookup => false,
|
||||
TreatParams::ForLookup | TreatParams::NextSolverLookup => false,
|
||||
TreatParams::AsCandidateKey => true,
|
||||
},
|
||||
|
||||
|
|
@ -348,7 +355,7 @@ impl DeepRejectCtxt {
|
|||
let k = impl_ct.kind();
|
||||
match obligation_ct.kind() {
|
||||
ty::ConstKind::Param(_) => match self.treat_obligation_params {
|
||||
TreatParams::ForLookup => false,
|
||||
TreatParams::ForLookup | TreatParams::NextSolverLookup => false,
|
||||
TreatParams::AsCandidateKey => true,
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ impl FlagComputation {
|
|||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => {}
|
||||
ty::PredicateKind::AliasEq(t1, t2) => {
|
||||
ty::PredicateKind::AliasRelate(t1, t2, _) => {
|
||||
self.add_term(t1);
|
||||
self.add_term(t2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -543,7 +543,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| PredicateKind::Clause(Clause::TypeOutlives(_))
|
||||
| PredicateKind::Clause(Clause::Projection(_))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::ObjectSafe(_)
|
||||
| PredicateKind::ClosureKind(_, _, _)
|
||||
| PredicateKind::Subtype(_)
|
||||
|
|
@ -640,7 +640,23 @@ pub enum PredicateKind<'tcx> {
|
|||
/// This predicate requires two terms to be equal to eachother.
|
||||
///
|
||||
/// Only used for new solver
|
||||
AliasEq(Term<'tcx>, Term<'tcx>),
|
||||
AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, Debug)]
|
||||
pub enum AliasRelationDirection {
|
||||
Equate,
|
||||
Subtype,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AliasRelationDirection {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AliasRelationDirection::Equate => write!(f, " == "),
|
||||
AliasRelationDirection::Subtype => write!(f, " <: "),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
|
|
@ -976,11 +992,11 @@ impl<'tcx> Term<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This function returns `None` for `AliasKind::Opaque`.
|
||||
/// This function returns the inner `AliasTy` if this term is a projection.
|
||||
///
|
||||
/// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
|
||||
/// deal with constants.
|
||||
pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
|
||||
pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
|
||||
match self.unpack() {
|
||||
TermKind::Ty(ty) => match ty.kind() {
|
||||
ty::Alias(kind, alias_ty) => match kind {
|
||||
|
|
@ -1035,6 +1051,21 @@ impl<'tcx> TermKind<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ParamTerm {
|
||||
Ty(ParamTy),
|
||||
Const(ParamConst),
|
||||
}
|
||||
|
||||
impl ParamTerm {
|
||||
pub fn index(self) -> usize {
|
||||
match self {
|
||||
ParamTerm::Ty(ty) => ty.index as usize,
|
||||
ParamTerm::Const(ct) => ct.index as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This kind of predicate has no *direct* correspondent in the
|
||||
/// syntax, but it roughly corresponds to the syntactic forms:
|
||||
///
|
||||
|
|
@ -1206,7 +1237,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
|
|
@ -1227,7 +1258,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
|
||||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
|
|
@ -1249,7 +1280,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
PredicateKind::Clause(Clause::Trait(..))
|
||||
| PredicateKind::Clause(Clause::ConstArgHasType(..))
|
||||
| PredicateKind::Clause(Clause::Projection(..))
|
||||
| PredicateKind::AliasEq(..)
|
||||
| PredicateKind::AliasRelate(..)
|
||||
| PredicateKind::Subtype(..)
|
||||
| PredicateKind::Coerce(..)
|
||||
| PredicateKind::Clause(Clause::RegionOutlives(..))
|
||||
|
|
|
|||
|
|
@ -704,7 +704,11 @@ pub trait PrettyPrinter<'tcx>:
|
|||
ty::BoundTyKind::Anon(bv) => {
|
||||
self.pretty_print_bound_var(debruijn, ty::BoundVar::from_u32(bv))?
|
||||
}
|
||||
ty::BoundTyKind::Param(_, s) => p!(write("{}", s)),
|
||||
ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() {
|
||||
true if debruijn == ty::INNERMOST => p!(write("^{}", s)),
|
||||
true => p!(write("^{}_{}", debruijn.index(), s)),
|
||||
false => p!(write("{}", s)),
|
||||
},
|
||||
},
|
||||
ty::Adt(def, substs) => {
|
||||
p!(print_def_path(def.did(), substs));
|
||||
|
|
@ -2847,7 +2851,7 @@ define_print_and_forward_display! {
|
|||
p!("the type `", print(ty), "` is found in the environment")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => p!("ambiguous"),
|
||||
ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
|||
write!(f, "TypeWellFormedFromEnv({:?})", ty)
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
|
||||
ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => {
|
||||
write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -250,6 +252,7 @@ TrivialTypeTraversalAndLiftImpls! {
|
|||
crate::ty::AssocItem,
|
||||
crate::ty::AssocKind,
|
||||
crate::ty::AliasKind,
|
||||
crate::ty::AliasRelationDirection,
|
||||
crate::ty::Placeholder<crate::ty::BoundRegionKind>,
|
||||
crate::ty::Placeholder<crate::ty::BoundTyKind>,
|
||||
crate::ty::ClosureKind,
|
||||
|
|
|
|||
|
|
@ -153,12 +153,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self_ty: Ty<'tcx>,
|
||||
) -> impl Iterator<Item = DefId> + 'tcx {
|
||||
let impls = self.trait_impls_of(trait_def_id);
|
||||
if let Some(simp) = fast_reject::simplify_type(
|
||||
self,
|
||||
self_ty,
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
|
||||
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
|
||||
return impls.iter().copied();
|
||||
}
|
||||
|
|
@ -191,13 +186,17 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
|
||||
// `TreatParams::AsCandidateKey` while actually adding them.
|
||||
let treat_params = match treat_projections {
|
||||
TreatProjections::NextSolverLookup => TreatParams::NextSolverLookup,
|
||||
TreatProjections::ForLookup => TreatParams::ForLookup,
|
||||
};
|
||||
// This way, when searching for some impl for `T: Trait`, we do not look at any impls
|
||||
// whose outer level is not a parameter or projection. Especially for things like
|
||||
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
|
||||
// of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
|
||||
if let Some(simp) =
|
||||
fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup, treat_projections)
|
||||
{
|
||||
if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
|
||||
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
|
||||
for &impl_def_id in impls {
|
||||
if let result @ Some(_) = f(impl_def_id) {
|
||||
|
|
@ -258,12 +257,9 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Some(simplified_self_ty) = fast_reject::simplify_type(
|
||||
tcx,
|
||||
impl_self_ty,
|
||||
TreatParams::AsCandidateKey,
|
||||
TreatProjections::AsCandidateKey,
|
||||
) {
|
||||
if let Some(simplified_self_ty) =
|
||||
fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey)
|
||||
{
|
||||
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
|
||||
} else {
|
||||
impls.blanket_impls.push(impl_def_id);
|
||||
|
|
|
|||
|
|
@ -137,6 +137,10 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
|
||||
parse_by_kind!(self, expr_id, expr, "rvalue",
|
||||
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
|
||||
@call("mir_cast_transmute", args) => {
|
||||
let source = self.parse_operand(args[0])?;
|
||||
Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
|
||||
},
|
||||
@call("mir_checked", args) => {
|
||||
parse_by_kind!(self, args[0], _, "binary op",
|
||||
ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
|
||||
|
|
|
|||
|
|
@ -566,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Rvalue::Use(Operand::Move(val))
|
||||
}
|
||||
BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => {
|
||||
// Consider that the shift overflows if `rhs < 0` or `rhs >= bits`.
|
||||
// This can be encoded as a single operation as `(rhs & -bits) != 0`.
|
||||
let (size, _) = ty.int_size_and_signed(self.tcx);
|
||||
let bits = size.bits();
|
||||
debug_assert!(bits.is_power_of_two());
|
||||
let mask = !((bits - 1) as u128);
|
||||
|
||||
// For an unsigned RHS, the shift is in-range for `rhs < bits`.
|
||||
// For a signed RHS, `IntToInt` cast to the equivalent unsigned
|
||||
// type and do that same comparison. Because the type is the
|
||||
// same size, there's no negative shift amount that ends up
|
||||
// overlapping with valid ones, thus it catches negatives too.
|
||||
let (lhs_size, _) = ty.int_size_and_signed(self.tcx);
|
||||
let rhs_ty = rhs.ty(&self.local_decls, self.tcx);
|
||||
let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx);
|
||||
let mask = Operand::const_from_scalar(
|
||||
|
||||
let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() {
|
||||
ty::Uint(_) => (rhs.to_copy(), rhs_ty),
|
||||
ty::Int(int_width) => {
|
||||
let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned());
|
||||
let rhs_temp = self.temp(uint_ty, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
rhs_temp,
|
||||
Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty),
|
||||
);
|
||||
(Operand::Move(rhs_temp), uint_ty)
|
||||
}
|
||||
_ => unreachable!("only integers are shiftable"),
|
||||
};
|
||||
|
||||
// This can't overflow because the largest shiftable types are 128-bit,
|
||||
// which fits in `u8`, the smallest possible `unsigned_ty`.
|
||||
// (And `from_uint` will `bug!` if that's ever no longer true.)
|
||||
let lhs_bits = Operand::const_from_scalar(
|
||||
self.tcx,
|
||||
rhs_ty,
|
||||
Scalar::from_uint(rhs_size.truncate(mask), rhs_size),
|
||||
unsigned_ty,
|
||||
Scalar::from_uint(lhs_size.bits(), rhs_size),
|
||||
span,
|
||||
);
|
||||
|
||||
let outer_bits = self.temp(rhs_ty, span);
|
||||
let inbounds = self.temp(bool_ty, span);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
outer_bits,
|
||||
Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))),
|
||||
);
|
||||
|
||||
let overflows = self.temp(bool_ty, span);
|
||||
let zero = self.zero_literal(span, rhs_ty);
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
source_info,
|
||||
overflows,
|
||||
Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))),
|
||||
inbounds,
|
||||
Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))),
|
||||
);
|
||||
|
||||
let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy());
|
||||
block = self.assert(block, Operand::Move(overflows), false, overflow_err, span);
|
||||
block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span);
|
||||
Rvalue::BinaryOp(op, Box::new((lhs, rhs)))
|
||||
}
|
||||
BinOp::Div | BinOp::Rem if ty.is_integral() => {
|
||||
|
|
|
|||
|
|
@ -504,6 +504,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
|
||||
return None;
|
||||
}
|
||||
// Do not try creating references, nor any types with potentially-complex
|
||||
// invariants. This avoids an issue where checking validity would do a
|
||||
// bunch of work generating a nice message about the invariant violation,
|
||||
// only to not show it to anyone (since this isn't the lint).
|
||||
Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => {
|
||||
trace!("skipping Transmute of {:?} to {:?}", op, dst_ty);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
// There's no other checking to do at this time.
|
||||
Rvalue::Aggregate(..)
|
||||
|
|
|
|||
|
|
@ -221,6 +221,32 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
}
|
||||
sym::transmute => {
|
||||
let dst_ty = destination.ty(local_decls, tcx).ty;
|
||||
let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
|
||||
span_bug!(
|
||||
terminator.source_info.span,
|
||||
"Wrong number of arguments for transmute intrinsic",
|
||||
);
|
||||
};
|
||||
|
||||
// Always emit the cast, even if we transmute to an uninhabited type,
|
||||
// because that lets CTFE and codegen generate better error messages
|
||||
// when such a transmute actually ends up reachable.
|
||||
block.statements.push(Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
*destination,
|
||||
Rvalue::Cast(CastKind::Transmute, arg, dst_ty),
|
||||
))),
|
||||
});
|
||||
|
||||
if let Some(target) = *target {
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
} else {
|
||||
terminator.kind = TerminatorKind::Unreachable;
|
||||
}
|
||||
}
|
||||
_ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
|
||||
validate_simd_shuffle(tcx, args, terminator.source_info.span);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use crate::errors::{LoadPluginError, MalformedPluginAttribute};
|
||||
use crate::Registry;
|
||||
use libloading::Library;
|
||||
use rustc_ast::Crate;
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_session::cstore::MetadataLoader;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -20,11 +20,11 @@ type PluginRegistrarFn = fn(&mut Registry<'_>);
|
|||
pub fn load_plugins(
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
krate: &Crate,
|
||||
attrs: &[Attribute],
|
||||
) -> Vec<PluginRegistrarFn> {
|
||||
let mut plugins = Vec::new();
|
||||
|
||||
for attr in &krate.attrs {
|
||||
for attr in attrs {
|
||||
if !attr.has_name(sym::plugin) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ where
|
|||
| ty::PredicateKind::ConstEquate(_, _)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(_)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::AliasEq(_, _) => bug!("unexpected predicate: {:?}", predicate),
|
||||
| ty::PredicateKind::AliasRelate(..) => bug!("unexpected predicate: {:?}", predicate),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
|||
use rustc_metadata::creader::LoadedMacro;
|
||||
use rustc_middle::metadata::ModChild;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_session::cstore::CrateStore;
|
||||
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -115,34 +114,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if !def_id.is_local() {
|
||||
let def_kind = self.cstore().def_kind(def_id);
|
||||
match def_kind {
|
||||
DefKind::Mod | DefKind::Enum | DefKind::Trait => {
|
||||
let def_key = self.cstore().def_key(def_id);
|
||||
let parent = def_key.parent.map(|index| {
|
||||
self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
|
||||
});
|
||||
let name = if let Some(cnum) = def_id.as_crate_root() {
|
||||
self.cstore().crate_name(cnum)
|
||||
} else {
|
||||
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
|
||||
};
|
||||
|
||||
let expn_id = self.cstore().module_expansion_untracked(def_id, &self.tcx.sess);
|
||||
Some(self.new_module(
|
||||
parent,
|
||||
ModuleKind::Def(def_kind, def_id, name),
|
||||
expn_id,
|
||||
self.def_span(def_id),
|
||||
// FIXME: Account for `#[no_implicit_prelude]` attributes.
|
||||
parent.map_or(false, |module| module.no_implicit_prelude),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
// Query `def_kind` is not used because query system overhead is too expensive here.
|
||||
let def_kind = self.cstore().def_kind_untracked(def_id);
|
||||
if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind {
|
||||
let parent = self
|
||||
.tcx
|
||||
.opt_parent(def_id)
|
||||
.map(|parent_id| self.get_nearest_non_block_module(parent_id));
|
||||
// Query `expn_that_defined` is not used because
|
||||
// hashing spans in its result is expensive.
|
||||
let expn_id = self.cstore().expn_that_defined_untracked(def_id, &self.tcx.sess);
|
||||
return Some(self.new_module(
|
||||
parent,
|
||||
ModuleKind::Def(def_kind, def_id, self.tcx.item_name(def_id)),
|
||||
expn_id,
|
||||
self.def_span(def_id),
|
||||
// FIXME: Account for `#[no_implicit_prelude]` attributes.
|
||||
parent.map_or(false, |module| module.no_implicit_prelude),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
|
||||
|
|
@ -204,6 +197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) {
|
||||
// Query `module_children` is not used because hashing spans in its result is expensive.
|
||||
let children =
|
||||
Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess));
|
||||
for child in children {
|
||||
|
|
|
|||
|
|
@ -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 let Some(node_id) = import.id() {
|
||||
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
|
||||
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,21 +124,44 @@ 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() {
|
||||
// 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 {
|
||||
let binding_id = ImportId::new_unchecked(binding);
|
||||
self.update_import(binding_id, parent_id);
|
||||
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
|
||||
{
|
||||
let binding_id = ImportId::new_unchecked(binding);
|
||||
self.update_import(binding_id, parent_id);
|
||||
|
||||
parent_id = ParentId::Import(binding_id);
|
||||
binding = nested_binding;
|
||||
}
|
||||
parent_id = ParentId::Import(binding_id);
|
||||
binding = nested_binding;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -1168,7 +1168,7 @@ impl<'tcx> Resolver<'_, 'tcx> {
|
|||
if let Some(def_id) = def_id.as_local() {
|
||||
self.item_generics_num_lifetimes[&def_id]
|
||||
} else {
|
||||
self.cstore().item_generics_num_lifetimes(def_id, self.tcx.sess)
|
||||
self.tcx.generics_of(def_id).own_counts().lifetimes
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1180,7 +1180,8 @@ impl<'tcx> Resolver<'_, 'tcx> {
|
|||
impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
pub fn new(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
krate: &Crate,
|
||||
attrs: &[ast::Attribute],
|
||||
crate_span: Span,
|
||||
arenas: &'a ResolverArenas<'a>,
|
||||
) -> Resolver<'a, 'tcx> {
|
||||
let root_def_id = CRATE_DEF_ID.to_def_id();
|
||||
|
|
@ -1189,8 +1190,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
None,
|
||||
ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty),
|
||||
ExpnId::root(),
|
||||
krate.spans.inner_span,
|
||||
attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
|
||||
crate_span,
|
||||
attr::contains_name(attrs, sym::no_implicit_prelude),
|
||||
&mut module_map,
|
||||
);
|
||||
let empty_module = arenas.new_module(
|
||||
|
|
@ -1222,9 +1223,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
.map(|(name, _)| (Ident::from_str(name), Default::default()))
|
||||
.collect();
|
||||
|
||||
if !attr::contains_name(&krate.attrs, sym::no_core) {
|
||||
if !attr::contains_name(attrs, sym::no_core) {
|
||||
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
|
||||
if !attr::contains_name(&krate.attrs, sym::no_std) {
|
||||
if !attr::contains_name(attrs, sym::no_std) {
|
||||
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
|
||||
}
|
||||
}
|
||||
|
|
@ -1474,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());
|
||||
|
|
@ -1871,7 +1875,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
fn def_span(&self, def_id: DefId) -> Span {
|
||||
match def_id.as_local() {
|
||||
Some(def_id) => self.tcx.source_span(def_id),
|
||||
None => self.cstore().get_span_untracked(def_id, self.tcx.sess),
|
||||
// Query `def_span` is not used because hashing its result span is expensive.
|
||||
None => self.cstore().def_span_untracked(def_id, self.tcx.sess),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1906,10 +1911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
return v.clone();
|
||||
}
|
||||
|
||||
let attr = self
|
||||
.cstore()
|
||||
.item_attrs_untracked(def_id, self.tcx.sess)
|
||||
.find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
|
||||
let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?;
|
||||
let mut ret = Vec::new();
|
||||
for meta in attr.meta_item_list()? {
|
||||
match meta.lit()?.kind {
|
||||
|
|
|
|||
|
|
@ -112,8 +112,8 @@ fn fast_print_path(path: &ast::Path) -> Symbol {
|
|||
|
||||
pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
|
||||
let mut registered_tools = RegisteredTools::default();
|
||||
let krate = tcx.crate_for_resolver(()).borrow();
|
||||
for attr in attr::filter_by_name(&krate.attrs, sym::register_tool) {
|
||||
let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow();
|
||||
for attr in attr::filter_by_name(pre_configured_attrs, sym::register_tool) {
|
||||
for nested_meta in attr.meta_item_list().unwrap_or_default() {
|
||||
match nested_meta.ident() {
|
||||
Some(ident) => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -99,20 +99,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: Vec<ty::GenericArg<'tcx>>,
|
||||
response: CanonicalResponse<'tcx>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
) -> Result<(Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
|
||||
let substitution = self.compute_query_response_substitution(&original_values, &response);
|
||||
|
||||
let Response { var_values, external_constraints, certainty } =
|
||||
response.substitute(self.tcx(), &substitution);
|
||||
|
||||
self.unify_query_var_values(param_env, &original_values, var_values)?;
|
||||
let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
|
||||
|
||||
// FIXME: implement external constraints.
|
||||
let ExternalConstraintsData { region_constraints, opaque_types: _ } =
|
||||
external_constraints.deref();
|
||||
self.register_region_constraints(region_constraints);
|
||||
|
||||
Ok(certainty)
|
||||
Ok((certainty, nested_goals))
|
||||
}
|
||||
|
||||
/// This returns the substitutions to instantiate the bound variables of
|
||||
|
|
@ -205,21 +205,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: &[ty::GenericArg<'tcx>],
|
||||
var_values: CanonicalVarValues<'tcx>,
|
||||
) -> Result<(), NoSolution> {
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
assert_eq!(original_values.len(), var_values.len());
|
||||
|
||||
let mut nested_goals = vec![];
|
||||
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
|
||||
// This can fail due to the occurs check, see
|
||||
// `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example
|
||||
// where that can happen.
|
||||
//
|
||||
// FIXME: To deal with #105787 I also expect us to emit nested obligations here at
|
||||
// some point. We can figure out how to deal with this once we actually have
|
||||
// an ICE.
|
||||
let nested_goals = self.eq_and_get_goals(param_env, orig, response)?;
|
||||
assert!(nested_goals.is_empty(), "{nested_goals:?}");
|
||||
nested_goals.extend(self.eq_and_get_goals(param_env, orig, response)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(nested_goals)
|
||||
}
|
||||
|
||||
fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ pub trait InferCtxtEvalExt<'tcx> {
|
|||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> Result<(bool, Certainty), NoSolution>;
|
||||
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
||||
|
|
@ -78,9 +78,8 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
|||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> Result<(bool, Certainty), NoSolution> {
|
||||
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
|
||||
let mode = if self.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
||||
|
||||
let mut search_graph = search_graph::SearchGraph::new(self.tcx, mode);
|
||||
|
||||
let mut ecx = EvalCtxt {
|
||||
|
|
@ -152,13 +151,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
&mut self,
|
||||
is_normalizes_to_hack: IsNormalizesToHack,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> Result<(bool, Certainty), NoSolution> {
|
||||
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
|
||||
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||
let canonical_response =
|
||||
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
|
||||
|
||||
let has_changed = !canonical_response.value.var_values.is_identity();
|
||||
let certainty = self.instantiate_and_apply_query_response(
|
||||
let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
|
||||
goal.param_env,
|
||||
orig_values,
|
||||
canonical_response,
|
||||
|
|
@ -186,7 +185,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
assert_eq!(certainty, canonical_response.value.certainty);
|
||||
}
|
||||
|
||||
Ok((has_changed, certainty))
|
||||
Ok((has_changed, certainty, nested_goals))
|
||||
}
|
||||
|
||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||
|
|
@ -236,9 +235,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::AliasEq(lhs, rhs) => {
|
||||
self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
|
||||
.compute_alias_relate_goal(Goal {
|
||||
param_env,
|
||||
predicate: (lhs, rhs, direction),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
|
||||
|
|
@ -261,13 +262,14 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
let mut has_changed = Err(Certainty::Yes);
|
||||
|
||||
if let Some(goal) = goals.normalizes_to_hack_goal.take() {
|
||||
let (_, certainty) = match this.evaluate_goal(
|
||||
let (_, certainty, nested_goals) = match this.evaluate_goal(
|
||||
IsNormalizesToHack::Yes,
|
||||
goal.with(this.tcx(), ty::Binder::dummy(goal.predicate)),
|
||||
) {
|
||||
Ok(r) => r,
|
||||
Err(NoSolution) => return Some(Err(NoSolution)),
|
||||
};
|
||||
new_goals.goals.extend(nested_goals);
|
||||
|
||||
if goal.predicate.projection_ty
|
||||
!= this.resolve_vars_if_possible(goal.predicate.projection_ty)
|
||||
|
|
@ -306,11 +308,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
for nested_goal in goals.goals.drain(..) {
|
||||
let (changed, certainty) =
|
||||
let (changed, certainty, nested_goals) =
|
||||
match this.evaluate_goal(IsNormalizesToHack::No, nested_goal) {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => return Some(Err(NoSolution)),
|
||||
};
|
||||
new_goals.goals.extend(nested_goals);
|
||||
|
||||
if changed {
|
||||
has_changed = Ok(());
|
||||
|
|
@ -470,6 +473,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, param_env), ret)]
|
||||
pub(super) fn sub<T: ToTrace<'tcx>>(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
sub: T,
|
||||
sup: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.sub(DefineOpaqueTypes::No, sub, sup)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
debug!(?e, "failed to subtype");
|
||||
NoSolution
|
||||
})
|
||||
}
|
||||
|
||||
/// Equates two values returning the nested goals without adding them
|
||||
/// to the nested goals of the `EvalCtxt`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::mem;
|
||||
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_infer::traits::{
|
||||
query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
|
||||
PredicateObligation, SelectionError, TraitEngine,
|
||||
|
|
@ -61,7 +62,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
let mut has_changed = false;
|
||||
for obligation in mem::take(&mut self.obligations) {
|
||||
let goal = obligation.clone().into();
|
||||
let (changed, certainty) = match infcx.evaluate_root_goal(goal) {
|
||||
let (changed, certainty, nested_goals) = match infcx.evaluate_root_goal(goal) {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => {
|
||||
errors.push(FulfillmentError {
|
||||
|
|
@ -73,7 +74,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::AliasEq(_, _) => {
|
||||
ty::PredicateKind::AliasRelate(_, _, _) => {
|
||||
FulfillmentErrorCode::CodeProjectionError(
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
|
|
@ -125,7 +126,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Push any nested goals that we get from unifying our canonical response
|
||||
// with our obligation onto the fulfillment context.
|
||||
self.obligations.extend(nested_goals.into_iter().map(|goal| {
|
||||
Obligation::new(
|
||||
infcx.tcx,
|
||||
obligation.cause.clone(),
|
||||
goal.param_env,
|
||||
goal.predicate,
|
||||
)
|
||||
}));
|
||||
has_changed |= changed;
|
||||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalGoal, CanonicalResponse, Certainty, ExternalConstraints, ExternalConstraintsData,
|
||||
|
|
@ -110,11 +109,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
// That won't actually reflect in the query response, so it seems moot.
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
} else {
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), goal.param_env)
|
||||
.sub(DefineOpaqueTypes::No, goal.predicate.a, goal.predicate.b)?;
|
||||
self.add_goals(obligations.into_iter().map(|pred| pred.into()));
|
||||
self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
@ -165,55 +160,94 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn compute_alias_eq_goal(
|
||||
fn compute_alias_relate_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
// We may need to invert the alias relation direction if dealing an alias on the RHS.
|
||||
enum Invert {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
let evaluate_normalizes_to =
|
||||
|ecx: &mut EvalCtxt<'_, 'tcx>, alias, other, direction, invert| {
|
||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||
let result = ecx.probe(|ecx| {
|
||||
let other = match direction {
|
||||
// This is purely an optimization.
|
||||
ty::AliasRelationDirection::Equate => other,
|
||||
|
||||
let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
|
||||
debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
|
||||
let r = ecx.probe(|ecx| {
|
||||
ecx.add_goal(goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: alias,
|
||||
term: other,
|
||||
}),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
debug!("evaluate_normalizes_to(..) -> {:?}", r);
|
||||
r
|
||||
};
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
let fresh = ecx.next_term_infer_of_kind(other);
|
||||
let (sub, sup) = match invert {
|
||||
Invert::No => (fresh, other),
|
||||
Invert::Yes => (other, fresh),
|
||||
};
|
||||
ecx.sub(goal.param_env, sub, sup)?;
|
||||
fresh
|
||||
}
|
||||
};
|
||||
ecx.add_goal(goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(ty::ProjectionPredicate {
|
||||
projection_ty: alias,
|
||||
term: other,
|
||||
}),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
});
|
||||
debug!("evaluate_normalizes_to({alias}, {other}, {direction:?}) -> {result:?}");
|
||||
result
|
||||
};
|
||||
|
||||
if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
|
||||
let (lhs, rhs, direction) = goal.predicate;
|
||||
|
||||
if lhs.is_infer() || rhs.is_infer() {
|
||||
bug!(
|
||||
"`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
|
||||
"`AliasRelate` goal with an infer var on lhs or rhs which should have been instantiated"
|
||||
);
|
||||
}
|
||||
|
||||
match (
|
||||
goal.predicate.0.to_alias_term_no_opaque(tcx),
|
||||
goal.predicate.1.to_alias_term_no_opaque(tcx),
|
||||
) {
|
||||
(None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"),
|
||||
(Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1),
|
||||
(None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0),
|
||||
match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
|
||||
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
|
||||
|
||||
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
|
||||
(Some(alias_lhs), None) => {
|
||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No)
|
||||
}
|
||||
|
||||
// LHS is not a projection, only way this is true is if RHS normalizes-to LHS
|
||||
(None, Some(alias_rhs)) => {
|
||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes)
|
||||
}
|
||||
|
||||
(Some(alias_lhs), Some(alias_rhs)) => {
|
||||
debug!("compute_alias_eq_goal: both sides are aliases");
|
||||
debug!("compute_alias_relate_goal: both sides are aliases");
|
||||
|
||||
let mut candidates = Vec::with_capacity(3);
|
||||
let candidates = vec![
|
||||
// LHS normalizes-to RHS
|
||||
evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No),
|
||||
// RHS normalizes-to RHS
|
||||
evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes),
|
||||
// Relate via substs
|
||||
self.probe(|ecx| {
|
||||
debug!(
|
||||
"compute_alias_relate_goal: alias defids are equal, equating substs"
|
||||
);
|
||||
|
||||
// Evaluate all 3 potential candidates for the alias' being equal
|
||||
candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
|
||||
candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
|
||||
candidates.push(self.probe(|ecx| {
|
||||
debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
|
||||
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}));
|
||||
match direction {
|
||||
ty::AliasRelationDirection::Equate => {
|
||||
ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
}
|
||||
ty::AliasRelationDirection::Subtype => {
|
||||
ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
|
||||
}
|
||||
}
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}),
|
||||
];
|
||||
debug!(?candidates);
|
||||
|
||||
self.try_merge_responses(candidates.into_iter())
|
||||
|
|
|
|||
|
|
@ -832,7 +832,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
// the `ParamEnv`.
|
||||
ty::PredicateKind::WellFormed(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasEq(..)
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
|
||||
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
|
||||
// FIXME(deferred_projection_equality): We really should get rid of this relation.
|
||||
ty::AliasRelationDirection::Equate
|
||||
}
|
||||
|
||||
fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
|
||||
// FIXME(deferred_projection_equality)
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue