diff options
Diffstat (limited to 'compiler')
149 files changed, 2091 insertions, 2001 deletions
diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index ab1413d6080..12cbb3b2a15 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -18,12 +18,6 @@ pub enum EntryPointType { /// fn main() {} /// ``` RustcMainAttr, - /// This is a function with the `#[start]` attribute. - /// ```ignore (clashes with test entrypoint) - /// #[start] - /// fn main() {} - /// ``` - Start, /// This function is **not** an entrypoint but simply named `main` (not at the root). /// This is only used for diagnostics. /// ``` @@ -40,9 +34,7 @@ pub fn entry_point_type( at_root: bool, name: Option<Symbol>, ) -> EntryPointType { - if attr::contains_name(attrs, sym::start) { - EntryPointType::Start - } else if attr::contains_name(attrs, sym::rustc_main) { + if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if let Some(name) = name && name == sym::main diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a76ca6772e5..f31e2c65c79 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2159,7 +2159,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let path = hir::ExprKind::Path(hir::QPath::TypeRelative( self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))), self.arena.alloc(hir::PathSegment::new( - Ident::new(name, span), + Ident::new(name, self.lower_span(span)), self.next_id(), Res::Err, )), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 29d4fb9ef25..9cfdbc47495 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -78,24 +78,31 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. - if cfg!(debug_assertions) && hir_id.owner != self.owner { - span_bug!( - span, - "inconsistent HirId at `{:?}` for `{:?}`: \ + if cfg!(debug_assertions) { + if hir_id.owner != self.owner { + span_bug!( + span, + "inconsistent HirId at `{:?}` for `{node:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.tcx.sess.source_map().span_to_diagnostic_string(span), - node, - self.tcx - .definitions_untracked() - .def_path(self.owner.def_id) - .to_string_no_crate_verbose(), - self.owner, - self.tcx - .definitions_untracked() - .def_path(hir_id.owner.def_id) - .to_string_no_crate_verbose(), - hir_id.owner, - ) + self.tcx.sess.source_map().span_to_diagnostic_string(span), + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), + self.owner, + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), + hir_id.owner, + ) + } + if self.tcx.sess.opts.incremental.is_some() + && span.parent().is_none() + && !span.is_dummy() + { + span_bug!(span, "span without a parent: {:#?}, {node:?}", span.data()) + } } self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 61d7da429f8..74870d74150 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1092,6 +1092,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // this as a special case. return self.lower_fn_body(decl, |this| { if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { + let span = this.lower_span(span); let empty_block = hir::Block { hir_id: this.next_id(), stmts: &[], diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index abd314ae74c..3c78ed0497d 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -375,24 +375,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { expr: &Expr, allow_paths: bool, ) -> &'hir hir::PatExpr<'hir> { + let span = self.lower_span(expr.span); let err = |guar| hir::PatExprKind::Lit { - lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))), + lit: self.arena.alloc(respan(span, LitKind::Err(guar))), negated: false, }; let kind = match &expr.kind { ExprKind::Lit(lit) => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } } ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { - lit: self.arena.alloc(respan( - self.lower_span(expr.span), - LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), - )), + lit: self + .arena + .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), negated: false, }, ExprKind::Err(guar) => err(*guar), - ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"), + ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"), ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath( expr.id, qself, @@ -403,21 +403,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, )), ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true } } _ => { let pattern_from_macro = expr.is_approximately_pattern(); let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { - span: expr.span, + span, pattern_from_macro_note: pattern_from_macro, }); err(guar) } }; - self.arena.alloc(hir::PatExpr { - hir_id: self.lower_node_id(expr.id), - span: expr.span, - kind, - }) + self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d6f0af9ad38..80b99f94485 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -230,18 +230,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs, sym::start) { - gate!( - &self, - start, - i.span, - "`#[start]` functions are experimental and their signature may change \ - over time" - ); - } - } - ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 497d672ccb2..d020244bf55 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -39,7 +39,9 @@ use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::error_reporting::traits::call_kind::CallKind; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::{ + Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids, +}; use tracing::{debug, instrument}; use super::explain_borrow::{BorrowExplanation, LaterUseKind}; @@ -658,8 +660,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { clause.as_trait_clause().is_some_and(|tc| { tc.self_ty().skip_binder().is_param(param.index) && tc.polarity() == ty::PredicatePolarity::Positive - && tcx - .supertrait_def_ids(tc.def_id()) + && supertrait_def_ids(tcx, tc.def_id()) .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order()) .any(|item| item.fn_has_self_parameter) }) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 3903c45fda5..bffd9f38334 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CustomTypeOp::new( |ocx| { let structurally_normalize = |ty| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), @@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring, CustomTypeOp::new( |ocx| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6071d36f8eb..0918403b855 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -16,6 +16,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] +#![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 123b96f6bca..d163da3ddea 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{ use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::{Pos, Span, Symbol}; @@ -209,9 +209,10 @@ pub(crate) fn expand_include_str( let interned_src = Symbol::intern(src); MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } - Err(_) => { - let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); - DummyResult::any(sp, guar) + Err(utf8err) => { + let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file")); + utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]); + DummyResult::any(sp, err.emit()) } }, Err(dummy) => dummy, @@ -273,7 +274,7 @@ fn load_binary_file( .and_then(|path| path.into_os_string().into_string().ok()); if let Some(new_path) = new_path { - err.span_suggestion( + err.span_suggestion_verbose( path_span, "there is a file with the same name in a different directory", format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 46446598943..31b068bd33d 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -204,11 +204,11 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { ast::mut_visit::walk_item(self, item); self.depth -= 1; - // Remove any #[rustc_main] or #[start] from the AST so it doesn't + // Remove any #[rustc_main] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. match entry_point_type(&item, self.depth == 0) { - EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { + EntryPointType::MainNamed | EntryPointType::RustcMainAttr => { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, @@ -217,8 +217,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { sym::dead_code, self.def_site, ); - item.attrs - .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)); + item.attrs.retain(|attr| !attr.has_name(sym::rustc_main)); item.attrs.push(allow_dead_code); } EntryPointType::None | EntryPointType::OtherMain => {} diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index e4c3dd708fd..9c6aad3490d 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-01-10" +channel = "nightly-2025-01-20" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index e569da90cf7..41aa011e805 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -176,12 +176,11 @@ diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-supp index 9607ff02f96..b7d97caf9a2 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs -@@ -34,8 +34,6 @@ pub fn bare() -> Self { +@@ -34,7 +34,6 @@ pub fn bare() -> Self { #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); -- let target_rpath_dir = env_var_os("TARGET_RPATH_DIR"); -- cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); +- cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR")); Self { cmd } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index fe578e44770..7d5592daac1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -333,9 +333,17 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> { let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); + + // Disable function sections by default on MSVC as it causes significant slowdowns with link.exe. + // Maybe link.exe has exponential behavior when there are many sections with the same name? Also + // explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such + // isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has + // been on MinGW. + let default_function_sections = sess.target.function_sections && !sess.target.is_like_windows; builder.per_function_section( - sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections), + sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), ); + UnwindModule::new(ObjectModule::new(builder), true) } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 2e5813556aa..26f14532b45 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1,4 +1,5 @@ //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, +//! functions marked with the `#[rustc_intrinsic]` attribute //! and LLVM intrinsics that have symbol names starting with `llvm.`. macro_rules! intrinsic_args { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index e6bf0d5b47e..f6843496895 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,7 +1,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; use rustc_middle::ty::{AssocKind, GenericArg}; -use rustc_session::config::{EntryFnType, sigpipe}; +use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; use crate::prelude::*; @@ -14,10 +14,9 @@ pub(crate) fn maybe_create_entry_wrapper( is_jit: bool, is_primary_cgu: bool, ) { - let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) { + let (main_def_id, sigpipe) = match tcx.entry_fn(()) { Some((def_id, entry_ty)) => (def_id, match entry_ty { - EntryFnType::Main { sigpipe } => (true, sigpipe), - EntryFnType::Start => (false, sigpipe::DEFAULT), + EntryFnType::Main { sigpipe } => sigpipe, }), None => return, }; @@ -31,14 +30,13 @@ pub(crate) fn maybe_create_entry_wrapper( return; } - create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe); + create_entry_fn(tcx, module, main_def_id, is_jit, sigpipe); fn create_entry_fn( tcx: TyCtxt<'_>, m: &mut dyn Module, rust_main_def_id: DefId, ignore_lang_start_wrapper: bool, - is_main_fn: bool, sigpipe: u8, ) { let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output(); @@ -94,8 +92,8 @@ pub(crate) fn maybe_create_entry_wrapper( let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); - let result = if is_main_fn && ignore_lang_start_wrapper { - // regular main fn, but ignoring #[lang = "start"] as we are running in the jit + let result = if ignore_lang_start_wrapper { + // ignoring #[lang = "start"] as we are running in the jit // FIXME set program arguments somehow let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); @@ -133,7 +131,8 @@ pub(crate) fn maybe_create_entry_wrapper( types::I64 => bcx.ins().sextend(types::I64, res), _ => unimplemented!("16bit systems are not yet supported"), } - } else if is_main_fn { + } else { + // Regular main fn invoked via start lang item. let start_def_id = tcx.require_lang_item(LangItem::Start, None); let start_instance = Instance::expect_resolve( tcx, @@ -150,10 +149,6 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]); bcx.inst_results(call_inst)[0] - } else { - // using user-defined start fn - let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]); - bcx.inst_results(call_inst)[0] }; bcx.ins().return_(&[result]); diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 7cc7336612c..0e790a4befc 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -426,19 +426,6 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { run_command_with_env(&command, None, Some(env))?; maybe_run_command_in_vm(&[&cargo_target_dir.join("track-caller-attribute")], env, args)?; - // FIXME: create a function "display_if_not_quiet" or something along the line. - println!("[AOT] mod_bench"); - let mut command = args.config_info.rustc_command_vec(); - command.extend_from_slice(&[ - &"example/mod_bench.rs", - &"--crate-type", - &"bin", - &"--target", - &args.config_info.target_triple, - ]); - run_command_with_env(&command, None, Some(env))?; - // FIXME: the compiled binary is not run. - Ok(()) } @@ -696,19 +683,6 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -// echo "[BENCH COMPILE] mod_bench" -// -// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" -// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort" -// -// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow -// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" -// echo "[BENCH RUN] mod_bench" -// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_* - fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { if !args.is_using_gcc_master_branch() { println!("Not using GCC master branch. Skipping `extended_rand_tests`."); diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index 6ed8b9157f2..9a0b46d5b22 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -1,5 +1,6 @@ -#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] +#![feature(core_intrinsics, alloc_error_handler, lang_items)] #![no_std] +#![no_main] #![allow(internal_features)] extern crate alloc; @@ -37,8 +38,8 @@ unsafe extern "C" fn _Unwind_Resume() { core::intrinsics::unreachable(); } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let world: Box<&str> = Box::new("Hello World!\0"); unsafe { puts(*world as *const str as *const u8); diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 1d51e0a1856..4cbe66c5e4c 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -1,7 +1,7 @@ // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs #![feature( - no_core, unboxed_closures, start, lang_items, never_type, linkage, + no_core, unboxed_closures, lang_items, never_type, linkage, extern_types, thread_local )] #![no_core] diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs deleted file mode 100644 index e8a9cade747..00000000000 --- a/compiler/rustc_codegen_gcc/example/mod_bench.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(start, core_intrinsics, lang_items)] -#![no_std] -#![allow(internal_features)] - -#[link(name = "c")] -extern "C" {} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[lang="eh_personality"] -fn eh_personality(){} - -// Required for rustc_codegen_llvm -#[no_mangle] -unsafe extern "C" fn _Unwind_Resume() { - core::intrinsics::unreachable(); -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - for i in 2..100_000_000 { - black_box((i + 1) % i); - } - - 0 -} - -#[inline(never)] -fn black_box(i: u32) { - if i != 1 { - core::intrinsics::abort(); - } -} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index f43743fc2a4..bd5d6ba387c 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -64,6 +64,11 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } + fn is_undef(&self, _val: RValue<'gcc>) -> bool { + // FIXME: actually check for undef + false + } + fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); if typ.is_struct().is_some() { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index c81c53359fd..30732c74eb3 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -513,7 +513,6 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} - // instead of #[start] None } } diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index 696197d7377..385e41a6881 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -3,11 +3,12 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -49,7 +50,7 @@ fn test_fail() -> ! { unsafe { intrinsics::abort() }; } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { test_fail(); } diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index 714cd6c0f38..6c66a930e07 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -3,11 +3,12 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -50,8 +51,8 @@ fn fail() -> i32 { 0 } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { fail(); 0 } diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index c3c08c29c6d..e18a4ced6bc 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -7,10 +7,11 @@ // 5 // 10 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -28,8 +29,8 @@ fn make_array() -> [u8; 3] { [42, 10, 5] } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let array = [42, 7, 5]; let array2 = make_array(); unsafe { diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index 2a47f0c2966..4d414c577a6 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -6,10 +6,11 @@ // 10 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -142,8 +143,8 @@ fn inc(num: isize) -> isize { } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { argc = inc(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index 46c47bc54ed..c7a236f74f9 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -8,10 +8,11 @@ // Int argument: 2 // Both args: 11 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -22,8 +23,8 @@ mod libc { } } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let string = "Arg: %d\n\0"; let mut closure = || { unsafe { diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index 039ef94eaa7..b02359702ed 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -5,10 +5,11 @@ // stdout: true // 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -19,8 +20,8 @@ mod libc { } } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { if argc == 1 { libc::printf(b"true\n\0" as *const u8 as *const i8); diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs index e66a859ad69..042e44080c5 100644 --- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs +++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs @@ -3,11 +3,12 @@ // Run-time: // status: 0 -#![feature(auto_traits, lang_items, no_core, start)] +#![feature(auto_traits, lang_items, no_core)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { 0 } diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs index bf1cbeef302..9a7c91c0adb 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs @@ -3,11 +3,12 @@ // Run-time: // status: 2 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] mod libc { #[link(name = "c")] @@ -41,8 +42,8 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::exit(2); } diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs index be7a233efda..c50d2b0d710 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs @@ -3,11 +3,12 @@ // Run-time: // status: 1 -#![feature(auto_traits, lang_items, no_core, start)] +#![feature(auto_traits, lang_items, no_core)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { 1 } diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index ed1bf72bb27..98b351e5044 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -26,8 +27,8 @@ fn call_func(func: fn(i16) -> i8, param: i16) -> i8 { func(param) } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { let result = call_func(i16_as_i8, argc as i16) as isize; libc::printf(b"%ld\n\0" as *const u8 as *const i8, result); diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index 3ae79338216..9be64f991ee 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -8,10 +8,11 @@ // 11 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -148,8 +149,8 @@ fn update_num(num: &mut isize) { *num = *num + 5; } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let mut test = test(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index 0e44fc580b8..c92d3cc0b8f 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -6,10 +6,11 @@ // 10 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -231,8 +232,8 @@ pub fn panic_const_mul_overflow() -> ! { * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc); libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc); diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index 2b8812ad51c..0ba49e7187f 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -24,8 +25,8 @@ fn make_array() -> [u8; 3] { [42, 10, 5] } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { let ptr = ONE as *mut usize; let value = ptr as usize; diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs index f2a5a2e4384..3cc1e274001 100644 --- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs @@ -6,11 +6,12 @@ // 10 // 42 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] #[lang = "copy"] pub unsafe trait Copy {} @@ -61,8 +62,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3 ) } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); unsafe { libc::printf(b"%d\n\0" as *const u8 as *const i8, c); diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index fba93fc1554..825fcb8a081 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 5 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -26,8 +27,8 @@ fn index_slice(s: &[u32]) -> u32 { } } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let array = [42, 7, 5]; unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array)); diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index a17ea2a4893..80c8782c4b1 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -9,11 +9,12 @@ // 12 // 1 -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -98,8 +99,8 @@ static mut WITH_REF: WithRef = WithRef { refe: unsafe { &TEST }, }; -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT); libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs index d6455667400..59b8f358863 100644 --- a/compiler/rustc_codegen_gcc/tests/run/structs.rs +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -5,11 +5,12 @@ // stdout: 1 // 2 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -55,8 +56,8 @@ fn one() -> isize { 1 } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let test = Test { field: one(), }; diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs index 8a7d85ae867..ed60a56a68c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs @@ -4,11 +4,12 @@ // status: 0 // stdout: 3 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -42,8 +43,8 @@ mod libc { * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let test: (isize, isize, isize) = (3, 1, 4); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0); diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index c44d1a5e5c2..94f21ac5f57 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -9,6 +9,8 @@ test = false [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +# To avoid duplicate dependencies, this should match the version of gimli used +# by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.30" itertools = "0.12" libc = "0.2" diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 509b24dd703..4706744f353 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -769,12 +769,9 @@ pub(crate) unsafe fn codegen( } } - // Two things to note: - // - If object files are just LLVM bitcode we write bitcode, copy it to - // the .o file, and delete the bitcode if it wasn't otherwise - // requested. - // - If we don't have the integrated assembler then we need to emit - // asm from LLVM and use `gcc` to create the object file. + // Note that if object files are just LLVM bitcode we write bitcode, + // copy it to the .o file, and delete the bitcode if it wasn't + // otherwise requested. let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let bc_summary_out = diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index adfe8aeb5c5..b4e9b9f44f4 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -126,6 +126,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetUndef(t) } } + fn is_undef(&self, v: &'ll Value) -> bool { + unsafe { llvm::LLVMIsUndef(v) == True } + } + fn const_poison(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMGetPoison(t) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 65345751842..91283a5944e 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -751,7 +751,6 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} - // instead of #[start] None } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ec6c84f6f25..009d15a932f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -741,8 +741,11 @@ pub mod debuginfo { pub type DIEnumerator = DIDescriptor; pub type DITemplateTypeParameter = DIDescriptor; - // These values **must** match with LLVMRustDIFlags!! bitflags! { + /// Must match the layout of `LLVMDIFlags` in the LLVM-C API. + /// + /// Each value declared here must also be covered by the static + /// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`. #[repr(transparent)] #[derive(Clone, Copy, Default)] pub struct DIFlags: u32 { @@ -752,7 +755,7 @@ pub mod debuginfo { const FlagPublic = 3; const FlagFwdDecl = (1 << 2); const FlagAppleBlock = (1 << 3); - const FlagBlockByrefStruct = (1 << 4); + const FlagReservedBit4 = (1 << 4); const FlagVirtual = (1 << 5); const FlagArtificial = (1 << 6); const FlagExplicit = (1 << 7); @@ -763,10 +766,21 @@ pub mod debuginfo { const FlagStaticMember = (1 << 12); const FlagLValueReference = (1 << 13); const FlagRValueReference = (1 << 14); - const FlagExternalTypeRef = (1 << 15); + const FlagReserved = (1 << 15); + const FlagSingleInheritance = (1 << 16); + const FlagMultipleInheritance = (2 << 16); + const FlagVirtualInheritance = (3 << 16); const FlagIntroducedVirtual = (1 << 18); const FlagBitField = (1 << 19); const FlagNoReturn = (1 << 20); + // The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`. + const FlagTypePassByValue = (1 << 22); + const FlagTypePassByReference = (1 << 23); + const FlagEnumClass = (1 << 24); + const FlagThunk = (1 << 25); + const FlagNonTrivial = (1 << 26); + const FlagBigEndian = (1 << 27); + const FlagLittleEndian = (1 << 28); } } @@ -918,6 +932,7 @@ unsafe extern "C" { pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values + pub fn LLVMIsUndef(Val: &Value) -> Bool; pub fn LLVMTypeOf(Val: &Value) -> &Type; pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char; pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3254b5d38e7..b6b453d069e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -59,5 +59,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 484f467068a..a4c50dcc135 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -211,7 +211,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times - .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point codegen_ssa_no_field = no field `{$name}` diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 544578b29f1..83724af604d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -490,8 +490,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let ptr_ty = cx.type_ptr(); let (arg_argc, arg_argv) = get_argc_argv(&mut bx); - let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type - { + let EntryFnType::Main { sigpipe } = entry_type; + let (start_fn, start_ty, args, instance) = { let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); let start_instance = ty::Instance::expect_resolve( cx.tcx(), @@ -512,10 +512,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( vec![rust_main, arg_argc, arg_argv, arg_sigpipe], Some(start_instance), ) - } else { - debug!("using user-defined start fn"); - let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty); - (rust_main, start_ty, vec![arg_argc, arg_argv], None) }; let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); @@ -530,7 +526,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Obtain the `argc` and `argv` values to pass to the rust start function. +/// Obtain the `argc` and `argv` values to pass to the rust start function +/// (i.e., the "start" lang item). fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) { if bx.cx().sess().target.os.contains("uefi") { // Params for UEFI diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 19101ec2d1b..9ca7d4f8f00 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -204,14 +204,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let alloc_align = alloc.inner().align; assert!(alloc_align >= layout.align.abi); + // Returns `None` when the value is partially undefined or any byte of it has provenance. + // Otherwise returns the value or (if the entire value is undef) returns an undef. let read_scalar = |start, size, s: abi::Scalar, ty| { + let range = alloc_range(start, size); match alloc.0.read_scalar( bx, - alloc_range(start, size), + range, /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)), ) { - Ok(val) => bx.scalar_to_backend(val, s, ty), - Err(_) => bx.const_poison(ty), + Ok(val) => Some(bx.scalar_to_backend(val, s, ty)), + Err(_) => { + // We may have failed due to partial provenance or unexpected provenance, + // continue down the normal code path if so. + if alloc.0.provenance().range_empty(range, &bx.tcx()) + // Since `read_scalar` failed, but there were no relocations involved, the + // bytes must be partially or fully uninitialized. Thus we can now unwrap the + // information about the range of uninit bytes and check if it's the full range. + && alloc.0.init_mask().is_range_initialized(range).unwrap_err() == range + { + Some(bx.const_undef(ty)) + } else { + None + } + } } }; @@ -222,16 +238,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). match layout.backend_repr { - BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { + BackendRepr::Scalar(s) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); - OperandRef { val: OperandValue::Immediate(val), layout } + if let Some(val) = read_scalar(offset, size, s, bx.immediate_backend_type(layout)) { + return OperandRef { val: OperandValue::Immediate(val), layout }; + } } - BackendRepr::ScalarPair( - a @ abi::Scalar::Initialized { .. }, - b @ abi::Scalar::Initialized { .. }, - ) => { + BackendRepr::ScalarPair(a, b) => { let (a_size, b_size) = (a.size(bx), b.size(bx)); let b_offset = (offset + a_size).align_to(b.align(bx).abi); assert!(b_offset.bytes() > 0); @@ -247,20 +261,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { b, bx.scalar_pair_element_backend_type(layout, 1, true), ); - OperandRef { val: OperandValue::Pair(a_val, b_val), layout } - } - _ if layout.is_zst() => OperandRef::zero_sized(layout), - _ => { - // Neither a scalar nor scalar pair. Load from a place - // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the - // same `ConstAllocation`? - let init = bx.const_data_from_alloc(alloc); - let base_addr = bx.static_addr_of(init, alloc_align, None); - - let llval = bx.const_ptr_byte_offset(base_addr, offset); - bx.load_operand(PlaceRef::new_sized(llval, layout)) + if let (Some(a_val), Some(b_val)) = (a_val, b_val) { + return OperandRef { val: OperandValue::Pair(a_val, b_val), layout }; + } } + _ if layout.is_zst() => return OperandRef::zero_sized(layout), + _ => {} } + // Neither a scalar nor scalar pair. Load from a place + // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the + // same `ConstAllocation`? + let init = bx.const_data_from_alloc(alloc); + let base_addr = bx.static_addr_of(init, alloc_align, None); + + let llval = bx.const_ptr_byte_offset(base_addr, offset); + bx.load_operand(PlaceRef::new_sized(llval, layout)) } /// Asserts that this operand refers to a scalar and returns diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index eb4ef599b82..e775d219c7b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // If `v` is an integer constant whose value is just a single byte repeated N times, + // emit a `memset` filling the entire `dest` with that byte. let try_init_all_same = |bx: &mut Bx, v| { let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); @@ -117,13 +119,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { false }; + trace!(?cg_elem.val); match cg_elem.val { OperandValue::Immediate(v) => { if try_init_all_same(bx, v) { return; } } - _ => (), + OperandValue::Pair(a, b) => { + let a_is_undef = bx.cx().is_undef(a); + match (a_is_undef, bx.cx().is_undef(b)) { + // Can happen for uninit unions + (true, true) => { + // FIXME: can we produce better output here? + } + (false, true) | (true, false) => { + let val = if a_is_undef { b } else { a }; + if try_init_all_same(bx, val) { + return; + } + } + (false, false) => { + // FIXME: if both are the same value, use try_init_all_same + } + } + } + OperandValue::ZeroSized => unreachable!("checked above"), + OperandValue::Ref(..) => {} } let count = self @@ -365,10 +387,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { use abi::Primitive::*; imm = bx.from_immediate(imm); - // When scalars are passed by value, there's no metadata recording their - // valid ranges. For example, `char`s are passed as just `i32`, with no - // way for LLVM to know that they're 0x10FFFF at most. Thus we assume - // the range of the input value too, not just the output range. + // If we have a scalar, we must already know its range. Either + // + // 1) It's a parameter with `range` parameter metadata, + // 2) It's something we `load`ed with `!range` metadata, or + // 3) After a transmute we `assume`d the range (see below). + // + // That said, last time we tried removing this, it didn't actually help + // the rustc-perf results, so might as well keep doing it + // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182> self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { @@ -389,7 +416,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.bitcast(int_imm, to_backend_ty) } }; + + // This `assume` remains important for cases like (a conceptual) + // transmute::<u32, NonZeroU32>(x) == 0 + // since it's never passed to something with parameter metadata (especially + // after MIR inlining) so the only way to tell the backend about the + // constraint that the `transmute` introduced is to `assume` it. self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty); + imm = bx.to_immediate_scalar(imm, to_scalar); imm } @@ -411,31 +445,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - let abi::WrappingRange { start, end } = scalar.valid_range(self.cx); - - if start <= end { - if start > 0 { - let low = bx.const_uint_big(backend_ty, start); - let cmp = bx.icmp(IntPredicate::IntUGE, imm, low); - bx.assume(cmp); - } - - let type_max = scalar.size(self.cx).unsigned_int_max(); - if end < type_max { - let high = bx.const_uint_big(backend_ty, end); - let cmp = bx.icmp(IntPredicate::IntULE, imm, high); - bx.assume(cmp); - } - } else { - let low = bx.const_uint_big(backend_ty, start); - let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low); - - let high = bx.const_uint_big(backend_ty, end); - let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high); - - let or = bx.or(cmp_low, cmp_high); - bx.assume(or); - } + let range = scalar.valid_range(self.cx); + bx.assume_integer_range(imm, backend_ty, range); } pub(crate) fn codegen_rvalue_unsized( diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 3ee13b19f66..bbf87a59942 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -217,6 +217,27 @@ pub trait BuilderMethods<'a, 'tcx>: dest: PlaceRef<'tcx, Self::Value>, ); + /// Emits an `assume` that the integer value `imm` of type `ty` is contained in `range`. + /// + /// This *always* emits the assumption, so you probably want to check the + /// optimization level and `Scalar::is_always_valid` before calling it. + fn assume_integer_range(&mut self, imm: Self::Value, ty: Self::Type, range: WrappingRange) { + let WrappingRange { start, end } = range; + + // Perhaps one day we'll be able to use assume operand bundles for this, + // but for now this encoding with a single icmp+assume is best per + // <https://github.com/llvm/llvm-project/issues/123278#issuecomment-2597440158> + let shifted = if start == 0 { + imm + } else { + let low = self.const_uint_big(ty, start); + self.sub(imm, low) + }; + let width = self.const_uint_big(ty, u128::wrapping_sub(end, start)); + let cmp = self.icmp(IntPredicate::IntULE, shifted, width); + self.assume(cmp); + } + fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); fn nonnull_metadata(&mut self, load: Self::Value); diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 9af463a691a..d0de7ff0b5f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes { /// Generate an uninitialized value (matching uninitialized memory in MIR). /// Whether memory is initialized or not is tracked byte-for-byte. fn const_undef(&self, t: Self::Type) -> Self::Value; + fn is_undef(&self, v: Self::Value) -> bool; /// Generate a fake value. Poison always affects the entire value, even if just a single byte is /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c8ecddb046c..889a8299c18 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,7 @@ tracing = "0.1" version = "0.12" [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 9739e501272..e761faee67b 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -60,9 +60,9 @@ impl Lock { unsafe { LockFileEx( - HANDLE(file.as_raw_handle() as isize), + HANDLE(file.as_raw_handle()), flags, - 0, + None, u32::MAX, u32::MAX, &mut overlapped, diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 2f0fe64b096..07b88e59723 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -59,7 +59,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index f7e7aa64614..20be2144609 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,8 +28,8 @@ use std::io::{self, IsTerminal, Read, Write}; use std::panic::{self, PanicHookInfo, catch_unwind}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; +use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; use std::{env, str}; @@ -53,14 +53,13 @@ use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions, - Z_OPTIONS, nightly_options, + Z_OPTIONS, nightly_options, parse_target_triple, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::collect_crate_types; use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; use rustc_span::FileName; -use rustc_span::source_map::FileLoader; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; use time::OffsetDateTime; @@ -208,84 +207,7 @@ pub fn diagnostics_registry() -> Registry { } /// This is the primary entry point for rustc. -pub struct RunCompiler<'a> { - at_args: &'a [String], - callbacks: &'a mut (dyn Callbacks + Send), - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - make_codegen_backend: - Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, - using_internal_features: Arc<std::sync::atomic::AtomicBool>, -} - -impl<'a> RunCompiler<'a> { - pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self { - Self { - at_args, - callbacks, - file_loader: None, - make_codegen_backend: None, - using_internal_features: Arc::default(), - } - } - - /// Set a custom codegen backend. - /// - /// Has no uses within this repository, but is used by bjorn3 for "the - /// hotswapping branch of cg_clif" for "setting the codegen backend from a - /// custom driver where the custom codegen backend has arbitrary data." - /// (See #102759.) - pub fn set_make_codegen_backend( - &mut self, - make_codegen_backend: Option< - Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, - >, - ) -> &mut Self { - self.make_codegen_backend = make_codegen_backend; - self - } - - /// Load files from sources other than the file system. - /// - /// Has no uses within this repository, but may be used in the future by - /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for - /// running rustc without having to save". (See #102759.) - pub fn set_file_loader( - &mut self, - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - ) -> &mut Self { - self.file_loader = file_loader; - self - } - - /// Set the session-global flag that checks whether internal features have been used, - /// suppressing the message about submitting an issue in ICEs when enabled. - #[must_use] - pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self { - self.using_internal_features = using_internal_features; - self - } - - /// Parse args and run the compiler. - pub fn run(self) { - run_compiler( - self.at_args, - self.callbacks, - self.file_loader, - self.make_codegen_backend, - self.using_internal_features, - ); - } -} - -fn run_compiler( - at_args: &[String], - callbacks: &mut (dyn Callbacks + Send), - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - make_codegen_backend: Option< - Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, - >, - using_internal_features: Arc<std::sync::atomic::AtomicBool>, -) { +pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) { let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); // Throw away the first argument, the name of the binary. @@ -322,16 +244,16 @@ fn run_compiler( output_file: ofile, output_dir: odir, ice_file, - file_loader, + file_loader: None, locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(), lint_caps: Default::default(), psess_created: None, hash_untracked_state: None, register_lints: None, override_queries: None, - make_codegen_backend, + make_codegen_backend: None, registry: diagnostics_registry(), - using_internal_features, + using_internal_features: &USING_INTERNAL_FEATURES, expanded_args: args, }; @@ -916,13 +838,7 @@ pub fn version_at_macro_invocation( safe_println!("host: {}", config::host_tuple()); safe_println!("release: {release}"); - let debug_flags = matches.opt_strs("Z"); - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version(); + get_backend_from_raw_matches(early_dcx, matches).print_version(); } } @@ -1125,19 +1041,32 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> } if cg_flags.iter().any(|x| *x == "passes=list") { - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes(); + get_backend_from_raw_matches(early_dcx, matches).print_passes(); return true; } false } +/// Get the codegen backend based on the raw [`Matches`]. +/// +/// `rustc -vV` and `rustc -Cpasses=list` need to get the codegen backend before we have parsed all +/// arguments and created a [`Session`]. This function reads `-Zcodegen-backend`, `--target` and +/// `--sysroot` without validating any other arguments and loads the codegen backend based on these +/// arguments. +fn get_backend_from_raw_matches( + early_dcx: &EarlyDiagCtxt, + matches: &Matches, +) -> Box<dyn CodegenBackend> { + let debug_flags = matches.opt_strs("Z"); + let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); + let target = parse_target_triple(early_dcx, matches); + let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from)); + let target = config::build_target_config(early_dcx, &target, &sysroot); + + get_codegen_backend(early_dcx, &sysroot, backend_name, &target) +} + fn describe_debug_flags() { safe_println!("\nAvailable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); @@ -1343,6 +1272,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat }) } +pub static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); + /// Installs a panic hook that will print the ICE message on unexpected panics. /// /// The hook is intended to be useable even by external tools. You can pass a custom @@ -1353,15 +1284,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to /// extra_info. /// -/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to -/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering -/// internal features. -/// /// A custom rustc driver can skip calling this to set up a custom ICE hook. -pub fn install_ice_hook( - bug_report_url: &'static str, - extra_info: fn(&DiagCtxt), -) -> Arc<AtomicBool> { +pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&DiagCtxt)) { // If the user has not explicitly overridden "RUST_BACKTRACE", then produce // full backtraces. When a compiler ICE happens, we want to gather // as much information as possible to present in the issue opened @@ -1378,8 +1302,6 @@ pub fn install_ice_hook( } } - let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); - let using_internal_features_hook = Arc::clone(&using_internal_features); panic::update_hook(Box::new( move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), info: &PanicHookInfo<'_>| { @@ -1431,11 +1353,9 @@ pub fn install_ice_hook( } // Print the ICE message - report_ice(info, bug_report_url, extra_info, &using_internal_features_hook); + report_ice(info, bug_report_url, extra_info, &USING_INTERNAL_FEATURES); }, )); - - using_internal_features } /// Prints the ICE message, including query stack, but without backtrace. @@ -1521,9 +1441,9 @@ fn report_ice( // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0"); - let num_frames = if backtrace { None } else { Some(2) }; + let limit_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(dcx, num_frames, file); + interface::try_print_query_stack(dcx, limit_frames, file); // We don't trust this callback not to panic itself, so run it at the end after we're sure we've // printed all the relevant info. @@ -1576,13 +1496,11 @@ pub fn main() -> ! { init_rustc_env_logger(&early_dcx); signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); - let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); + install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); install_ctrlc_handler(); let exit_code = catch_with_exit_code(|| { - RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks) - .set_using_internal_features(using_internal_features) - .run(); + run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks); Ok(()) }); diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index 014d8c4f761..4b06395897a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -264,15 +264,15 @@ trait Foo { ### Trait contains associated constants Just like static functions, associated constants aren't stored on the method -table. If the trait or any subtrait contain an associated constant, they cannot -be made into an object. +table. If the trait or any subtrait contain an associated constant, they are not +dyn compatible. ```compile_fail,E0038 trait Foo { const X: i32; } -impl Foo {} +impl dyn Foo {} ``` A simple workaround is to use a helper method instead: diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md index 51258739b89..cbb14510ed7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0132.md +++ b/compiler/rustc_error_codes/src/error_codes/E0132.md @@ -1,32 +1,3 @@ -A function with the `start` attribute was declared with type parameters. - -Erroneous code example: - -```compile_fail,E0132 -#![feature(start)] - -#[start] -fn f<T>() {} -``` - -It is not possible to declare type parameters on a function that has the `start` -attribute. Such a function must have the following type signature (for more -information, view [the unstable book][1]): +#### Note: this error code is no longer emitted by the compiler. -[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html - -``` -# let _: -fn(isize, *const *const u8) -> isize; -``` - -Example: - -``` -#![feature(start)] - -#[start] -fn my_start(argc: isize, argv: *const *const u8) -> isize { - 0 -} -``` +A function with the `start` attribute was declared with type parameters. diff --git a/compiler/rustc_error_codes/src/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md index 3f5eaea9f98..2e6ba546a16 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0138.md +++ b/compiler/rustc_error_codes/src/error_codes/E0138.md @@ -1,25 +1,3 @@ -More than one function was declared with the `#[start]` attribute. - -Erroneous code example: - -```compile_fail,E0138 -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} +#### Note: this error code is no longer emitted by the compiler. -#[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} -// error: multiple 'start' functions -``` - -This error indicates that the compiler found multiple functions with the -`#[start]` attribute. This is an error because there must be a unique entry -point into a Rust program. Example: - -``` -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok! -``` +More than one function was declared with the `#[start]` attribute. diff --git a/compiler/rustc_error_codes/src/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md index 59bb47ba62a..e2f14b81aa6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0647.md +++ b/compiler/rustc_error_codes/src/error_codes/E0647.md @@ -1,13 +1,3 @@ -The `start` function was defined with a where clause. - -Erroneous code example: +#### Note: this error code is no longer emitted by the compiler. -```compile_fail,E0647 -#![feature(start)] - -#[start] -fn start(_: isize, _: *const *const u8) -> isize where (): Copy { - //^ error: `#[start]` function is not allowed to have a where clause - 0 -} -``` +The `start` function was defined with a where clause. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 29f3277d399..0a30bdb48a0 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -24,6 +24,10 @@ // // Both columns are necessary because it's not possible in Rust to create a new identifier such as // `E0123` from an integer literal such as `0123`, unfortunately. +// +// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown +// file saying that this error is not emitted by the compiler any more (see E0001.md for an +// example), and remove all code examples that do not build any more. #[macro_export] macro_rules! error_codes { ($macro:path) => ( diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 66b9adbead0..fbb6a1cc475 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -31,7 +31,7 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Security", diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index ef209c2bce1..21688521ade 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -282,11 +282,13 @@ pub(super) fn transcribe<'a>( } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { marker.visit_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { marker.visit_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } @@ -295,6 +297,8 @@ pub(super) fn transcribe<'a>( // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. marker.visit_span(&mut sp); + let use_span = nt.use_span(); + with_metavar_spans(|mspans| mspans.insert(use_span, sp)); TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp) } MatchedSeq(..) => { @@ -410,19 +414,15 @@ fn maybe_use_metavar_location( return orig_tt.clone(); } - let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) { - Ok(_) => true, - Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success - }; marker.visit_span(&mut metavar_span); let no_collision = match orig_tt { TokenTree::Token(token, ..) => { - with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span)) + with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span)) } TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| { - insert(mspans, dspan.open, metavar_span) - && insert(mspans, dspan.close, metavar_span) - && insert(mspans, dspan.entire(), metavar_span) + mspans.insert(dspan.open, metavar_span) + && mspans.insert(dspan.close, metavar_span) + && mspans.insert(dspan.entire(), metavar_span) }), }; if no_collision || psess.source_map().is_imported(metavar_span) { @@ -434,14 +434,14 @@ fn maybe_use_metavar_location( match orig_tt { TokenTree::Token(Token { kind, span }, spacing) => { let span = metavar_span.with_ctxt(span.ctxt()); - with_metavar_spans(|mspans| insert(mspans, span, metavar_span)); + with_metavar_spans(|mspans| mspans.insert(span, metavar_span)); TokenTree::Token(Token { kind: kind.clone(), span }, *spacing) } TokenTree::Delimited(dspan, dspacing, delimiter, tts) => { let open = metavar_span.with_ctxt(dspan.open.ctxt()); let close = metavar_span.with_ctxt(dspan.close.ctxt()); with_metavar_spans(|mspans| { - insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span) + mspans.insert(open, metavar_span) && mspans.insert(close, metavar_span) }); let dspan = DelimSpan::from_pair(open, close); TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone()) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5510e7e09e5..68e0191f45e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -448,7 +448,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Entry point: - ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 9aa59375706..081638715df 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -163,7 +163,7 @@ declare_features! ( /// then removed. But there was no utility storing it separately, so now /// it's in this list. (removed, no_stack_check, "1.0.0", None, None), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible (object safe). + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe). /// Renamed to `dyn_compatible_for_dispatch`. (removed, object_safe_for_dispatch, "1.83.0", Some(43561), Some("renamed to `dyn_compatible_for_dispatch`")), @@ -220,8 +220,9 @@ declare_features! ( (removed, rustc_diagnostic_macros, "1.38.0", None, None), /// Allows identifying crates that contain sanitizer runtimes. (removed, sanitizer_runtime, "1.17.0", None, None), - (removed, simd, "1.0.0", Some(27731), - Some("removed in favor of `#[repr(simd)]`")), + (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")), + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. + (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")), /// Allows `#[link(kind = "static-nobundle", ...)]`. (removed, static_nobundle, "1.16.0", Some(37403), Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4ab0bc47305..1a216ebf117 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -272,7 +272,7 @@ declare_features! ( (unstable, doc_notable_trait, "1.52.0", Some(45040)), /// Allows using the `may_dangle` attribute (RFC 1327). (unstable, dropck_eyepatch, "1.10.0", Some(34761)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1]. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. /// @@ -300,8 +300,6 @@ declare_features! ( (internal, rustdoc_internals, "1.58.0", Some(90418)), /// Allows using the `rustdoc::missing_doc_code_examples` lint (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)), - /// Allows using `#[start]` on a function indicating that it is the program entrypoint. - (unstable, start, "1.0.0", Some(29633)), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library /// feature with the same name exists. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index fae3b778d7b..02bc069fc5f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -332,6 +332,10 @@ language_item_table! { FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; + /// For all binary crates without `#![no_main]`, Rust will generate a "main" function. + /// The exact name and signature are target-dependent. The "main" function will invoke + /// this lang item, passing it the `argc` and `argv` (or null, if those don't exist + /// on the current target) as well as the user-defined `fn main` from the binary crate. Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d7ab6eca84b..512d379687b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -489,21 +489,6 @@ hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is hi hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable .help = add `#![feature(min_specialization)]` to the crate attributes to enable -hir_analysis_start_function_parameters = `#[start]` function is not allowed to have type parameters - .label = `#[start]` function cannot have type parameters - -hir_analysis_start_function_where = `#[start]` function is not allowed to have a `where` clause - .label = `#[start]` function cannot have a `where` clause - -hir_analysis_start_not_async = `#[start]` function is not allowed to be `async` - .label = `#[start]` is not allowed to be `async` - -hir_analysis_start_not_target_feature = `#[start]` function is not allowed to have `#[target_feature]` - .label = `#[start]` function is not allowed to have `#[target_feature]` - -hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` - .label = `#[start]` function is not allowed to be `#[track_caller]` - hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d8e9227a87c..b3eade8c8ae 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { if self.infcx.next_trait_solver() && let ty::Alias(..) = ty.kind() { - let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; self.state.obligations.extend(obligations); (AutoderefKind::Builtin, normalized_ty) } else { @@ -166,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } let (normalized_ty, obligations) = - self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; + self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); @@ -174,12 +174,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> { let ocx = ObligationCtxt::new(self.infcx); - let Ok(normalized_ty) = ocx.structurally_normalize( + let Ok(normalized_ty) = ocx.structurally_normalize_ty( &traits::ObligationCause::misc(self.span, self.body_id), self.param_env, ty, diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 332ac2fa0c0..25c2f8554b7 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_span::{Span, sym}; @@ -18,7 +18,6 @@ use crate::errors; pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) { match tcx.entry_fn(()) { Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id), - Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id), _ => {} } } @@ -192,83 +191,3 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { }); } } - -fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { - let start_def_id = start_def_id.expect_local(); - let start_id = tcx.local_def_id_to_hir_id(start_def_id); - let start_span = tcx.def_span(start_def_id); - let start_t = tcx.type_of(start_def_id).instantiate_identity(); - match start_t.kind() { - ty::FnDef(..) => { - if let Node::Item(it) = tcx.hir_node(start_id) { - if let hir::ItemKind::Fn { sig, generics, .. } = &it.kind { - let mut error = false; - if !generics.params.is_empty() { - tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span }); - error = true; - } - if generics.has_where_clause_predicates { - tcx.dcx().emit_err(errors::StartFunctionWhere { - span: generics.where_clause_span, - }); - error = true; - } - if sig.header.asyncness.is_async() { - let span = tcx.def_span(it.owner_id); - tcx.dcx().emit_err(errors::StartAsync { span }); - error = true; - } - - let attrs = tcx.hir().attrs(start_id); - for attr in attrs { - if attr.has_name(sym::track_caller) { - tcx.dcx().emit_err(errors::StartTrackCaller { - span: attr.span, - start: start_span, - }); - error = true; - } - if attr.has_name(sym::target_feature) - // Calling functions with `#[target_feature]` is - // not unsafe on WASM, see #84988 - && !tcx.sess.target.is_like_wasm - && !tcx.sess.opts.actually_rustdoc - { - tcx.dcx().emit_err(errors::StartTargetFeature { - span: attr.span, - start: start_span, - }); - error = true; - } - } - - if error { - return; - } - } - } - - let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], - tcx.types.isize, - false, - hir::Safety::Safe, - ExternAbi::Rust, - )); - - let _ = check_function_signature( - tcx, - ObligationCause::new( - start_span, - start_def_id, - ObligationCauseCode::StartFunctionType, - ), - start_def_id.into(), - expected_sig, - ); - } - _ => { - span_bug!(start_span, "start has a non-function type: found `{}`", start_t); - } - } -} diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 1be4aa2f63a..4e5f0a3186a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -13,6 +13,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; use rustc_span::{ErrorGuaranteed, sym}; +use rustc_type_ir::elaborate; use tracing::debug; use crate::errors; @@ -184,7 +185,7 @@ fn check_object_overlap<'tcx>( // check for overlap with the automatic `impl Trait for dyn Trait` if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { // This is something like `impl Trait1 for Trait2`. Illegal if - // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible. + // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible. let component_def_ids = data.iter().flat_map(|predicate| { match predicate.skip_binder() { @@ -205,7 +206,7 @@ fn check_object_overlap<'tcx>( // With the feature enabled, the trait is not implemented automatically, // so this is valid. } else { - let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id); + let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object) { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 7d651155781..d17ee86ba66 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -320,7 +320,7 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &cause, ty::ParamEnv::empty(), infcx.resolve_vars_if_possible(ty), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 00ba1741ed7..a0f365142ba 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -620,48 +620,6 @@ pub(crate) struct TargetFeatureOnMain { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_not_track_caller)] -pub(crate) struct StartTrackCaller { - #[primary_span] - pub span: Span, - #[label] - pub start: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_not_target_feature)] -pub(crate) struct StartTargetFeature { - #[primary_span] - pub span: Span, - #[label] - pub start: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_not_async, code = E0752)] -pub(crate) struct StartAsync { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_function_where, code = E0647)] -pub(crate) struct StartFunctionWhere { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_function_parameters, code = E0132)] -pub(crate) struct StartFunctionParameters { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_main_function_return_type_generic, code = E0131)] pub(crate) struct MainFunctionReturnTypeGeneric { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 71a5727ed6c..72ad190df7e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -4,13 +4,12 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; -use rustc_middle::span_bug; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; @@ -30,16 +29,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], + hir_bounds: &[hir::PolyTraitRef<'tcx>], lifetime: &hir::Lifetime, representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); + let dummy_self = tcx.types.trait_object_dummy_self; - let mut bounds = Bounds::default(); + let mut user_written_bounds = Bounds::default(); let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { + for trait_bound in hir_bounds.iter() { if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { continue; } @@ -53,92 +52,67 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::BoundConstness::Never, hir::BoundPolarity::Positive, dummy_self, - &mut bounds, + &mut user_written_bounds, PredicateFilter::SelfOnly, ) { potential_assoc_types.extend(cur_potential_assoc_types); } } - let mut trait_bounds = vec![]; - let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { - let bound_pred = pred.kind(); - match bound_pred.skip_binder() { - ty::ClauseKind::Trait(trait_pred) => { - assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); - trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span)); - } - ty::ClauseKind::Projection(proj) => { - projection_bounds.push((bound_pred.rebind(proj), span)); - } - ty::ClauseKind::TypeOutlives(_) => { - // Do nothing, we deal with regions separately - } - ty::ClauseKind::RegionOutlives(_) - | ty::ClauseKind::ConstArgHasType(..) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::HostEffect(..) => { - span_bug!(span, "did not expect {pred} clause in object bounds"); - } - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b))); - - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = - expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + let (trait_bounds, mut projection_bounds) = + traits::expand_trait_aliases(tcx, user_written_bounds.clauses()); + let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds + .into_iter() + .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + // We don't support empty trait objects. + if regular_traits.is_empty() && auto_traits.is_empty() { + let guar = + self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses()); + return Ty::new_error(tcx, guar); + } // We don't support >1 principal if regular_traits.len() > 1 { let guar = self.report_trait_object_addition_traits_error(®ular_traits); return Ty::new_error(tcx, guar); } - // We don't support empty trait objects. - if regular_traits.is_empty() && auto_traits.is_empty() { - let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds); - return Ty::new_error(tcx, guar); - } // Don't create a dyn trait if we have errors in the principal. - if let Err(guar) = trait_bounds.error_reported() { + if let Err(guar) = regular_traits.error_reported() { return Ty::new_error(tcx, guar); } // Check that there are no gross dyn-compatibility violations; // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. - for item in ®ular_traits { - let violations = - hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id()); - if !violations.is_empty() { - let reported = report_dyn_incompatibility( - tcx, - span, - Some(hir_id), - item.trait_ref().def_id(), - &violations, - ) - .emit(); - return Ty::new_error(tcx, reported); + for (clause, span) in user_written_bounds.clauses() { + if let Some(trait_pred) = clause.as_trait_clause() { + let violations = + hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id()); + if !violations.is_empty() { + let reported = report_dyn_incompatibility( + tcx, + span, + Some(hir_id), + trait_pred.def_id(), + &violations, + ) + .emit(); + return Ty::new_error(tcx, reported); + } } } - let mut needed_associated_types = FxIndexSet::default(); - - let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1); - let regular_traits_refs_spans = trait_bounds - .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + let principal_trait = regular_traits.into_iter().next(); - for (base_trait_ref, original_span) in regular_traits_refs_spans { - let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx); + let mut needed_associated_types = FxIndexSet::default(); + if let Some((principal_trait, spans)) = &principal_trait { + let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx); for ClauseWithSupertraitSpan { pred, supertrait_span } in - traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)]) - .filter_only_self() + traits::elaborate(tcx, [ClauseWithSupertraitSpan::new( + pred, + *spans.last().unwrap(), + )]) + .filter_only_self() { debug!("observing object predicate `{pred:?}`"); @@ -179,7 +153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // } // ``` // - // Here, the user could theoretically write `dyn MyTrait<Output = X>`, + // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`, // but actually supporting that would "expand" to an infinitely-long type // `fix $ Ï„ → dyn MyTrait<MyOutput = X, Output = <Ï„ as MyTrait>::MyOutput`. // @@ -188,12 +162,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, original_span)); + projection_bounds.push((pred, supertrait_span)); } self.check_elaborated_projection_mentions_input_lifetimes( pred, - original_span, + *spans.first().unwrap(), supertrait_span, ); } @@ -202,11 +176,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`. - // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated - // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a - // corresponding `Projection` clause - for (projection_bound, span) in &projection_bounds { + // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where + // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an + // `Assoc = Foo` bound. `needed_associated_types` contains all associated + // types that we expect to be provided by the user, so the following loop + // removes all the associated types that have a corresponding `Projection` + // clause, either from expanding trait aliases or written by the user. + for &(projection_bound, span) in &projection_bounds { let def_id = projection_bound.item_def_id(); let trait_ref = tcx.anonymize_bound_vars( projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), @@ -216,17 +192,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, - *span, - crate::errors::UnusedAssociatedTypeBounds { span: *span }, + span, + crate::errors::UnusedAssociatedTypeBounds { span }, ); } } if let Err(guar) = self.check_for_required_assoc_tys( - principal_span, + principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()), needed_associated_types, potential_assoc_types, - hir_trait_bounds, + hir_bounds, ) { return Ty::new_error(tcx, guar); } @@ -236,32 +212,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering // the bounds let mut duplicates = FxHashSet::default(); - auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); - debug!(?regular_traits); + auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id())); + + debug!(?principal_trait); debug!(?auto_traits); // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = regular_traits.iter().map(|i| { - i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| { + trait_pred.map_bound(|trait_pred| { + let trait_ref = trait_pred.trait_ref; + assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); assert_eq!(trait_ref.self_ty(), dummy_self); + let span = *spans.first().unwrap(); + // Verify that `dummy_self` did not leak inside default type parameters. This // could not be done at path creation, since we need to see through trait aliases. let mut missing_type_params = vec![]; - let mut references_self = false; let generics = tcx.generics_of(trait_ref.def_id); let args: Vec<_> = trait_ref .args .iter() .enumerate() - .skip(1) // Remove `Self` for `ExistentialPredicate`. + // Skip `Self` + .skip(1) .map(|(index, arg)| { if arg == dummy_self.into() { let param = &generics.own_params[index]; missing_type_params.push(param.name); Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { - references_self = true; let guar = self.dcx().span_delayed_bug( span, "trait object trait bounds reference `Self`", @@ -273,8 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) .collect(); - let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + let empty_generic_args = hir_bounds.iter().any(|hir_bound| { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); @@ -285,26 +264,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { empty_generic_args, ); - if references_self { - let def_id = i.bottom().0.def_id(); - struct_span_code_err!( - self.dcx(), - i.bottom().1, - E0038, - "the {} `{}` cannot be made into an object", - tcx.def_descr(def_id), - tcx.item_name(def_id), - ) - .with_note( - rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf( - smallvec![], - ) - .error_msg(), - ) - .emit(); - } - - ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args) + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new( + tcx, + trait_ref.def_id, + args, + )) }) }); @@ -327,21 +291,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar); } - ty::ExistentialProjection::erase_self_ty(tcx, b) + ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty( + tcx, b, + )) }) }); - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| { + assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive); + assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self); + + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id())) }); + // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling - let mut v = regular_trait_predicates - .chain( - existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), - ) + let mut v = principal_trait_ref + .into_iter() + .chain(existential_projections) .chain(auto_trait_predicates) .collect::<SmallVec<[_; 8]>>(); v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 7a3d921f00e..5d751a25080 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::{ - self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt, + self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_param, }; use rustc_session::parse::feature_err; @@ -19,8 +19,9 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ - FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item, + FulfillmentError, dyn_compatibility_violations_for_assoc_item, }; +use smallvec::SmallVec; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, @@ -720,7 +721,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn check_for_required_assoc_tys( &self, - principal_span: Span, + spans: SmallVec<[Span; 1]>, missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>, potential_assoc_types: Vec<usize>, trait_bounds: &[hir::PolyTraitRef<'_>], @@ -729,6 +730,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return Ok(()); } + let principal_span = *spans.first().unwrap(); + let tcx = self.tcx(); // FIXME: This logic needs some more care w.r.t handling of conflicts let missing_assoc_types: Vec<_> = missing_assoc_types @@ -1124,29 +1127,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn report_trait_object_addition_traits_error( &self, - regular_traits: &Vec<TraitAliasExpansionInfo<'_>>, + regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>, ) -> ErrorGuaranteed { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; + // we use the last span to point at the traits themselves, + // and all other preceding spans are trait alias expansions. + let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap(); + let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap(); let mut err = struct_span_code_err!( self.dcx(), - additional_trait.bottom().1, + *regular_traits[1].1.first().unwrap(), E0225, "only auto traits can be used as additional traits in a trait object" ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.span_label(first_span, "first non-auto trait"); + for &alias_span in first_alias_spans { + err.span_label(alias_span, "first non-auto trait comes from this alias"); + } + err.span_label(second_span, "additional non-auto trait"); + for &alias_span in second_alias_spans { + err.span_label(alias_span, "second non-auto trait comes from this alias"); + } err.help(format!( "consider creating a new trait with all of these as supertraits and using that \ trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() // FIXME: This should `print_sugared`, but also needs to integrate projection bounds... - .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .map(|(pred, _)| pred + .map_bound(|pred| pred.trait_ref) + .print_only_trait_path() + .to_string()) .collect::<Vec<_>>() .join(" + "), )); @@ -1161,14 +1171,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn report_trait_object_with_no_traits_error( &self, span: Span, - trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>, + user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, ) -> ErrorGuaranteed { let tcx = self.tcx(); - let trait_alias_span = trait_bounds - .iter() - .map(|&(trait_ref, _)| trait_ref.def_id()) - .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) - .map(|trait_ref| tcx.def_span(trait_ref)); + let trait_alias_span = user_written_clauses + .into_iter() + .filter_map(|(clause, _)| clause.as_trait_clause()) + .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id())) + .map(|trait_ref| tcx.def_span(trait_ref.def_id())); self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 7b07e0ee939..5d00ecbe918 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -45,6 +45,7 @@ use rustc_session::lint; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_type_ir::elaborate; use tracing::{debug, instrument}; use super::FnCtxt; @@ -923,7 +924,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let src_auto: FxHashSet<_> = src_tty .auto_traits() .chain( - tcx.supertrait_def_ids(src_principal.def_id()) + elaborate::supertrait_def_ids(tcx, src_principal.def_id()) .filter(|def_id| tcx.trait_is_auto(*def_id)), ) .collect(); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6945dbc3216..47abba1cc29 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to the target type), since that should be the least // confusing. let Some(InferOk { value: ty, mut obligations }) = found else { - let err = first_error.expect("coerce_borrowed_pointer had no error"); - debug!("coerce_borrowed_pointer: failed with err = {:?}", err); - return Err(err); + if let Some(first_error) = first_error { + debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error); + return Err(first_error); + } else { + // This may happen in the new trait solver since autoderef requires + // the pointee to be structurally normalizable, or else it'll just bail. + // So when we have a type like `&<not well formed>`, then we get no + // autoderef steps (even though there should be at least one). That means + // we get no type mismatches, since the loop above just exits early. + return Err(TypeError::Mismatch); + } }; if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { @@ -1124,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.next_trait_solver() && let ty::Alias(..) = ty.kind() { - ocx.structurally_normalize(&cause, self.param_env, ty) + ocx.structurally_normalize_ty(&cause, self.param_env, ty) } else { Ok(ty) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 01fed72d5a2..bdd436302f4 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_missing_fields( adt_ty, path_span, + expr.span, remaining_fields, variant, hir_fields, @@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, + full_span: Span, remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], @@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); + if remaining_fields.items().all(|(_, (_, field))| field.value.is_some()) + && self.tcx.sess.is_nightly_build() + { + let msg = format!( + "all remaining fields have default values, {you_can} use those values with `..`", + you_can = if self.tcx.features().default_field_values() { + "you can" + } else { + "if you added `#![feature(default_field_values)]` to your crate you could" + }, + ); + if let Some(hir_field) = hir_fields.last() { + err.span_suggestion_verbose( + hir_field.span.shrink_to_hi(), + msg, + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else if hir_fields.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(full_span.hi()), + msg, + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + } + if let Some(hir_field) = hir_fields.last() { self.suggest_fru_from_range_and_emit(hir_field, variant, args, err); } else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index be6d9570e35..e26c09e3601 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1433,7 +1433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in a reentrant borrow, causing an ICE. let result = self .at(&self.misc(sp), self.param_env) - .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()); + .structurally_normalize_ty(ty, &mut **self.fulfillment_cx.borrow_mut()); match result { Ok(normalized_ty) => normalized_ty, Err(errors) => { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 116765325a9..b9d1f93bfb8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,6 +1,5 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; -use std::iter; use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; @@ -1009,11 +1008,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.tcx.is_trait_alias(trait_def_id) { // For trait aliases, recursively assume all explicitly named traits are relevant - for expansion in traits::expand_trait_aliases( - self.tcx, - iter::once((ty::Binder::dummy(trait_ref), self.span)), - ) { - let bound_trait_ref = expansion.trait_ref(); + for (bound_trait_pred, _) in + traits::expand_trait_aliases(self.tcx, [(trait_ref.upcast(self.tcx), self.span)]).0 + { + assert_eq!(bound_trait_pred.polarity(), ty::PredicatePolarity::Positive); + let bound_trait_ref = bound_trait_pred.map_bound(|pred| pred.trait_ref); for item in self.impl_or_trait_item(bound_trait_ref.def_id()) { if !self.has_applicable_self(&item) { self.record_static_candidate(CandidateSource::Trait( diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 5fc9b679c8a..69ab0e69e21 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -114,7 +114,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { ) } - fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( + fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>>, U>( &self, value: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U, diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 7908733e734..061f7e6c22a 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -24,9 +24,9 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self), ret)] pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T where - T: TypeFoldable<TyCtxt<'tcx>> + Copy, + T: TypeFoldable<TyCtxt<'tcx>>, { - if let Some(inner) = binder.no_bound_vars() { + if let Some(inner) = binder.clone().no_bound_vars() { return inner; } @@ -71,7 +71,7 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self, f))] pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U where - T: TypeFoldable<TyCtxt<'tcx>> + Copy, + T: TypeFoldable<TyCtxt<'tcx>>, { // FIXME: currently we do nothing to prevent placeholders with the new universe being // used after exiting `f`. For example region subtyping can result in outlives constraints diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 1456255ea14..2113345eda3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -1,6 +1,5 @@ use std::path::PathBuf; use std::result; -use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; @@ -309,6 +308,11 @@ pub struct Config { pub output_dir: Option<PathBuf>, pub output_file: Option<OutFileName>, pub ice_file: Option<PathBuf>, + /// Load files from sources other than the file system. + /// + /// Has no uses within this repository, but may be used in the future by + /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for + /// running rustc without having to save". (See #102759.) pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>, /// The list of fluent resources, used for lints declared with /// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic). @@ -337,6 +341,11 @@ pub struct Config { pub override_queries: Option<fn(&Session, &mut Providers)>, /// This is a callback from the driver that is called to create a codegen backend. + /// + /// Has no uses within this repository, but is used by bjorn3 for "the + /// hotswapping branch of cg_clif" for "setting the codegen backend from a + /// custom driver where the custom codegen backend has arbitrary data." + /// (See #102759.) pub make_codegen_backend: Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, @@ -346,8 +355,7 @@ pub struct Config { /// The inner atomic value is set to true when a feature marked as `internal` is /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with /// internal features are wontfix, and they are usually the cause of the ICEs. - /// None signifies that this is not tracked. - pub using_internal_features: Arc<std::sync::atomic::AtomicBool>, + pub using_internal_features: &'static std::sync::atomic::AtomicBool, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -383,7 +391,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se crate::callbacks::setup_callbacks(); let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone()); - let target = config::build_target_config(&early_dcx, &config.opts, &sysroot); + let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target); @@ -533,7 +541,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se pub fn try_print_query_stack( dcx: DiagCtxtHandle<'_>, - num_frames: Option<usize>, + limit_frames: Option<usize>, file: Option<std::fs::File>, ) { eprintln!("query stack during panic:"); @@ -541,13 +549,13 @@ pub fn try_print_query_stack( // Be careful relying on global state here: this code is called from // a panic hook, which means that the global `DiagCtxt` may be in a weird // state if it was responsible for triggering the panic. - let i = ty::tls::with_context_opt(|icx| { + let all_frames = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { ty::print::with_no_queries!(print_query_stack( QueryCtxt::new(icx.tcx), icx.query, dcx, - num_frames, + limit_frames, file, )) } else { @@ -555,9 +563,14 @@ pub fn try_print_query_stack( } }); - if num_frames == None || num_frames >= Some(i) { - eprintln!("end of query stack"); + if let Some(limit_frames) = limit_frames + && all_frames > limit_frames + { + eprintln!( + "... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack", + all_frames - limit_frames + ); } else { - eprintln!("we're just showing a limited slice of the query stack"); + eprintln!("end of query stack"); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 07c4b898721..74d02ac2227 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZero; use std::path::{Path, PathBuf}; -use std::sync::Arc; +use std::sync::atomic::AtomicBool; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; @@ -42,7 +42,8 @@ where let matches = optgroups().parse(args).unwrap(); let sessopts = build_session_options(&mut early_dcx, &matches); let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone()); - let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot); + let target = + rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); let sm_inputs = Some(SourceMapInputs { @@ -61,6 +62,8 @@ where temps_dir, }; + static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); + let sess = build_session( early_dcx, sessopts, @@ -73,7 +76,7 @@ where sysroot, "", None, - Arc::default(), + &USING_INTERNAL_FEATURES, Default::default(), ); let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7522e21d0ef..64c8f00cc83 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -209,7 +209,9 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html> + .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}` + .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice + .help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html> lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary @@ -970,6 +972,8 @@ lint_unused_result = unused result of type `{$ty}` lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result +lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 259ea908fc6..b5a6159bd0a 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -9,7 +9,7 @@ use rustc_errors::{ use rustc_hir::{self as hir, HirIdSet}; use rustc_macros::LintDiagnostic; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{FutureIncompatibilityReason, Level}; +use rustc_session::lint::{FutureIncompatibilityReason, LintId}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::Span; use rustc_span::edition::Edition; @@ -245,12 +245,12 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() { - return; - } - if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { + if expr.span.edition().at_least_rust_2024() + || cx.tcx.lints_that_dont_need_to_run(()).contains(&LintId::of(IF_LET_RESCOPE)) + { return; } + if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind && let Some(value) = block.expr && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind @@ -290,7 +290,6 @@ struct IfLetRescopeLint { rewrite: Option<IfLetRescopeRewrite>, } -// #[derive(Subdiagnostic)] struct IfLetRescopeRewrite { match_heads: Vec<SingleArmMatchBegin>, consequent_heads: Vec<ConsequentRewrite>, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ac995b59caf..2f610802ff5 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1139,7 +1139,9 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { #[derive(LintDiagnostic)] #[diag(lint_dangling_pointers_from_temporaries)] #[note] -#[help] +#[help(lint_help_bind)] +#[help(lint_help_returned)] +#[help(lint_help_visit)] // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub callee: Symbol, @@ -1693,6 +1695,10 @@ pub(crate) struct OverflowingLiteral<'a> { } #[derive(LintDiagnostic)] +#[diag(lint_uses_power_alignment)] +pub(crate) struct UsesPowerAlignment; + +#[derive(LintDiagnostic)] #[diag(lint_unused_comparisons)] pub(crate) struct UnusedComparisons; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 3bd27a224e7..0757e6840c6 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,14 +1,15 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange}; +use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton}; use rustc_middle::ty::{ - self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, }; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; @@ -23,7 +24,7 @@ use crate::lints::{ AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons, - UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, + UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment, VariantSizeDifferencesDiag, }; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -727,7 +728,60 @@ declare_lint! { "proper use of libc types in foreign item definitions" } -declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]); +declare_lint! { + /// The `uses_power_alignment` lint detects specific `repr(C)` + /// aggregates on AIX. + /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment + /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment), + /// which can also be set for XLC by `#pragma align(power)` or + /// `-qalign=power`. Aggregates with a floating-point type as the + /// recursively first field (as in "at offset 0") modify the layout of + /// *subsequent* fields of the associated structs to use an alignment value + /// where the floating-point type is aligned on a 4-byte boundary. + /// + /// The power alignment rule for structs needed for C compatibility is + /// unimplementable within `repr(C)` in the compiler without building in + /// handling of references to packed fields and infectious nested layouts, + /// so a warning is produced in these situations. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-powerpc64-ibm-aix) + /// #[repr(C)] + /// pub struct Floats { + /// a: f64, + /// b: u8, + /// c: f64, + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + /// --> <source>:5:3 + /// | + /// 5 | c: f64, + /// | ^^^^^^ + /// | + /// = note: `#[warn(uses_power_alignment)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The power alignment rule specifies that the above struct has the + /// following alignment: + /// - offset_of!(Floats, a) == 0 + /// - offset_of!(Floats, b) == 8 + /// - offset_of!(Floats, c) == 12 + /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16. + /// Thus, a warning should be produced for the above struct in this case. + USES_POWER_ALIGNMENT, + Warn, + "Structs do not follow the power alignment rule under repr(C)" +} + +declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]); #[derive(Clone, Copy)] pub(crate) enum CItemKind { @@ -1539,6 +1593,71 @@ impl ImproperCTypesDefinitions { vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false); } } + + fn check_arg_for_power_alignment<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + // Structs (under repr(C)) follow the power alignment rule if: + // - the first field of the struct is a floating-point type that + // is greater than 4-bytes, or + // - the first field of the struct is an aggregate whose + // recursively first field is a floating-point type greater than + // 4 bytes. + if cx.tcx.sess.target.os != "aix" { + return false; + } + if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 { + return true; + } else if let Adt(adt_def, _) = ty.kind() + && adt_def.is_struct() + { + let struct_variant = adt_def.variant(VariantIdx::ZERO); + // Within a nested struct, all fields are examined to correctly + // report if any fields after the nested struct within the + // original struct are misaligned. + for struct_field in &struct_variant.fields { + let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity(); + if self.check_arg_for_power_alignment(cx, field_ty) { + return true; + } + } + } + return false; + } + + fn check_struct_for_power_alignment<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + item: &'tcx hir::Item<'tcx>, + ) { + let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id()); + if adt_def.repr().c() + && !adt_def.repr().packed() + && cx.tcx.sess.target.os == "aix" + && !adt_def.all_fields().next().is_none() + { + let struct_variant_data = item.expect_struct().0; + for (index, ..) in struct_variant_data.fields().iter().enumerate() { + // Struct fields (after the first field) are checked for the + // power alignment rule, as fields after the first are likely + // to be the fields that are misaligned. + if index != 0 { + let first_field_def = struct_variant_data.fields()[index]; + let def_id = first_field_def.def_id; + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if self.check_arg_for_power_alignment(cx, ty) { + cx.emit_span_lint( + USES_POWER_ALIGNMENT, + first_field_def.span, + UsesPowerAlignment, + ); + } + } + } + } + } } /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in @@ -1562,8 +1681,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { } // See `check_fn`.. hir::ItemKind::Fn { .. } => {} + // Structs are checked based on if they follow the power alignment + // rule (under repr(C)). + hir::ItemKind::Struct(..) => { + self.check_struct_for_power_alignment(cx, item); + } // See `check_field_def`.. - hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {} + hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {} // Doesn't define something that can contain a external type to be checked. hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index dd72ea2497f..35186778671 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -2,6 +2,7 @@ #include "llvm-c/Analysis.h" #include "llvm-c/Core.h" +#include "llvm-c/DebugInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -676,120 +677,73 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) { #define DIArray DINodeArray #define unwrapDI unwrapDIPtr -// These values **must** match debuginfo::DIFlags! They also *happen* -// to match LLVM, but that isn't required as we do giant sets of -// matching below. The value shouldn't be directly passed to LLVM. -enum class LLVMRustDIFlags : uint32_t { - FlagZero = 0, - FlagPrivate = 1, - FlagProtected = 2, - FlagPublic = 3, - FlagFwdDecl = (1 << 2), - FlagAppleBlock = (1 << 3), - FlagBlockByrefStruct = (1 << 4), - FlagVirtual = (1 << 5), - FlagArtificial = (1 << 6), - FlagExplicit = (1 << 7), - FlagPrototyped = (1 << 8), - FlagObjcClassComplete = (1 << 9), - FlagObjectPointer = (1 << 10), - FlagVector = (1 << 11), - FlagStaticMember = (1 << 12), - FlagLValueReference = (1 << 13), - FlagRValueReference = (1 << 14), - FlagExternalTypeRef = (1 << 15), - FlagIntroducedVirtual = (1 << 18), - FlagBitField = (1 << 19), - FlagNoReturn = (1 << 20), - // Do not add values that are not supported by the minimum LLVM - // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def -}; - -inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) & - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) | - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) { - return A = A | B; -} - -inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; } - -inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3); -} - -static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) { - DINode::DIFlags Result = DINode::DIFlags::FlagZero; - - switch (visibility(Flags)) { - case LLVMRustDIFlags::FlagPrivate: - Result |= DINode::DIFlags::FlagPrivate; - break; - case LLVMRustDIFlags::FlagProtected: - Result |= DINode::DIFlags::FlagProtected; - break; - case LLVMRustDIFlags::FlagPublic: - Result |= DINode::DIFlags::FlagPublic; - break; - default: - // The rest are handled below - break; - } - - if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) { - Result |= DINode::DIFlags::FlagFwdDecl; - } - if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) { - Result |= DINode::DIFlags::FlagAppleBlock; - } - if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) { - Result |= DINode::DIFlags::FlagVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) { - Result |= DINode::DIFlags::FlagArtificial; - } - if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) { - Result |= DINode::DIFlags::FlagExplicit; - } - if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) { - Result |= DINode::DIFlags::FlagPrototyped; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) { - Result |= DINode::DIFlags::FlagObjcClassComplete; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) { - Result |= DINode::DIFlags::FlagObjectPointer; - } - if (isSet(Flags & LLVMRustDIFlags::FlagVector)) { - Result |= DINode::DIFlags::FlagVector; - } - if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) { - Result |= DINode::DIFlags::FlagStaticMember; - } - if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) { - Result |= DINode::DIFlags::FlagLValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { - Result |= DINode::DIFlags::FlagRValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { - Result |= DINode::DIFlags::FlagIntroducedVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { - Result |= DINode::DIFlags::FlagBitField; - } - if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { - Result |= DINode::DIFlags::FlagNoReturn; - } - - return Result; +// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of +// bindings that are going to be deleted and replaced with their LLVM-C +// equivalents, as part of #134009. After that happens, the remaining bindings +// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef. +typedef LLVMDIFlags LLVMRustDIFlags; + +// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same +// layout, at least for the flags we know about. This isn't guaranteed, but is +// likely to remain true, and as long as it is true it makes conversions easy. +#define ASSERT_DIFLAG_VALUE(FLAG, VALUE) \ + static_assert((LLVMDI##FLAG == (VALUE)) && (DINode::DIFlags::FLAG == (VALUE))) +ASSERT_DIFLAG_VALUE(FlagZero, 0); +ASSERT_DIFLAG_VALUE(FlagPrivate, 1); +ASSERT_DIFLAG_VALUE(FlagProtected, 2); +ASSERT_DIFLAG_VALUE(FlagPublic, 3); +// Bit (1 << 1) is part of the private/protected/public values above. +ASSERT_DIFLAG_VALUE(FlagFwdDecl, 1 << 2); +ASSERT_DIFLAG_VALUE(FlagAppleBlock, 1 << 3); +ASSERT_DIFLAG_VALUE(FlagReservedBit4, 1 << 4); +ASSERT_DIFLAG_VALUE(FlagVirtual, 1 << 5); +ASSERT_DIFLAG_VALUE(FlagArtificial, 1 << 6); +ASSERT_DIFLAG_VALUE(FlagExplicit, 1 << 7); +ASSERT_DIFLAG_VALUE(FlagPrototyped, 1 << 8); +ASSERT_DIFLAG_VALUE(FlagObjcClassComplete, 1 << 9); +ASSERT_DIFLAG_VALUE(FlagObjectPointer, 1 << 10); +ASSERT_DIFLAG_VALUE(FlagVector, 1 << 11); +ASSERT_DIFLAG_VALUE(FlagStaticMember, 1 << 12); +ASSERT_DIFLAG_VALUE(FlagLValueReference, 1 << 13); +ASSERT_DIFLAG_VALUE(FlagRValueReference, 1 << 14); +// Bit (1 << 15) has been recycled, but the C API value hasn't been renamed. +static_assert((LLVMDIFlagReserved == (1 << 15)) && + (DINode::DIFlags::FlagExportSymbols == (1 << 15))); +ASSERT_DIFLAG_VALUE(FlagSingleInheritance, 1 << 16); +ASSERT_DIFLAG_VALUE(FlagMultipleInheritance, 2 << 16); +ASSERT_DIFLAG_VALUE(FlagVirtualInheritance, 3 << 16); +// Bit (1 << 17) is part of the inheritance values above. +ASSERT_DIFLAG_VALUE(FlagIntroducedVirtual, 1 << 18); +ASSERT_DIFLAG_VALUE(FlagBitField, 1 << 19); +ASSERT_DIFLAG_VALUE(FlagNoReturn, 1 << 20); +// Bit (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`. +ASSERT_DIFLAG_VALUE(FlagTypePassByValue, 1 << 22); +ASSERT_DIFLAG_VALUE(FlagTypePassByReference, 1 << 23); +ASSERT_DIFLAG_VALUE(FlagEnumClass, 1 << 24); +ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25); +ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26); +ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27); +ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28); +ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5)); +#undef ASSERT_DIFLAG_VALUE + +// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`: +// - Check and copy every individual bit/subvalue from input to output. +// - Statically assert that both have the same layout, and cast. +// As long as the static assertions succeed, a cast is easier and faster. +// In the (hopefully) unlikely event that the assertions do fail someday, and +// LLVM doesn't expose its own conversion function, we'll have to switch over +// to copying each bit/subvalue. +static DINode::DIFlags fromRust(LLVMDIFlags Flags) { + // Check that all set bits are covered by the static assertions above. + const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21); + if (Flags & UNKNOWN_BITS) { + report_fatal_error("bad LLVMDIFlags"); + } + + // As long as the static assertions are satisfied and no unknown bits are + // present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast. + return static_cast<DINode::DIFlags>(Flags); } // These values **must** match debuginfo::DISPFlags! They also *happen* diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5d78bed5cf8..926760b84aa 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -12,7 +12,7 @@ use rustc_hir::*; use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans}; use crate::hir::ModuleItems; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -1117,6 +1117,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { // the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`, // and combining it with other hashes here. resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher); + with_metavar_spans(|mspans| { + mspans.freeze_and_get_read_spans().hash_stable(&mut hcx, &mut stable_hasher); + }); stable_hasher.finish() }); diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index d6f8fed755f..1b07846e0cf 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -222,7 +222,7 @@ impl AllocError { } /// The information that makes up a memory access: offset and size. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub struct AllocRange { pub start: Size, pub size: Size, diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs new file mode 100644 index 00000000000..ec6e466ff68 --- /dev/null +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -0,0 +1,47 @@ +/// Helper trait that allows `arena_cache` queries to return `Option<&T>` +/// instead of `&Option<T>`, and avoid allocating `None` in the arena. +/// +/// An arena-cached query must be declared to return a type that implements +/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then +/// determines the types returned by the provider and stored in the arena, +/// and provides a function to bridge between the three types. +pub trait ArenaCached<'tcx>: Sized { + /// Type that is returned by the query provider. + type Provided; + /// Type that is stored in the arena. + type Allocated: 'tcx; + + /// Takes a provided value, and allocates it in the arena (if appropriate) + /// with the help of the given `arena_alloc` closure. + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self; +} + +impl<'tcx, T> ArenaCached<'tcx> for &'tcx T { + type Provided = T; + type Allocated = T; + + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self { + // Just allocate in the arena normally. + arena_alloc(value) + } +} + +impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> { + type Provided = Option<T>; + /// The provide value is `Option<T>`, but we only store `T` in the arena. + type Allocated = T; + + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self { + // Don't store None in the arena, and wrap the allocated reference in Some. + value.map(arena_alloc) + } +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 65e93c3a1cc..05ded71dbeb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,7 +7,6 @@ #![allow(unused_parens)] use std::mem; -use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -85,6 +84,7 @@ use crate::ty::{ }; use crate::{dep_graph, mir, thir}; +mod arena_cached; pub mod erase; mod keys; pub use keys::{AsLocalKey, Key, LocalCrate}; @@ -586,7 +586,7 @@ rustc_queries! { separate_provide_extern } - query mir_coroutine_witnesses(key: DefId) -> &'tcx Option<mir::CoroutineLayout<'tcx>> { + query mir_coroutine_witnesses(key: DefId) -> Option<&'tcx mir::CoroutineLayout<'tcx>> { arena_cache desc { |tcx| "coroutine witness types for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -2415,7 +2415,7 @@ rustc_queries! { /// because the `ty::Ty`-based wfcheck is always run. query diagnostic_hir_wf_check( key: (ty::Predicate<'tcx>, WellFormedLoc) - ) -> &'tcx Option<ObligationCause<'tcx>> { + ) -> Option<&'tcx ObligationCause<'tcx>> { arena_cache eval_always no_hash diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 2cb6f6d8c6e..1c157f33a81 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -289,10 +289,10 @@ macro_rules! define_callbacks { /// This type alias specifies the type returned from query providers and the type /// used for decoding. For regular queries this is the declared returned type `V`, - /// but `arena_cache` will use `<V as Deref>::Target` instead. + /// but `arena_cache` will use `<V as ArenaCached>::Provided` instead. pub type ProvidedValue<'tcx> = query_if_arena!( [$($modifiers)*] - (<$V as Deref>::Target) + (<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided) ($V) ); @@ -307,10 +307,18 @@ macro_rules! define_callbacks { ) -> Erase<Value<'tcx>> { erase(query_if_arena!([$($modifiers)*] { - if mem::needs_drop::<ProvidedValue<'tcx>>() { - &*_tcx.query_system.arenas.$name.alloc(value) + use $crate::query::arena_cached::ArenaCached; + + if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() { + <$V as ArenaCached>::alloc_in_arena( + |v| _tcx.query_system.arenas.$name.alloc(v), + value, + ) } else { - &*_tcx.arena.dropless.alloc(value) + <$V as ArenaCached>::alloc_in_arena( + |v| _tcx.arena.dropless.alloc(v), + value, + ) } } (value) @@ -354,7 +362,7 @@ macro_rules! define_callbacks { pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] - (TypedArena<<$V as Deref>::Target>) + (TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>) () ),)* } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index db2bb8a7248..55d78e083e0 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -345,9 +345,6 @@ pub enum ObligationCauseCode<'tcx> { /// `main` has wrong type MainFunctionType, - /// `start` has wrong type - StartFunctionType, - /// language function has wrong type LangFunctionType(Symbol), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7035e641f39..2d76f6ec7d6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -52,7 +52,9 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; +use rustc_type_ir::{ + CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, elaborate, search_graph, +}; use tracing::{debug, instrument}; use crate::arena::Arena; @@ -2558,7 +2560,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.supertrait_def_ids(trait_def_id).any(|trait_did| { + elaborate::supertrait_def_ids(self, trait_def_id).any(|trait_did| { self.associated_items(trait_did) .filter_by_name_unhygienic(assoc_name.name) .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did)) @@ -2579,14 +2581,6 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) - /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors, - /// and to make size estimates for vtable layout computation. - pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { - rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id) - } - /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 09a05104e49..23e2e8ad3d3 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -2,6 +2,7 @@ use std::fmt; use rustc_ast::Mutability; use rustc_macros::HashStable; +use rustc_type_ir::elaborate; use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; @@ -64,7 +65,7 @@ pub(crate) fn vtable_min_entries<'tcx>( }; // This includes self in supertraits. - for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) { + for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) { count += tcx.own_existential_vtable_entries(def_id).len(); } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b944d13fb0d..b21ec8f3083 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } + let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; candidate.subcandidates.retain_mut(|candidate| { if candidate.extra_data.is_never { candidate.visit_leaves(|subcandidate| { @@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }); if candidate.subcandidates.is_empty() { - // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. - candidate.pre_binding_block = Some(self.cfg.start_new_block()); + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`. + let next_block = self.cfg.start_new_block(); + candidate.pre_binding_block = Some(next_block); + candidate.otherwise_block = Some(next_block); + // In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here. + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = false_edge_start_block; + } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 66310867200..b5b7b54a1cc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1086,6 +1086,12 @@ fn find_fallback_pattern_typo<'tcx>( let vis = cx.tcx.visibility(item.owner_id); if vis.is_accessible_from(parent, cx.tcx) { accessible.push(item_name); + // FIXME: the line below from PR #135310 is a workaround for the ICE in issue + // #135289, where a macro in a dependency can create unreachable patterns in the + // current crate. Path trimming expects diagnostics for a typoed const, but no + // diagnostics are emitted and we ICE. See + // `tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs` for a + // test that reproduces the ICE if we don't use `with_no_trimmed_paths!`. let path = with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id)); accessible_path.push(path); } else if name == item_name { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index f9168112216..451c215566b 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -smallvec = "1.8.1" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 37678bfd880..8d1194ee539 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -277,23 +277,7 @@ where param_env: I::ParamEnv, ty: I::Ty, ) -> Result<I::Ty, NoSolution> { - if let ty::Alias(..) = ty.kind() { - let normalized_ty = self.next_ty_infer(); - let alias_relate_goal = Goal::new( - self.cx(), - param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - normalized_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - self.add_goal(GoalSource::Misc, alias_relate_goal); - self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ty)) - } else { - Ok(ty) - } + self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty()) } /// Normalize a const for when it is structurally matched on, or more likely @@ -308,22 +292,34 @@ where param_env: I::ParamEnv, ct: I::Const, ) -> Result<I::Const, NoSolution> { - if let ty::ConstKind::Unevaluated(..) = ct.kind() { - let normalized_ct = self.next_const_infer(); + self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const()) + } + + /// Normalize a term for when it is structurally matched on. + /// + /// This function is necessary in nearly all cases before matching on a ty/const. + /// Not doing so is likely to be incomplete and therefore unsound during coherence. + fn structurally_normalize_term( + &mut self, + param_env: I::ParamEnv, + term: I::Term, + ) -> Result<I::Term, NoSolution> { + if let Some(_) = term.to_alias_term() { + let normalized_term = self.next_term_infer_of_kind(term); let alias_relate_goal = Goal::new( self.cx(), param_env, ty::PredicateKind::AliasRelate( - ct.into(), - normalized_ct.into(), + term, + normalized_term, ty::AliasRelationDirection::Equate, ), ); self.add_goal(GoalSource::Misc, alias_relate_goal); self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ct)) + Ok(self.resolve_vars_if_possible(normalized_term)) } else { - Ok(ct) + Ok(term) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 4faa243c02a..513fc9355c8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::CanonicalResponse; use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; -use smallvec::SmallVec; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -1199,33 +1198,42 @@ where // nested requirements, over all others. This is a fix for #53123 and // prevents where-bounds from accidentally extending the lifetime of a // variable. - if candidates - .iter() - .any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))) - { - let trivial_builtin_impls: SmallVec<[_; 1]> = candidates - .iter() - .filter(|c| { - matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)) - }) - .map(|c| c.result) - .collect(); + let mut trivial_builtin_impls = candidates.iter().filter(|c| { + matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)) + }); + if let Some(candidate) = trivial_builtin_impls.next() { // There should only ever be a single trivial builtin candidate // as they would otherwise overlap. - assert_eq!(trivial_builtin_impls.len(), 1); - return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) { - Ok((response, Some(TraitGoalProvenVia::Misc))) - } else { - Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None)) - }; + assert!(trivial_builtin_impls.next().is_none()); + return Ok((candidate.result, Some(TraitGoalProvenVia::Misc))); } // If there are non-global where-bounds, prefer where-bounds // (including global ones) over everything else. let has_non_global_where_bounds = candidates.iter().any(|c| match c.source { CandidateSource::ParamEnv(idx) => { - let where_bound = goal.param_env.caller_bounds().get(idx); - where_bound.has_bound_vars() || !where_bound.is_global() + let where_bound = goal.param_env.caller_bounds().get(idx).unwrap(); + let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else { + unreachable!("expected trait-bound: {where_bound:?}"); + }; + + if trait_pred.has_bound_vars() || !trait_pred.is_global() { + return true; + } + + // We don't consider a trait-bound global if it has a projection bound. + // + // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs + // for an example where this is necessary. + for p in goal.param_env.caller_bounds().iter() { + if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() { + if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref { + return true; + } + } + } + + false } _ => false, }); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f963a424a7f..e681987ff07 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -11,18 +11,21 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] +#![feature(string_from_utf8_lossy_owned)] #![warn(unreachable_pub)] // tidy-alphabetical-end -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::Utf8Error; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Diag, FatalError, PResult}; +use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; use rustc_session::parse::ParseSess; +use rustc_span::source_map::SourceMap; use rustc_span::{FileName, SourceFile, Span}; pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION; @@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>( path: &Path, sp: Option<Span>, ) -> Result<Parser<'a>, Vec<Diag<'a>>> { - let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { - let msg = format!("couldn't read {}: {}", path.display(), e); + let sm = psess.source_map(); + let source_file = sm.load_file(path).unwrap_or_else(|e| { + let msg = format!("couldn't read `{}`: {}", path.display(), e); let mut err = psess.dcx().struct_fatal(msg); + if let Ok(contents) = std::fs::read(path) + && let Err(utf8err) = String::from_utf8(contents.clone()) + { + utf8_error( + sm, + &path.display().to_string(), + sp, + &mut err, + utf8err.utf8_error(), + &contents, + ); + } if let Some(sp) = sp { err.span(sp); } @@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>( new_parser_from_source_file(psess, source_file) } +pub fn utf8_error<E: EmissionGuarantee>( + sm: &SourceMap, + path: &str, + sp: Option<Span>, + err: &mut Diag<'_, E>, + utf8err: Utf8Error, + contents: &[u8], +) { + // The file exists, but it wasn't valid UTF-8. + let start = utf8err.valid_up_to(); + let note = format!("invalid utf-8 at byte `{start}`"); + let msg = if let Some(len) = utf8err.error_len() { + format!( + "byte{s} `{bytes}` {are} not valid utf-8", + bytes = if len == 1 { + format!("{:?}", contents[start]) + } else { + format!("{:?}", &contents[start..start + len]) + }, + s = pluralize!(len), + are = if len == 1 { "is" } else { "are" }, + ) + } else { + note.clone() + }; + let contents = String::from_utf8_lossy(contents).to_string(); + let source = sm.new_source_file(PathBuf::from(path).into(), contents); + let span = Span::with_root_ctxt( + source.normalized_byte_pos(start as u32), + source.normalized_byte_pos(start as u32), + ); + if span.is_dummy() { + err.note(note); + } else { + if sp.is_some() { + err.span_note(span, msg); + } else { + err.span(span); + err.span_label(span, msg); + } + } +} + /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing /// the initial token stream. fn new_parser_from_source_file( diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 8b6b37c0f8f..86f673c100c 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -11,7 +11,7 @@ use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; use rustc_session::parse::ParseSess; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use crate::{errors, parse_in}; @@ -164,11 +164,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the // `unsafe(`, `)` right after and right before the opening and closing // square bracket respectively. - let diag_span = if attr_item.span().can_be_used_for_suggestions() { - attr_item.span() - } else { - attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1)) - }; + let diag_span = attr_item.span(); if attr.span.at_least_rust_2024() { psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9eb335cb34c..5418f054beb 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -514,13 +514,7 @@ impl<'a> Parser<'a> { /// Consumes all whitespace characters until the first non-whitespace character fn ws(&mut self) { - while let Some(&(_, c)) = self.cur.peek() { - if c.is_whitespace() { - self.cur.next(); - } else { - break; - } - } + while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {} } /// Parses all of a string which is to be considered a "raw literal" in a @@ -545,7 +539,7 @@ impl<'a> Parser<'a> { } } } - &self.input[start..self.input.len()] + &self.input[start..] } /// Parses an `Argument` structure, or what's contained within braces inside the format string. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3ed600a717f..133d84572e6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -502,11 +502,6 @@ passes_multiple_rustc_main = .first = first `#[rustc_main]` function .additional = additional `#[rustc_main]` function -passes_multiple_start_functions = - multiple `start` functions - .label = multiple `start` functions - .previous = previous `#[start]` function here - passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, union, or trait .label = is not a struct, enum, union, or trait diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1b2b8ac5dd9..dbb87443eed 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -275,7 +275,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::lang | sym::needs_allocator | sym::default_lib_allocator - | sym::start | sym::custom_mir, .. ] => {} @@ -2655,7 +2654,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { sym::repr, sym::path, sym::automatically_derived, - sym::start, sym::rustc_main, sym::derive, sym::test, diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 4949a4316a7..22291c9282d 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -10,9 +10,7 @@ use rustc_session::RemapFileNameExt; use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe}; use rustc_span::{Span, Symbol, sym}; -use crate::errors::{ - AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr, -}; +use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr}; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -20,9 +18,6 @@ struct EntryContext<'tcx> { /// The function has the `#[rustc_main]` attribute. rustc_main_fn: Option<(LocalDefId, Span)>, - /// The function that has the attribute `#[start]` on it. - start_fn: Option<(LocalDefId, Span)>, - /// The functions that one might think are `main` but aren't, e.g. /// main functions not defined at the top level. For diagnostics. non_main_fns: Vec<Span>, @@ -40,8 +35,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { return None; } - let mut ctxt = - EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; + let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() }; for id in tcx.hir().items() { check_and_search_item(id, &mut ctxt); @@ -57,7 +51,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { - for attr in [sym::start, sym::rustc_main] { + for attr in [sym::rustc_main] { if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); } @@ -91,24 +85,11 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { }); } } - EntryPointType::Start => { - if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); - } else { - ctxt.tcx.dcx().emit_err(MultipleStartFunctions { - span: ctxt.tcx.def_span(id.owner_id), - labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()), - previous: ctxt.start_fn.unwrap().1, - }); - } - } } } fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { - if let Some((def_id, _)) = visitor.start_fn { - Some((def_id.to_def_id(), EntryFnType::Start)) - } else if let Some((local_def_id, _)) = visitor.rustc_main_fn { + if let Some((local_def_id, _)) = visitor.rustc_main_fn { let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })) } else { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c3043ac60aa..3d38b00e99f 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1314,17 +1314,6 @@ pub(crate) struct MultipleRustcMain { } #[derive(Diagnostic)] -#[diag(passes_multiple_start_functions, code = E0138)] -pub(crate) struct MultipleStartFunctions { - #[primary_span] - pub span: Span, - #[label] - pub labeled: Span, - #[label(passes_previous)] - pub previous: Span, -} - -#[derive(Diagnostic)] #[diag(passes_extern_main)] pub(crate) struct ExternMain { #[primary_span] diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 3e179c61f39..a8c2aa98cd0 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -567,7 +567,7 @@ pub fn print_query_stack<Qcx: QueryContext>( qcx: Qcx, mut current_query: Option<QueryJobId>, dcx: DiagCtxtHandle<'_>, - num_frames: Option<usize>, + limit_frames: Option<usize>, mut file: Option<std::fs::File>, ) -> usize { // Be careful relying on global state here: this code is called from @@ -584,7 +584,7 @@ pub fn print_query_stack<Qcx: QueryContext>( let Some(query_info) = query_map.get(&query) else { break; }; - if Some(count_printed) < num_frames || num_frames.is_none() { + if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation #[allow(rustc::diagnostic_outside_of_impl)] @@ -615,5 +615,5 @@ pub fn print_query_stack<Qcx: QueryContext>( if let Some(ref mut file) = file { let _ = writeln!(file, "end of query stack"); } - count_printed + count_total } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fe1eed243f..eec9e9a8515 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let self_spans = items .iter() .filter_map(|(use_tree, _)| { - if let ast::UseTreeKind::Simple(..) = use_tree.kind { - if use_tree.ident().name == kw::SelfLower { - return Some(use_tree.span); - } + if let ast::UseTreeKind::Simple(..) = use_tree.kind + && use_tree.ident().name == kw::SelfLower + { + return Some(use_tree.span); } None @@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) { - if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { - self.r.dcx().emit_err( - errors::MacroExpandedExternCrateCannotShadowExternArguments { - span: item.span, - }, - ); - // `return` is intended to discard this binding because it's an - // unregistered ambiguity error which would result in a panic - // caused by inconsistency `path_res` - // more details: https://github.com/rust-lang/rust/pull/111761 - return; - } + if let Some(entry) = self.r.extern_prelude.get(&ident) + && expansion != LocalExpnId::ROOT + && orig_name.is_some() + && !entry.is_import() + { + self.r.dcx().emit_err( + errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, + ); + // `return` is intended to discard this binding because it's an + // unregistered ambiguity error which would result in a panic + // caused by inconsistency `path_res` + // more details: https://github.com/rust-lang/rust/pull/111761 + return; } let entry = self .r @@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, }); } - if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { - if orig_name == kw::SelfLower { - self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); - } + if let ItemKind::ExternCrate(Some(orig_name)) = item.kind + && orig_name == kw::SelfLower + { + self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); } let ill_formed = |span| { self.r.dcx().emit_err(errors::BadMacroImport { span }); @@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return Some((MacroKind::Bang, item.ident, item.span)); } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(meta_item_inner) = + } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) + && let Some(meta_item_inner) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) - { - if let Some(ident) = meta_item_inner.ident() { - return Some((MacroKind::Derive, ident, ident.span)); - } - } + && let Some(ident) = meta_item_inner.ident() + { + return Some((MacroKind::Derive, ident, ident.span)); } None } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index ba217b7c88a..43e4e4d591f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -225,10 +225,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (name, span) = (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span)); - if let Some(s) = self.name_already_seen.get(&name) { - if s == &span { - return; - } + if self.name_already_seen.get(&name) == Some(&span) { + return; } let old_kind = match (ns, old_binding.module()) { @@ -380,20 +378,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion = Some(format!("self as {suggested_name}")) } ImportKind::Single { source, .. } => { - if let Some(pos) = - source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) + if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) + && pos as usize <= snippet.len() { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) { - if pos <= snippet.len() { - span = binding_span - .with_lo(binding_span.lo() + BytePos(pos as u32)) - .with_hi( - binding_span.hi() - - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), - ); - suggestion = Some(format!(" as {suggested_name}")); - } - } + span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi( + binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), + ); + suggestion = Some(format!(" as {suggested_name}")); } } ImportKind::ExternCrate { source, target, .. } => { @@ -510,13 +502,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If the first element of our path was actually resolved to an // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! - if let Some(binding) = second_binding { - if let NameBindingKind::Import { import, .. } = binding.kind { - // Careful: we still want to rewrite paths from renamed extern crates. - if let ImportKind::ExternCrate { source: None, .. } = import.kind { - return; - } - } + if let Some(binding) = second_binding + && let NameBindingKind::Import { import, .. } = binding.kind + // Careful: we still want to rewrite paths from renamed extern crates. + && let ImportKind::ExternCrate { source: None, .. } = import.kind + { + return; } let diag = BuiltinLintDiag::AbsPathWithModule(root_span); @@ -1047,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - if let Ok((Some(ext), _)) = this.resolve_macro_path( + let Ok((Some(ext), _)) = this.resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, false, false, None, - ) { - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::typo_from_name(*name, res)), - ); - } + ) else { + continue; + }; + suggestions.extend( + ext.helper_attrs + .iter() + .map(|name| TypoSuggestion::typo_from_name(*name, res)), + ); } } } @@ -1215,12 +1207,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let NameBindingKind::Import { binding, .. } = name_binding.kind { - if this.is_accessible_from(binding.vis, parent_scope.module) - && !this.is_accessible_from(name_binding.vis, parent_scope.module) - { - return; - } + if let NameBindingKind::Import { binding, .. } = name_binding.kind + && this.is_accessible_from(binding.vis, parent_scope.module) + && !this.is_accessible_from(name_binding.vis, parent_scope.module) + { + return; } let res = name_binding.res(); @@ -1253,14 +1244,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; - if child_accessible { + if child_accessible // Remove invisible match if exists - if let Some(idx) = candidates + && let Some(idx) = candidates .iter() .position(|v: &ImportSuggestion| v.did == did && !v.accessible) - { - candidates.remove(idx); - } + { + candidates.remove(idx); } if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { @@ -1373,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // otherwise cause duplicate suggestions. continue; } - let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)); - if let Some(crate_id) = crate_id { - let crate_def_id = crate_id.as_def_id(); - let crate_root = self.expect_module(crate_def_id); - - // Check if there's already an item in scope with the same name as the crate. - // If so, we have to disambiguate the potential import suggestions by making - // the paths *global* (i.e., by prefixing them with `::`). - let needs_disambiguation = - self.resolutions(parent_scope.module).borrow().iter().any( - |(key, name_resolution)| { - if key.ns == TypeNS - && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding - { - match binding.res() { - // No disambiguation needed if the identically named item we - // found in scope actually refers to the crate in question. - Res::Def(_, def_id) => def_id != crate_def_id, - Res::PrimTy(_) => true, - _ => false, - } - } else { - false - } - }, - ); - let mut crate_path = ThinVec::new(); - if needs_disambiguation { - crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); - } - crate_path.push(ast::PathSegment::from_ident(ident)); + let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)) + else { + continue; + }; - suggestions.extend(self.lookup_import_candidates_from_module( - lookup_ident, - namespace, - parent_scope, - crate_root, - crate_path, - &filter_fn, - )); + let crate_def_id = crate_id.as_def_id(); + let crate_root = self.expect_module(crate_def_id); + + // Check if there's already an item in scope with the same name as the crate. + // If so, we have to disambiguate the potential import suggestions by making + // the paths *global* (i.e., by prefixing them with `::`). + let needs_disambiguation = + self.resolutions(parent_scope.module).borrow().iter().any( + |(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == ident + && let Some(binding) = name_resolution.borrow().binding + { + match binding.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, + } + } else { + false + } + }, + ); + let mut crate_path = ThinVec::new(); + if needs_disambiguation { + crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } + crate_path.push(ast::PathSegment::from_ident(ident)); + + suggestions.extend(self.lookup_import_candidates_from_module( + lookup_ident, + namespace, + parent_scope, + crate_root, + crate_path, + &filter_fn, + )); } } @@ -1511,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1519,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, None, None, - ) { - let desc = match binding.res() { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - "a function-like macro".to_string() - } - Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { - format!("an attribute: `#[{ident}]`") - } - Res::Def(DefKind::Macro(MacroKind::Derive), _) => { - format!("a derive macro: `#[derive({ident})]`") - } - Res::ToolMod => { - // Don't confuse the user with tool modules. - continue; - } - Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { - "only a trait, without a derive macro".to_string() - } - res => format!( - "{} {}, not {} {}", - res.article(), - res.descr(), - macro_kind.article(), - macro_kind.descr_expected(), - ), - }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind { - if !import.span.is_dummy() { - let note = errors::IdentImporterHereButItIsDesc { - span: import.span, - imported_ident: ident, - imported_ident_desc: &desc, - }; - err.subdiagnostic(note); - // Silence the 'unused import' warning we might get, - // since this diagnostic already covers that import. - self.record_use(ident, binding, Used::Other); - return; - } + ) else { + continue; + }; + + let desc = match binding.res() { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(), + Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { + format!("an attribute: `#[{ident}]`") + } + Res::Def(DefKind::Macro(MacroKind::Derive), _) => { + format!("a derive macro: `#[derive({ident})]`") + } + Res::ToolMod => { + // Don't confuse the user with tool modules. + continue; + } + Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { + "only a trait, without a derive macro".to_string() } - let note = errors::IdentInScopeButItIsDesc { + res => format!( + "{} {}, not {} {}", + res.article(), + res.descr(), + macro_kind.article(), + macro_kind.descr_expected(), + ), + }; + if let crate::NameBindingKind::Import { import, .. } = binding.kind + && !import.span.is_dummy() + { + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, imported_ident: ident, imported_ident_desc: &desc, }; err.subdiagnostic(note); + // Silence the 'unused import' warning we might get, + // since this diagnostic already covers that import. + self.record_use(ident, binding, Used::Other); return; } + let note = errors::IdentInScopeButItIsDesc { + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(note); + return; } } @@ -1749,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> { - if let NameBindingKind::Res(Res::Def( + let NameBindingKind::Res(Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id, )) = binding.kind - { - let def_id = self.tcx.parent(ctor_def_id); - return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()` - } - None + else { + return None; + }; + + let def_id = self.tcx.parent(ctor_def_id); + self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()` } fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { @@ -1983,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::<Vec<_>>(); candidates.sort(); candidates.dedup(); - match find_best_match_for_name(&candidates, ident, None) { - Some(sugg) if sugg == ident => None, - sugg => sugg, - } + find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident) } pub(crate) fn report_path_resolution_error( @@ -2410,115 +2400,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let binding_key = BindingKey::new(ident, MacroNS); let resolution = resolutions.get(&binding_key)?; let binding = resolution.borrow().binding()?; - if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { - let module_name = crate_module.kind.name().unwrap(); - let import_snippet = match import.kind { - ImportKind::Single { source, target, .. } if source != target => { - format!("{source} as {target}") - } - _ => format!("{ident}"), - }; + let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { + return None; + }; + let module_name = crate_module.kind.name().unwrap(); + let import_snippet = match import.kind { + ImportKind::Single { source, target, .. } if source != target => { + format!("{source} as {target}") + } + _ => format!("{ident}"), + }; - let mut corrections: Vec<(Span, String)> = Vec::new(); - if !import.is_nested() { - // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove - // intermediate segments. - corrections.push((import.span, format!("{module_name}::{import_snippet}"))); - } else { - // Find the binding span (and any trailing commas and spaces). - // ie. `use a::b::{c, d, e};` - // ^^^ - let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( - self.tcx.sess, - import.span, - import.use_span, - ); - debug!(found_closing_brace, ?binding_span); - - let mut removal_span = binding_span; - if found_closing_brace { - // If the binding span ended with a closing brace, as in the below example: - // ie. `use a::b::{c, d};` - // ^ - // Then expand the span of characters to remove to include the previous - // binding's trailing comma. - // ie. `use a::b::{c, d};` - // ^^^ - if let Some(previous_span) = - extend_span_to_previous_binding(self.tcx.sess, binding_span) - { - debug!(?previous_span); - removal_span = removal_span.with_lo(previous_span.lo()); - } - } - debug!(?removal_span); - - // Remove the `removal_span`. - corrections.push((removal_span, "".to_string())); - - // Find the span after the crate name and if it has nested imports immediately - // after the crate name already. - // ie. `use a::b::{c, d};` - // ^^^^^^^^^ - // or `use a::{b, c, d}};` - // ^^^^^^^^^^^ - let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( - self.tcx.sess, - module_name, - import.use_span, - ); - debug!(has_nested, ?after_crate_name); + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !import.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((import.span, format!("{module_name}::{import_snippet}"))); + } else { + // Find the binding span (and any trailing commas and spaces). + // ie. `use a::b::{c, d, e};` + // ^^^ + let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( + self.tcx.sess, + import.span, + import.use_span, + ); + debug!(found_closing_brace, ?binding_span); + + let mut removal_span = binding_span; + + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if found_closing_brace + && let Some(previous_span) = + extend_span_to_previous_binding(self.tcx.sess, binding_span) + { + debug!(?previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); + } + debug!(?removal_span); - let source_map = self.tcx.sess.source_map(); + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); - // Make sure this is actually crate-relative. - let is_definitely_crate = import - .module_path - .first() - .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + // Find the span after the crate name and if it has nested imports immediately + // after the crate name already. + // ie. `use a::b::{c, d};` + // ^^^^^^^^^ + // or `use a::{b, c, d}};` + // ^^^^^^^^^^^ + let (has_nested, after_crate_name) = + find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span); + debug!(has_nested, ?after_crate_name); - // Add the import to the start, with a `{` if required. - let start_point = source_map.start_point(after_crate_name); - if is_definitely_crate - && let Ok(start_snippet) = source_map.span_to_snippet(start_point) - { - corrections.push(( - start_point, - if has_nested { - // In this case, `start_snippet` must equal '{'. - format!("{start_snippet}{import_snippet}, ") - } else { - // In this case, add a `{`, then the moved import, then whatever - // was there before. - format!("{{{import_snippet}, {start_snippet}") - }, - )); + let source_map = self.tcx.sess.source_map(); - // Add a `};` to the end if nested, matching the `{` added at the start. - if !has_nested { - corrections - .push((source_map.end_point(after_crate_name), "};".to_string())); - } - } else { - // If the root import is module-relative, add the import separately - corrections.push(( - import.use_span.shrink_to_lo(), - format!("use {module_name}::{import_snippet};\n"), - )); + // Make sure this is actually crate-relative. + let is_definitely_crate = import + .module_path + .first() + .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if is_definitely_crate + && let Ok(start_snippet) = source_map.span_to_snippet(start_point) + { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{start_snippet}{import_snippet}, ") + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{import_snippet}, {start_snippet}") + }, + )); + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), "};".to_string())); } + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + import.use_span.shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } + } - let suggestion = Some(( - corrections, - String::from("a macro with this name exists at the root of the crate"), - Applicability::MaybeIncorrect, - )); - Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \ + let suggestion = Some(( + corrections, + String::from("a macro with this name exists at the root of the crate"), + Applicability::MaybeIncorrect, + )); + Some(( + suggestion, + Some( + "this could be because a macro annotated with `#[macro_export]` will be exported \ at the root of the crate instead of the module where it is defined" - .to_string()))) - } else { - None - } + .to_string(), + ), + )) } /// Finds a cfg-ed out item inside `module` with the matching name. @@ -3042,7 +3032,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(&c.items); - return; } else { visit::walk_crate(self, c); } @@ -3056,7 +3045,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(items); - return; } } else { visit::walk_item(self, item); @@ -3066,16 +3054,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { for item in items { - if let ItemKind::Use(..) = item.kind { - if is_span_suitable_for_use_injection(item.span) { - let mut lo = item.span.lo(); - for attr in &item.attrs { - if attr.span.eq_ctxt(item.span) { - lo = std::cmp::min(lo, attr.span.lo()); - } + if let ItemKind::Use(..) = item.kind + && is_span_suitable_for_use_injection(item.span) + { + let mut lo = item.span.lo(); + for attr in &item.attrs { + if attr.span.eq_ctxt(item.span) { + lo = std::cmp::min(lo, attr.span.lo()); } - return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } + return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } } None diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index e279d14704e..6ef4aa40725 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() { - // 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. - // - // If the binding is ambiguous, 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 this way `is_ambiguity` returns true. - let is_ambiguity = - |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; - let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = binding.warn_ambiguity; - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - self.update_import(binding, parent_id); + let Some(mut binding) = name_resolution.borrow().binding() else { + continue; + }; + // 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. + // + // If the binding is ambiguous, 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 this way `is_ambiguity` returns true. + let is_ambiguity = + |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + let mut parent_id = ParentId::Def(module_id); + let mut warn_ambiguity = binding.warn_ambiguity; + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + self.update_import(binding, parent_id); - if is_ambiguity(binding, warn_ambiguity) { - // 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); - binding = nested_binding; - warn_ambiguity |= nested_binding.warn_ambiguity; - } - if !is_ambiguity(binding, warn_ambiguity) - && 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 is_ambiguity(binding, warn_ambiguity) { + // 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); + binding = nested_binding; + warn_ambiguity |= nested_binding.warn_ambiguity; + } + if !is_ambiguity(binding, warn_ambiguity) + && 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); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 45e87edc53e..a3d3e87ade0 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // ---- end // ``` // So we have to fall back to the module's parent during lexical resolution in this case. - if derive_fallback_lint_id.is_some() { - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = &self.get_macro_by_def_id(def_id).ext; - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - return Some((parent, derive_fallback_lint_id)); - } - } - } + if derive_fallback_lint_id.is_some() + && let Some(parent) = module.parent + // Inner module is inside the macro + && module.expansion != parent.expansion + // Parent module is outside of the macro + && module.expansion.is_descendant_of(parent.expansion) + // The macro is a proc macro derive + && let Some(def_id) = module.expansion.expn_data().macro_def_id + { + let ext = &self.get_macro_by_def_id(def_id).ext; + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); } } @@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); - if let Some(prelude) = this.prelude { - if let Ok(binding) = this.resolve_ident_in_module_unadjusted( + if let Some(prelude) = this.prelude + && let Ok(binding) = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ignore_binding, ignore_import, - ) { - if matches!(use_prelude, UsePrelude::Yes) - || this.is_builtin_macro(binding.res()) - { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); - } - } + ) + && (matches!(use_prelude, UsePrelude::Yes) + || this.is_builtin_macro(binding.res())) + { + result = Ok((binding, Flags::MISC_FROM_PRELUDE)); } + result } Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { @@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = binding { - if !binding.is_glob_import() { - return check_usable(self, binding); - } + if let Some(binding) = binding + && !binding.is_glob_import() + { + return check_usable(self, binding); } // --- From now on we either have a glob resolution or no resolution. --- @@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() { - if let Some(id) = id { - if !this.partial_res_map.contains_key(&id) { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - } + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.record_partial_res(id, PartialRes::new(res)); } }; @@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, }, }; - if let Some(self_module) = self_module { - if let Some(parent) = self_module.parent { - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent), - )); - continue; - } + if let Some(self_module) = self_module + && let Some(parent) = self_module.parent + { + module = + Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent))); + continue; } return PathResult::failed( ident, @@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { - if let Some(ModuleOrUniformRoot::Module(module)) = module { - if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PartialRes::with_unresolved_segments( - module.res().unwrap(), - path.len() - segment_idx, - )); - } + if let Some(ModuleOrUniformRoot::Module(module)) = module + && opt_ns.is_some() + && !module.is_normal() + { + return PathResult::NonModule(PartialRes::with_unresolved_segments( + module.res().unwrap(), + path.len() - segment_idx, + )); } return PathResult::failed( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 29b4d913c82..d555c938770 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding.vis }; - if let ImportKind::Glob { ref max_vis, .. } = import.kind { - if vis == import_vis - || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)) - { - max_vis.set(Some(vis.expect_local())) - } + if let ImportKind::Glob { ref max_vis, .. } = import.kind + && (vis == import_vis + || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) + { + max_vis.set(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -543,31 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(*import, is_indeterminate); - if let Some(err) = unresolved_import_error { - glob_error |= import.is_glob(); + let Some(err) = unresolved_import_error else { continue }; - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { - if source.name == kw::SelfLower { - // Silence `unresolved import` error if E0429 is already emitted - if let Err(Determined) = source_bindings.value_ns.get() { - continue; - } - } - } + glob_error |= import.is_glob(); - if prev_root_id != NodeId::ZERO - && prev_root_id != import.root_id - && !errors.is_empty() - { - // In the case of a new import line, throw a diagnostic message - // for the previous line. - self.throw_unresolved_import_error(errors, glob_error); - errors = vec![]; - } - if seen_spans.insert(err.span) { - errors.push((*import, err)); - prev_root_id = import.root_id; - } + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + && source.name == kw::SelfLower + // Silence `unresolved import` error if E0429 is already emitted + && let Err(Determined) = source_bindings.value_ns.get() + { + continue; + } + + if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty() + { + // In the case of a new import line, throw a diagnostic message + // for the previous line. + self.throw_unresolved_import_error(errors, glob_error); + errors = vec![]; + } + if seen_spans.insert(err.span) { + errors.push((*import, err)); + prev_root_id = import.root_id; } } @@ -609,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding { - if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity - && binding.res() != Res::Err - && exported_ambiguities.contains(&binding) + let Some(binding) = resolution.binding else { continue }; + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&binding) + { + self.lint_buffer.buffer_lint( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + BuiltinLintDiag::AmbiguousGlobReexports { + name: key.ident.to_string(), + namespace: key.ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + + if let Some(glob_binding) = resolution.shadowed_glob { + let binding_id = match binding.kind { + NameBindingKind::Res(res) => { + Some(self.def_id_to_node_id[res.def_id().expect_local()]) + } + NameBindingKind::Module(module) => { + Some(self.def_id_to_node_id[module.def_id().expect_local()]) + } + NameBindingKind::Import { import, .. } => import.id(), + }; + + if binding.res() != Res::Err + && glob_binding.res() != Res::Err + && let NameBindingKind::Import { import: glob_import, .. } = + glob_binding.kind + && let Some(binding_id) = binding_id + && let Some(glob_import_id) = glob_import.id() + && let glob_import_def_id = self.local_def_id(glob_import_id) + && self.effective_visibilities.is_exported(glob_import_def_id) + && glob_binding.vis.is_public() + && !binding.vis.is_public() { self.lint_buffer.buffer_lint( - AMBIGUOUS_GLOB_REEXPORTS, - import.root_id, - import.root_span, - BuiltinLintDiag::AmbiguousGlobReexports { - name: key.ident.to_string(), - namespace: key.ns.descr().to_string(), - first_reexport_span: import.root_span, - duplicate_reexport_span: amb_binding.span, + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + BuiltinLintDiag::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, }, ); } - - if let Some(glob_binding) = resolution.shadowed_glob { - let binding_id = match binding.kind { - NameBindingKind::Res(res) => { - Some(self.def_id_to_node_id[res.def_id().expect_local()]) - } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id[module.def_id().expect_local()]) - } - NameBindingKind::Import { import, .. } => import.id(), - }; - - if binding.res() != Res::Err - && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = - glob_binding.kind - && let Some(binding_id) = binding_id - && let Some(glob_import_id) = glob_import.id() - && let glob_import_def_id = self.local_def_id(glob_import_id) - && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_binding.vis.is_public() - && !binding.vis.is_public() - { - self.lint_buffer.buffer_lint( - HIDDEN_GLOB_REEXPORTS, - binding_id, - binding.span, - BuiltinLintDiag::HiddenGlobReexports { - name: key.ident.name.to_string(), - namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, - private_item_span: binding.span, - }, - ); - } - } } } } @@ -1006,21 +1002,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } - if let ModuleOrUniformRoot::Module(module) = module { - if module == import.parent_scope.module { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from( - "cannot glob-import a module into itself", - )), - note: None, - suggestion: None, - candidates: None, - segment: None, - module: None, - }); - } + if let ModuleOrUniformRoot::Module(module) = module + && module == import.parent_scope.module + { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }); } if !is_prelude && let Some(max_vis) = max_vis.get() @@ -1081,18 +1075,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Consistency checks, analogous to `finalize_macro_resolutions`. let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; - if let Some(target_binding) = target_bindings[ns].get() { - if target.name == kw::Underscore - && initial_binding.is_extern_crate() - && !initial_binding.is_import() - { - let used = if import.module_path.is_empty() { - Used::Scope - } else { - Used::Other - }; - this.record_use(ident, target_binding, used); - } + if let Some(target_binding) = target_bindings[ns].get() + && target.name == kw::Underscore + && initial_binding.is_extern_crate() + && !initial_binding.is_import() + { + let used = if import.module_path.is_empty() { + Used::Scope + } else { + Used::Other + }; + this.record_use(ident, target_binding, used); } initial_binding.res() }); @@ -1247,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { - if !binding.vis.is_at_least(import.vis, this.tcx) { - reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis { - if binding_def_id.is_top_level_module() { - crate_private_reexport = true; - } - } - } else { - any_successful_reexport = true; + let Ok(binding) = source_bindings[ns].get() else { + return; + }; + + if !binding.vis.is_at_least(import.vis, this.tcx) { + reexport_error = Some((ns, binding)); + if let ty::Visibility::Restricted(binding_def_id) = binding.vis + && binding_def_id.is_top_level_module() + { + crate_private_reexport = true; } + } else { + any_successful_reexport = true; } }); @@ -1474,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); - if let Some(def_id) = module.opt_def_id() { - let mut children = Vec::new(); - - module.for_each_child(self, |this, ident, _, binding| { - let res = binding.res().expect_non_local(); - let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; - if res != def::Res::Err && !error_ambiguity { - let mut reexport_chain = SmallVec::new(); - let mut next_binding = binding; - while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { - reexport_chain.push(import.simplify(this)); - next_binding = binding; - } + let Some(def_id) = module.opt_def_id() else { return }; + + let mut children = Vec::new(); - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + module.for_each_child(self, |this, ident, _, binding| { + let res = binding.res().expect_non_local(); + let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; + if res != def::Res::Err && !error_ambiguity { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = binding; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(this)); + next_binding = binding; } - }); - if !children.is_empty() { - // Should be fine because this code is only called for local modules. - self.module_children.insert(def_id.expect_local(), children); + children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); } + }); + + if !children.is_empty() { + // Should be fine because this code is only called for local modules. + self.module_children.insert(def_id.expect_local(), children); } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bbcbb5d1ce4..8bd40ed3a73 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -468,16 +468,12 @@ impl<'a> PathSource<'a> { { "external crate" } - ExprKind::Path(_, path) => { - let mut msg = "function"; - if let Some(segment) = path.segments.iter().last() { - if let Some(c) = segment.ident.to_string().chars().next() { - if c.is_uppercase() { - msg = "function, tuple struct or tuple variant"; - } - } - } - msg + ExprKind::Path(_, path) + if let Some(segment) = path.segments.last() + && let Some(c) = segment.ident.to_string().chars().next() + && c.is_uppercase() => + { + "function, tuple struct or tuple variant" } _ => "function", }, @@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r // namespace first, and if that fails we try again in the value namespace. If // resolution in the value namespace succeeds, we have an generic const argument on // our hands. - if let TyKind::Path(None, ref path) = ty.kind { + if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - if path.is_potential_trivial_const_arg() { - let mut check_ns = |ns| { - self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) - .is_some() - }; - if !check_ns(TypeNS) && check_ns(ValueNS) { - self.resolve_anon_const_manual( - true, - AnonConstKind::ConstArg(IsRepeatExpr::No), - |this| { - this.smart_resolve_path( - ty.id, - &None, - path, - PathSource::Expr(None), - ); - this.visit_path(path, ty.id); - }, - ); + && path.is_potential_trivial_const_arg() + { + let mut check_ns = |ns| { + self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) + .is_some() + }; + if !check_ns(TypeNS) && check_ns(ValueNS) { + self.resolve_anon_const_manual( + true, + AnonConstKind::ConstArg(IsRepeatExpr::No), + |this| { + this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None)); + this.visit_path(path, ty.id); + }, + ); - self.diag_metadata.currently_processing_generic_args = prev; - return; - } + self.diag_metadata.currently_processing_generic_args = prev; + return; } } @@ -1243,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - if let Some(ref args) = path_segment.args { - match &**args { - GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), - GenericArgs::Parenthesized(p_args) => { - // Probe the lifetime ribs to know how to behave. - for rib in self.lifetime_ribs.iter().rev() { - match rib.kind { - // We are inside a `PolyTraitRef`. The lifetimes are - // to be introduced in that (maybe implicit) `for<>` binder. - LifetimeRibKind::Generics { - binder, - kind: LifetimeBinderKind::PolyTrait, - .. - } => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { + let Some(ref args) = path_segment.args else { + return; + }; + + match &**args { + GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), + GenericArgs::Parenthesized(p_args) => { + // Probe the lifetime ribs to know how to behave. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // We are inside a `PolyTraitRef`. The lifetimes are + // to be introduced in that (maybe implicit) `for<>` binder. + LifetimeRibKind::Generics { + binder, + kind: LifetimeBinderKind::PolyTrait, + .. + } => { + self.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter { + binder, + report_in_path: false, + }, + |this| { + this.resolve_fn_signature( binder, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - binder, - false, - p_args.inputs.iter().map(|ty| (None, &**ty)), - &p_args.output, - ) - }, - ); - break; - } - // We have nowhere to introduce generics. Code is malformed, - // so use regular lifetime resolution to avoid spurious errors. - LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { - visit::walk_generic_args(self, args); - break; - } - LifetimeRibKind::AnonymousCreateParameter { .. } - | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } - | LifetimeRibKind::Elided(_) - | LifetimeRibKind::ElisionFailure - | LifetimeRibKind::ConcreteAnonConst(_) - | LifetimeRibKind::ConstParamTy => {} + false, + p_args.inputs.iter().map(|ty| (None, &**ty)), + &p_args.output, + ) + }, + ); + break; + } + // We have nowhere to introduce generics. Code is malformed, + // so use regular lifetime resolution to avoid spurious errors. + LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { + visit::walk_generic_args(self, args); + break; } + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::ElisionFailure + | LifetimeRibKind::ConcreteAnonConst(_) + | LifetimeRibKind::ConstParamTy => {} } } - GenericArgs::ParenthesizedElided(_) => {} } + GenericArgs::ParenthesizedElided(_) => {} } } @@ -1735,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } let normalized_ident = ident.normalize_to_macros_2_0(); - let mut outer_res = None; - for rib in lifetime_rib_iter { - if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { - outer_res = Some(outer); - break; - } - } + let outer_res = lifetime_rib_iter + .find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer)); self.emit_undeclared_lifetime_error(lifetime, outer_res); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); @@ -1808,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::AnonymousReportError => { if elided { - let mut suggestion = None; - for rib in self.lifetime_ribs[i..].iter().rev() { + let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| { if let LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, .. - } = &rib.kind + } = rib.kind { - suggestion = - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { - lo: span.shrink_to_lo(), - hi: lifetime.ident.span.shrink_to_hi(), - }); - break; + Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }) + } else { + None } - } - + }); // are we trying to use an anonymous lifetime // on a non GAT associated trait type? if !self.in_func_body @@ -2460,12 +2446,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for i in (0..self.label_ribs.len()).rev() { let rib = &self.label_ribs[i]; - if let RibKind::MacroDefinition(def) = rib.kind { + if let RibKind::MacroDefinition(def) = rib.kind // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - if def == self.r.macro_def(label.span.ctxt()) { - label.span.remove_mark(); - } + && def == self.r.macro_def(label.span.ctxt()) + { + label.span.remove_mark(); } let ident = label.normalize_to_macro_rules(); @@ -2493,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Determine whether or not a label from the `rib_index`th label rib is reachable. fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { let ribs = &self.label_ribs[rib_index + 1..]; - - for rib in ribs { - if rib.kind.is_label_barrier() { - return false; - } - } - - true + ribs.iter().all(|rib| !rib.kind.is_label_barrier()) } fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { @@ -3505,21 +3484,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_ty(&qself.ty); } self.visit_path(&delegation.path, delegation.id); - if let Some(body) = &delegation.body { - self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { - // `PatBoundCtx` is not necessary in this context - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - - let span = delegation.path.segments.last().unwrap().ident.span; - this.fresh_binding( - Ident::new(kw::SelfLower, span), - delegation.id, - PatternSource::FnParam, - &mut bindings, - ); - this.visit_block(body); - }); - } + let Some(body) = &delegation.body else { return }; + self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + + let span = delegation.path.segments.last().unwrap().ident.span; + this.fresh_binding( + Ident::new(kw::SelfLower, span), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + this.visit_block(body); + }); } fn resolve_params(&mut self, params: &'ast [Param]) { diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index e9983699609..b9c535df4bd 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -31,7 +31,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3d2042952b3..97bd2670aa6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1268,7 +1268,6 @@ pub enum EntryFnType { /// and an `include!()`. sigpipe: u8, }, - Start, } #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] @@ -1346,8 +1345,12 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { user_cfg } -pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target { - match Target::search(&opts.target_triple, sysroot) { +pub fn build_target_config( + early_dcx: &EarlyDiagCtxt, + target: &TargetTuple, + sysroot: &Path, +) -> Target { + match Target::search(target, sysroot) { Ok((target, warnings)) => { for warning in warnings.warning_messages() { early_dcx.early_warn(warning) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4be013fd6fd..ec83761da4a 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -145,7 +145,7 @@ fn current_dll_path() -> Result<PathBuf, String> { .map_err(|e| e.to_string())?; let mut filename = vec![0; 1024]; - let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize; + let n = unsafe { GetModuleFileNameW(Some(module), &mut filename) } as usize; if n == 0 { return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error())); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 60f1154dc6d..10f1ce376ef 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -189,7 +189,7 @@ pub struct Session { /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with /// internal features are wontfix, and they are usually the cause of the ICEs. /// None signifies that this is not tracked. - pub using_internal_features: Arc<AtomicBool>, + pub using_internal_features: &'static AtomicBool, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -966,7 +966,7 @@ pub fn build_session( sysroot: PathBuf, cfg_version: &'static str, ice_file: Option<PathBuf>, - using_internal_features: Arc<AtomicBool>, + using_internal_features: &'static AtomicBool, expanded_args: Vec<String>, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index dc63ea1999e..ad38ea228bf 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -316,7 +316,7 @@ macro_rules! optional { #[doc(hidden)] macro_rules! run_driver { ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ - use rustc_driver::{Callbacks, Compilation, RunCompiler}; + use rustc_driver::{Callbacks, Compilation, run_compiler}; use rustc_middle::ty::TyCtxt; use rustc_interface::interface; use stable_mir::CompilerError; @@ -347,7 +347,7 @@ macro_rules! run_driver { /// Runs the compiler against given target and tests it with `test_function` pub fn run(&mut self) -> Result<C, CompilerError<B>> { let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { - RunCompiler::new(&self.args.clone(), self).run(); + run_compiler(&self.args.clone(), self); Ok(()) }); match (compiler_result, self.result.take()) { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f932d3c8073..51d809bd65d 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -25,6 +25,7 @@ #![feature(hash_set_entry)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(map_try_insert)] #![feature(negative_impls)] #![feature(read_buf)] #![feature(round_char_boundary)] @@ -85,9 +86,9 @@ use std::str::FromStr; use std::{fmt, iter}; use md5::{Digest, Md5}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher}; use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc}; +use rustc_data_structures::unord::UnordMap; use sha1::Sha1; use sha2::Sha256; @@ -103,7 +104,7 @@ pub struct SessionGlobals { span_interner: Lock<span_encoding::SpanInterner>, /// Maps a macro argument token into use of the corresponding metavariable in the macro body. /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis. - metavar_spans: Lock<FxHashMap<Span, Span>>, + metavar_spans: MetavarSpansMap, hygiene_data: Lock<hygiene::HygieneData>, /// The session's source map, if there is one. This field should only be @@ -177,9 +178,42 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R { // deserialization. scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals); +#[derive(Default)] +pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>); + +impl MetavarSpansMap { + pub fn insert(&self, span: Span, var_span: Span) -> bool { + match self.0.write().try_insert(span, (var_span, false)) { + Ok(_) => true, + Err(entry) => entry.entry.get().0 == var_span, + } + } + + /// Read a span and record that it was read. + pub fn get(&self, span: Span) -> Option<Span> { + if let Some(mut mspans) = self.0.try_write() { + if let Some((var_span, read)) = mspans.get_mut(&span) { + *read = true; + Some(*var_span) + } else { + None + } + } else { + if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None } + } + } + + /// Freeze the set, and return the spans which have been read. + /// + /// After this is frozen, no spans that have not been read can be read. + pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> { + self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect() + } +} + #[inline] -pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R { - with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock())) +pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { + with_session_globals(|session_globals| f(&session_globals.metavar_spans)) } // FIXME: We should use this enum or something like it to get rid of the @@ -872,8 +906,7 @@ impl Span { /// Check if you can select metavar spans for the given spans to get matching contexts. fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) { - let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied(); - match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) { + match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) { (None, None) => {} (Some(meta_a), None) => { let meta_a = meta_a.data(); diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 3a71592cbe0..92c1f6e7148 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -58,8 +58,10 @@ where // The AIX ABI expect byval for aggregates // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp. + // The incoming parameter is represented as a pointer in the IR, + // the alignment is associated with the size of the register. (align 8 for 64bit) if !is_ret && abi == AIX { - arg.pass_by_stack_offset(None); + arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap())); return; } diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index e975102e238..d8b6ae8cf32 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions { emit_debug_gdb_scripts: false, requires_uwtable: true, eh_frame_header: false, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 4f370ec8bd0..86e52117dbf 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions { has_thread_local: true, crt_static_allows_dylibs: true, crt_static_respected: true, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1f2df7f0168..37564ab38fc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1853,6 +1853,8 @@ supported_targets! { ("armv7a-none-eabi", armv7a_none_eabi), ("armv7a-none-eabihf", armv7a_none_eabihf), + ("armv7a-nuttx-eabi", armv7a_nuttx_eabi), + ("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf), ("msp430-none-elf", msp430_none_elf), @@ -1896,6 +1898,7 @@ supported_targets! { ("aarch64-unknown-none", aarch64_unknown_none), ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat), + ("aarch64-unknown-nuttx", aarch64_unknown_nuttx), ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx), @@ -1971,6 +1974,8 @@ supported_targets! { ("x86_64-unknown-linux-none", x86_64_unknown_linux_none), ("thumbv6m-nuttx-eabi", thumbv6m_nuttx_eabi), + ("thumbv7a-nuttx-eabi", thumbv7a_nuttx_eabi), + ("thumbv7a-nuttx-eabihf", thumbv7a_nuttx_eabihf), ("thumbv7m-nuttx-eabi", thumbv7m_nuttx_eabi), ("thumbv7em-nuttx-eabi", thumbv7em_nuttx_eabi), ("thumbv7em-nuttx-eabihf", thumbv7em_nuttx_eabihf), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs new file mode 100644 index 00000000000..04fd3ec1c26 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs @@ -0,0 +1,46 @@ +// Generic AArch64 target for NuttX OS +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a53`. + +use crate::spec::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target, + TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + // Enable the Cortex-A53 errata 843419 mitigation by default + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[ + "--fix-cortex-a53-843419", + ]), + features: "+v8a,+strict-align,+neon,+fp-armv8".into(), + supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + stack_probes: StackProbeType::Inline, + panic_strategy: PanicStrategy::Abort, + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "aarch64-unknown-none".into(), + metadata: crate::spec::TargetMetadata { + description: Some("AArch64 NuttX".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: "aarch64".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs new file mode 100644 index 00000000000..138716e8f14 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs @@ -0,0 +1,41 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX +// +// This target assumes that the device does NOT have a FPU (Floating Point Unit) +// and will use software floating point operations. This matches the NuttX EABI +// configuration without hardware floating point support. + +use crate::spec::{ + Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: "eabi".into(), + llvm_floatabi: Some(FloatAbi::Soft), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "armv7a-none-eabi".into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARMv7-A Cortex-A with NuttX".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs new file mode 100644 index 00000000000..40391c9f48e --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs @@ -0,0 +1,41 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX with hardware floating point +// +// This target assumes that the device has a FPU (Floating Point Unit) +// and will use hardware floating point operations. This matches the NuttX EABI +// configuration with hardware floating point support. + +use crate::spec::{ + Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: "eabihf".into(), + llvm_floatabi: Some(FloatAbi::Hard), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v7,+thumb2,+vfp3,+neon,+strict-align".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "armv7a-none-eabihf".into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARMv7-A Cortex-A with NuttX (hard float)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs new file mode 100644 index 00000000000..7fd22602e56 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs @@ -0,0 +1,33 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) +// +// This target assumes that the device does NOT have a FPU (Floating Point Unit) +// and will use software floating point operations. This matches the NuttX EABI +// configuration without hardware floating point support. + +use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "thumbv7a-none-eabi".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "nuttx".into(), + abi: "eabi".into(), + llvm_floatabi: Some(FloatAbi::Soft), + // Cortex-A7/A8/A9 with software floating point + features: "+soft-float,-neon".into(), + max_atomic_width: Some(64), + ..base::thumb::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs new file mode 100644 index 00000000000..d3148c53a82 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs @@ -0,0 +1,37 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) +// +// This target assumes that the device has a FPU (Floating Point Unit) and lowers all (single +// precision) floating point operations to hardware instructions. Cortex-A7/A8/A9 processors +// support VFPv3-D32 or VFPv4-D32 floating point units with optional double-precision support. +// +// This target uses the "hard" floating convention (ABI) where floating point values +// are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.). + +use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "thumbv7a-none-eabihf".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "nuttx".into(), + abi: "eabihf".into(), + llvm_floatabi: Some(FloatAbi::Hard), + // Cortex-A7/A8/A9 support VFPv3-D32/VFPv4-D32 with optional double-precision + // and NEON SIMD instructions + features: "+vfp3,+neon".into(), + max_atomic_width: Some(64), + ..base::thumb::opts() + }, + } +} diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index b82bb27eb79..750d2756b4a 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -261,7 +261,6 @@ trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> *[lang_item_name] lang item `{$lang_item_name}` } function has wrong type trait_selection_oc_fn_main_correct_type = `main` function has wrong type -trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type trait_selection_oc_generic = mismatched types trait_selection_oc_if_else_different = `if` and `else` have incompatible types @@ -396,7 +395,6 @@ trait_selection_subtype = ...so that the {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type @@ -410,7 +408,6 @@ trait_selection_subtype_2 = ...so that {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9778299eb19..1e9ef5e536c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2318,7 +2318,6 @@ impl<'tcx> ObligationCause<'tcx> { | ObligationCauseCode::MatchExpressionArm(_) | ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::LetElse - | ObligationCauseCode::StartFunctionType | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver => FailureCode::Error0308, @@ -2376,9 +2375,6 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::MainFunctionType => { ObligationCauseFailureCode::FnMainCorrectType { span } } - ObligationCauseCode::StartFunctionType => { - ObligationCauseFailureCode::FnStartCorrectType { span, subdiags } - } &ObligationCauseCode::LangFunctionType(lang_item_name) => { ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } } @@ -2421,7 +2417,6 @@ impl<'tcx> ObligationCause<'tcx> { "const is compatible with trait" } ObligationCauseCode::MainFunctionType => "`main` function has the correct type", - ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type", ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type", ObligationCauseCode::IntrinsicType => "intrinsic has the correct type", ObligationCauseCode::MethodReceiver => "method receiver has the correct type", @@ -2442,7 +2437,6 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { "const_compat" } ObligationCauseCode::MainFunctionType => "fn_main_correct_type", - ObligationCauseCode::StartFunctionType => "fn_start_correct_type", ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type", ObligationCauseCode::IntrinsicType => "intrinsic_correct_type", ObligationCauseCode::MethodReceiver => "method_correct_type", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 36270e0da78..21124cf20e5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); + match self.tcx.coroutine_kind(cause.body_id) { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen, + _, + )) => (), + None + | Some( + hir::CoroutineKind::Coroutine(_) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _), + ) => return, + } + if let ObligationCauseCode::CompareImplItem { .. } = cause.code() { return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index c40ba330845..bcd3b0109b7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1338,20 +1338,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let derive_better_type_error = |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| { let ocx = ObligationCtxt::new(self); - let normalized_term = match expected_term.unpack() { - ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(), - ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(), - }; - ocx.register_obligation(Obligation::new( - self.tcx, - ObligationCause::dummy(), + + let Ok(normalized_term) = ocx.structurally_normalize_term( + &ObligationCause::dummy(), obligation.param_env, - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { - alias: alias_term, - term: normalized_term, - }), - )); - let _ = ocx.select_where_possible(); + alias_term.to_term(self.tcx), + ) else { + return None; + }; + if let Err(terr) = ocx.eq( &ObligationCause::dummy(), obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index cd4f77bb4cf..f2bcc51e687 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -433,33 +433,19 @@ pub fn report_dyn_incompatibility<'tcx>( hir::Node::Item(item) => Some(item.ident.span), _ => None, }); + let mut err = struct_span_code_err!( tcx.dcx(), span, E0038, - "the trait `{}` cannot be made into an object", + "the {} `{}` is not dyn compatible", + tcx.def_descr(trait_def_id), trait_str ); - err.span_label(span, format!("`{trait_str}` cannot be made into an object")); - - if let Some(hir_id) = hir_id - && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) - && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind - { - let mut hir_id = hir_id; - while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { - hir_id = ty.hir_id; - } - if tcx.parent_hir_node(hir_id).fn_sig().is_some() { - // Do not suggest `impl Trait` when dealing with things like super-traits. - err.span_suggestion_verbose( - ty.span.until(trait_ref.span), - "consider using an opaque type instead", - "impl ", - Applicability::MaybeIncorrect, - ); - } - } + err.span_label(span, format!("`{trait_str}` is not dyn compatible")); + + attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err); + let mut reported_violations = FxIndexSet::default(); let mut multi_span = vec![]; let mut messages = vec![]; @@ -474,7 +460,7 @@ pub fn report_dyn_incompatibility<'tcx>( if reported_violations.insert(violation.clone()) { let spans = violation.spans(); let msg = if trait_span.is_none() || spans.is_empty() { - format!("the trait cannot be made into an object because {}", violation.error_msg()) + format!("the trait is not dyn compatible because {}", violation.error_msg()) } else { format!("...because {}", violation.error_msg()) }; @@ -491,7 +477,7 @@ pub fn report_dyn_incompatibility<'tcx>( let has_multi_span = !multi_span.is_empty(); let mut note_span = MultiSpan::from_spans(multi_span.clone()); if let (Some(trait_span), true) = (trait_span, has_multi_span) { - note_span.push_span_label(trait_span, "this trait cannot be made into an object..."); + note_span.push_span_label(trait_span, "this trait is not dyn compatible..."); } for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); @@ -499,16 +485,12 @@ pub fn report_dyn_incompatibility<'tcx>( // FIXME(dyn_compat_renaming): Update the URL. err.span_note( note_span, - "for a trait to be \"dyn-compatible\" it needs to allow building a vtable to allow the call \ - to be resolvable dynamically; for more information visit \ - <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", + "for a trait to be dyn compatible it needs to allow building a vtable\n\ + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", ); // Only provide the help if its a local trait, otherwise it's not actionable. if trait_span.is_some() { - let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); - reported_violations.sort(); - let mut potential_solutions: Vec<_> = reported_violations.into_iter().map(|violation| violation.solution()).collect(); potential_solutions.sort(); @@ -519,68 +501,116 @@ pub fn report_dyn_incompatibility<'tcx>( } } + attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err); + + err +} + +/// Attempt to suggest converting the `dyn Trait` argument to an enumeration +/// over the types that implement `Trait`. +fn attempt_dyn_to_enum_suggestion( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + trait_str: &str, + err: &mut Diag<'_>, +) { let impls_of = tcx.trait_impls_of(trait_def_id); - let impls = if impls_of.blanket_impls().is_empty() { - impls_of - .non_blanket_impls() - .values() - .flatten() - .filter(|def_id| { - !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..)) - }) - .collect::<Vec<_>>() - } else { - vec![] - }; - let externally_visible = if !impls.is_empty() - && let Some(def_id) = trait_def_id.as_local() + + if !impls_of.blanket_impls().is_empty() { + return; + } + + let concrete_impls: Option<Vec<Ty<'_>>> = impls_of + .non_blanket_impls() + .values() + .flatten() + .map(|impl_id| { + // Don't suggest conversion to enum if the impl types have type parameters. + // It's unlikely the user wants to define a generic enum. + let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None }; + + // Obviously unsized impl types won't be usable in an enum. + // Note: this doesn't use `Ty::is_trivially_sized` because that function + // defaults to assuming that things are *not* sized, whereas we want to + // fall back to assuming that things may be sized. + match impl_type.kind() { + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => { + return None; + } + _ => {} + } + Some(impl_type) + }) + .collect(); + let Some(concrete_impls) = concrete_impls else { return }; + + const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9; + if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM { + return; + } + + let externally_visible = if let Some(def_id) = trait_def_id.as_local() { // We may be executing this during typeck, which would result in cycle // if we used effective_visibilities query, which looks into opaque types // (and therefore calls typeck). - && tcx.resolutions(()).effective_visibilities.is_exported(def_id) - { - true + tcx.resolutions(()).effective_visibilities.is_exported(def_id) } else { false }; - match &impls[..] { - [] => {} - _ if impls.len() > 9 => {} - [only] if externally_visible => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` is seen to implement the trait in this crate, consider using it \ - directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - [only] => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` implements the trait, consider using it directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - impls => { - let types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) - }) - .collect::<Vec<_>>(); - err.help(format!( - "the following types implement the trait, consider defining an enum where each \ - variant holds one of these types, implementing `{}` for this new enum and using \ - it instead:\n{}", - trait_str, - types.join("\n"), - )); - } + + if let [only_impl] = &concrete_impls[..] { + let within = if externally_visible { " within this crate" } else { "" }; + err.help(with_no_trimmed_paths!(format!( + "only type `{only_impl}` implements `{trait_str}`{within}; \ + consider using it directly instead." + ))); + } else { + let types = concrete_impls + .iter() + .map(|t| with_no_trimmed_paths!(format!(" {}", t))) + .collect::<Vec<String>>() + .join("\n"); + + err.help(format!( + "the following types implement `{trait_str}`:\n\ + {types}\n\ + consider defining an enum where each variant holds one of these types,\n\ + implementing `{trait_str}` for this new enum and using it instead", + )); } + if externally_visible { err.note(format!( - "`{trait_str}` can be implemented in other crates; if you want to support your users \ + "`{trait_str}` may be implemented in other crates; if you want to support your users \ passing their own types here, you can't refer to a specific type", )); } +} - err +/// Attempt to suggest that a `dyn Trait` argument or return type be converted +/// to use `impl Trait`. +fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) { + let Some(hir_id) = hir_id else { return }; + let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return }; + let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return }; + + // Only suggest converting `dyn` to `impl` if we're in a function signature. + // This ensures that we don't suggest converting e.g. + // `type Alias = Box<dyn DynIncompatibleTrait>;` to + // `type Alias = Box<impl DynIncompatibleTrait>;` + let Some((_id, first_non_type_parent_node)) = + tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_))) + else { + return; + }; + if first_non_type_parent_node.fn_sig().is_none() { + return; + } + + err.span_suggestion_verbose( + ty.span.until(trait_ref.span), + "consider using an opaque type instead", + "impl ", + Applicability::MaybeIncorrect, + ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c2e73b732d3..4669d286665 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2740,7 +2740,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 53a4e5031c6..0bf91ad35c1 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1695,13 +1695,6 @@ pub enum ObligationCauseFailureCode { #[primary_span] span: Span, }, - #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)] - FnStartCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)] FnLangCorrectType { #[primary_span] diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 4498beff4ea..2b7da4bc5ff 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { _ => ChildMode::PassThrough, }; + let nested_goals = candidate.instantiate_nested_goals(self.span()); + + // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as + // an actual candidate, instead we should treat them as if the impl was never considered to + // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written + // instead of `impl<T: FnPtr> Trait for T`. + // + // We do this as a separate loop so that we do not choose to tell the user about some nested + // goal before we encounter a `T: FnPtr` nested goal. + for nested_goal in &nested_goals { + if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait() + && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() + && poly_trait_pred.def_id() == fn_ptr_trait + && let Err(NoSolution) = nested_goal.result() + { + return ControlFlow::Break(self.obligation.clone()); + } + } + let mut impl_where_bound_count = 0; - for nested_goal in candidate.instantiate_nested_goals(self.span()) { + for nested_goal in nested_goals { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); let make_obligation = |cause| Obligation { @@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] enum ChildMode<'tcx> { // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, // and skip all `GoalSource::Misc`, which represent useless obligations diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e27143f1396..50d47d20e1a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -709,7 +709,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { if matches!(ty.kind(), ty::Alias(..)) { let ocx = ObligationCtxt::new(infcx); ty = ocx - .structurally_normalize(&ObligationCause::dummy(), param_env, ty) + .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty) .map_err(|_| ())?; if !ocx.select_where_possible().is_empty() { return Err(()); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index d2abd881c45..66491d9abe1 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{ TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_span::Span; +use rustc_type_ir::elaborate; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -39,7 +40,7 @@ pub fn hir_ty_lowering_dyn_compatibility_violations( trait_def_id: DefId, ) -> Vec<DynCompatibilityViolation> { debug_assert!(tcx.generics_of(trait_def_id).has_self); - tcx.supertrait_def_ids(trait_def_id) + elaborate::supertrait_def_ids(tcx, trait_def_id) .map(|def_id| predicates_reference_self(tcx, def_id, true)) .filter(|spans| !spans.is_empty()) .map(DynCompatibilityViolation::SupertraitSelf) @@ -52,9 +53,8 @@ fn dyn_compatibility_violations( ) -> &'_ [DynCompatibilityViolation] { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("dyn_compatibility_violations: {:?}", trait_def_id); - tcx.arena.alloc_from_iter( - tcx.supertrait_def_ids(trait_def_id) + elaborate::supertrait_def_ids(tcx, trait_def_id) .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)), ) } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 5e270b62b00..4a3983fca31 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -319,7 +319,7 @@ where self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -327,7 +327,7 @@ where ) -> Result<Ty<'tcx>, Vec<E>> { self.infcx .at(cause, param_env) - .structurally_normalize(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_ty(value, &mut **self.engine.borrow_mut()) } pub fn structurally_normalize_const( @@ -340,4 +340,15 @@ where .at(cause, param_env) .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) } + + pub fn structurally_normalize_term( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Term<'tcx>, + ) -> Result<ty::Term<'tcx>, Vec<E>> { + self.infcx + .at(cause, param_env) + .structurally_normalize_term(value, &mut **self.engine.borrow_mut()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index da16a742099..fe5ad003a7e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -66,9 +66,9 @@ pub use self::specialize::{ }; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ - BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo, elaborate, - expand_trait_aliases, impl_item_is_final, supertraits, - transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars, + BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, + supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, + with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d59cf88875e..537b042bde5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::sym; +use rustc_type_ir::elaborate; use thin_vec::thin_vec; use tracing::{debug, instrument}; @@ -836,8 +837,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( if tcx.is_impl_trait_in_trait(obligation.predicate.def_id) && let Some(out_trait_def_id) = data.principal_def_id() && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id) - && tcx - .supertrait_def_ids(out_trait_def_id) + && elaborate::supertrait_def_ids(tcx, out_trait_def_id) .any(|trait_def_id| trait_def_id == rpitit_trait_def_id) { candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b370f802052..13a6744c2e9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -18,7 +18,7 @@ use rustc_infer::traits::{ use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_type_ir::Interner; +use rustc_type_ir::{Interner, elaborate}; use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; @@ -1003,8 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let a_auto_traits: FxIndexSet<DefId> = a_data .auto_traits() .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| { - self.tcx() - .supertrait_def_ids(principal_def_id) + elaborate::supertrait_def_ids(self.tcx(), principal_def_id) .filter(|def_id| self.tcx().trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5581ea46882..0cc0d7f786b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,7 @@ use rustc_middle::ty::{ TypingMode, Upcast, }; use rustc_span::{Symbol, sym}; +use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use self::EvaluationResult::*; @@ -2531,7 +2532,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let a_auto_traits: FxIndexSet<DefId> = a_data .auto_traits() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - tcx.supertrait_def_ids(principal_def_id).filter(|def_id| tcx.trait_is_auto(*def_id)) + elaborate::supertrait_def_ids(tcx, principal_def_id) + .filter(|def_id| tcx.trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index f8e8f2176c1..e6d5d336b8d 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -7,44 +7,12 @@ use crate::traits::{NormalizeExt, Obligation}; #[extension(pub trait StructurallyNormalizeExt<'tcx>)] impl<'tcx> At<'_, 'tcx> { - fn structurally_normalize<E: 'tcx>( + fn structurally_normalize_ty<E: 'tcx>( &self, ty: Ty<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result<Ty<'tcx>, Vec<E>> { - assert!(!ty.is_ty_var(), "should have resolved vars before calling"); - - if self.infcx.next_trait_solver() { - let ty::Alias(..) = *ty.kind() else { - return Ok(ty); - }; - - let new_infer_ty = self.infcx.next_ty_var(self.cause.span); - - // We simply emit an `alias-eq` goal here, since that will take care of - // normalizing the LHS of the projection until it is a rigid projection - // (or a not-yet-defined opaque in scope). - let obligation = Obligation::new( - self.infcx.tcx, - self.cause.clone(), - self.param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - new_infer_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - fulfill_cx.register_predicate_obligation(self.infcx, obligation); - let errors = fulfill_cx.select_where_possible(self.infcx); - if !errors.is_empty() { - return Err(errors); - } - - Ok(self.infcx.resolve_vars_if_possible(new_infer_ty)) - } else { - Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) - } + self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type()) } fn structurally_normalize_const<E: 'tcx>( @@ -52,14 +20,29 @@ impl<'tcx> At<'_, 'tcx> { ct: ty::Const<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result<ty::Const<'tcx>, Vec<E>> { - assert!(!ct.is_ct_infer(), "should have resolved vars before calling"); + if self.infcx.tcx.features().generic_const_exprs() { + return Ok(super::evaluate_const(&self.infcx, ct, self.param_env)); + } + + self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const()) + } + + fn structurally_normalize_term<E: 'tcx>( + &self, + term: ty::Term<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result<ty::Term<'tcx>, Vec<E>> { + assert!(!term.is_infer(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - let ty::ConstKind::Unevaluated(..) = ct.kind() else { - return Ok(ct); - }; + if let None = term.to_alias_term() { + return Ok(term); + } - let new_infer_ct = self.infcx.next_const_var(self.cause.span); + let new_infer = match term.unpack() { + ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), + ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), + }; // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection @@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> { self.infcx.tcx, self.cause.clone(), self.param_env, - ty::PredicateKind::AliasRelate( - ct.into(), - new_infer_ct.into(), - ty::AliasRelationDirection::Equate, - ), + ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate), ); fulfill_cx.register_predicate_obligation(self.infcx, obligation); @@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> { return Err(errors); } - Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) - } else if self.infcx.tcx.features().generic_const_exprs() { - Ok(super::evaluate_const(&self.infcx, ct, self.param_env)) + Ok(self.infcx.resolve_vars_if_possible(new_infer)) } else { - Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) + Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index da1045b664a..c9fb2a757e1 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,162 +1,85 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::Diag; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; pub use rustc_infer::traits::util::*; use rustc_middle::bug; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_span::Span; use smallvec::{SmallVec, smallvec}; use tracing::debug; -/////////////////////////////////////////////////////////////////////////// -// `TraitAliasExpander` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Trait alias expansion" is the process of expanding a sequence of trait -/// references into another sequence by transitively following all trait -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias -/// `trait Foo = Bar + Sync;`, and another trait alias -/// `trait Bar = Read + Write`, then the bounds would expand to -/// `Read + Write + Sync + Send`. -/// Expansion is done via a DFS (depth-first search), and the `visited` field -/// is used to avoid cycles. -pub struct TraitAliasExpander<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<TraitAliasExpansionInfo<'tcx>>, -} - -/// Stores information about the expansion of a trait via a path of zero or more trait aliases. -#[derive(Debug, Clone)] -pub struct TraitAliasExpansionInfo<'tcx> { - pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, -} - -impl<'tcx> TraitAliasExpansionInfo<'tcx> { - fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - Self { path: smallvec![(trait_ref, span)] } - } - - /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate - /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut Diag<'_>, - top_label: &'static str, - use_desc: &str, - ) { - diag.span_label(self.top().1, top_label); - if self.path.len() > 1 { - for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({use_desc})")); - } - } - if self.top().1 != self.bottom().1 { - // When the trait object is in a return type these two spans match, we don't want - // redundant labels. - diag.span_label( - self.bottom().1, - format!("trait alias used in trait object type ({use_desc})"), - ); - } - } - - pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> { - self.top().0 - } - - pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.last().unwrap() - } - - pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.first().unwrap() - } - - fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - let mut path = self.path.clone(); - path.push((trait_ref, span)); - - Self { path } - } -} - +/// Return the trait and projection predicates that come from eagerly expanding the +/// trait aliases in the list of clauses. For each trait predicate, record a stack +/// of spans that trace from the user-written trait alias bound. For projection predicates, +/// just record the span of the projection itself. +/// +/// For trait aliases, we don't deduplicte the predicates, since we currently do not +/// consider duplicated traits as a single trait for the purposes of our "one trait principal" +/// restriction; however, for projections we do deduplicate them. +/// +/// ```rust,ignore (fails) +/// trait Bar {} +/// trait Foo = Bar + Bar; +/// +/// let not_object_safe: dyn Foo; // bad, two `Bar` principals. +/// ``` pub fn expand_trait_aliases<'tcx>( tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, -) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = - trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect(); - TraitAliasExpander { tcx, stack: items } -} - -impl<'tcx> TraitAliasExpander<'tcx> { - /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` - /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. - /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a - /// trait alias. - /// The return value indicates whether `item` should be yielded to the user. - fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { - let tcx = self.tcx; - let trait_ref = item.trait_ref(); - let pred = trait_ref.upcast(tcx); - - debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); - - // Don't recurse if this bound is not a trait alias. - let is_alias = tcx.is_trait_alias(trait_ref.def_id()); - if !is_alias { - return true; - } - - // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, pred); - if item - .path - .iter() - .rev() - .skip(1) - .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred) - { - return false; - } - - // Get components of trait alias. - let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id()); - debug!(?predicates); - - let items = predicates.skip_binder().iter().rev().filter_map(|(pred, span)| { - pred.instantiate_supertrait(tcx, trait_ref) - .as_trait_clause() - .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) - }); - debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>()); - - self.stack.extend(items); - - false - } -} - -impl<'tcx> Iterator for TraitAliasExpander<'tcx> { - type Item = TraitAliasExpansionInfo<'tcx>; - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> { - while let Some(item) = self.stack.pop() { - if self.expand(&item) { - return Some(item); + clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, +) -> ( + Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>, + Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, +) { + let mut trait_preds = vec![]; + let mut projection_preds = vec![]; + let mut seen_projection_preds = FxHashSet::default(); + + let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect(); + + while let Some((clause, spans)) = queue.pop_front() { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { + if tcx.is_trait_alias(trait_pred.def_id()) { + queue.extend( + tcx.explicit_super_predicates_of(trait_pred.def_id()) + .iter_identity_copied() + .map(|(clause, span)| { + let mut spans = spans.clone(); + spans.push(span); + ( + clause.instantiate_supertrait( + tcx, + clause.kind().rebind(trait_pred.trait_ref), + ), + spans, + ) + }), + ); + } else { + trait_preds.push((clause.kind().rebind(trait_pred), spans)); + } } + ty::ClauseKind::Projection(projection_pred) => { + let projection_pred = clause.kind().rebind(projection_pred); + if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) { + continue; + } + projection_preds.push((projection_pred, *spans.last().unwrap())); + } + ty::ClauseKind::RegionOutlives(..) + | ty::ClauseKind::TypeOutlives(..) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => {} } - None } + + (trait_preds, projection_preds) } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 71c3646498b..3213638afb2 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -47,6 +47,7 @@ use std::ops::ControlFlow; use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::{try_visit, walk_visitable_list}; use rustc_index::{Idx, IndexVec}; +use smallvec::SmallVec; use thin_vec::ThinVec; use crate::data_structures::Lrc; @@ -192,6 +193,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> { } } +impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { + walk_visitable_list!(visitor, self.iter()); + V::Result::output() + } +} + // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general // case, because we can't return a new slice. But note that there are a couple // of trivial impls of `TypeFoldable` for specific slice types elsewhere. |
