diff options
Diffstat (limited to 'compiler')
68 files changed, 907 insertions, 356 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f21f0b895ad..a594339296f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -34,6 +34,7 @@ #![feature(box_patterns)] #![feature(never_type)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index adc4d117b80..f4863137bdd 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -8,6 +8,7 @@ #![feature(box_patterns)] #![feature(let_else)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] pub mod ast_validation; pub mod feature_gate; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 1e9acb114b7..c288cc96990 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -9,6 +9,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6c16c285492..eda9be58d94 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -12,6 +12,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] extern crate proc_macro; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f0612eaba80..75836e14385 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -11,6 +11,7 @@ #![feature(extern_types)] #![feature(nll)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 350199f4e98..9bb8db076a8 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -7,6 +7,7 @@ #![feature(nll)] #![feature(associated_type_bounds)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). //! The backend-agnostic functions of this crate use functions defined in various traits that diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 92854af55bb..838484876c7 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 181e5180d53..205f1cd77c0 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,6 +26,7 @@ #![feature(vec_into_raw_parts)] #![allow(rustc::default_hash_types)] #![deny(unaligned_references)] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 2b64312dbef..0f490c33102 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -8,6 +8,7 @@ #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; @@ -845,7 +846,7 @@ Available lint options: let builtin = sort_lints(sess, builtin); let (plugin_groups, builtin_groups): (Vec<_>, _) = - lint_store.get_lint_groups().iter().cloned().partition(|&(.., p)| p); + lint_store.get_lint_groups().partition(|&(.., p)| p); let plugin_groups = sort_lint_groups(plugin_groups); let builtin_groups = sort_lint_groups(builtin_groups); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7582f317b85..a5c954cca13 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -8,6 +8,7 @@ #![feature(if_let_guard)] #![feature(let_else)] #![feature(nll)] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index dfc07da9169..43a310f4eaf 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -9,6 +9,7 @@ #![feature(proc_macro_span)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 25601ffb37d..3933746c319 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -581,6 +581,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_trivial_field_reads, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE ), + // Used by the `rustc::potential_query_instability` lint to warn methods which + // might not be stable during incremental compilation. + rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE), // ========================================================================== // Internal attributes, Const related: diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 67398c80f36..43900ba8899 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2203,6 +2203,12 @@ impl TypeBinding<'_> { _ => panic!("expected equality type binding for parenthesized generic args"), } } + pub fn opt_const(&self) -> Option<&'_ AnonConst> { + match self.kind { + TypeBindingKind::Equality { term: Term::Const(ref c) } => Some(c), + _ => None, + } + } } #[derive(Debug)] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index df64534ce54..b4df3e1e396 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -5,6 +5,7 @@ #![feature(let_else)] #![feature(nll)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 5aa213cb701..cf86c450a5b 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -938,6 +938,12 @@ pub struct GrowableBitSet<T: Idx> { bit_set: BitSet<T>, } +impl<T: Idx> Default for GrowableBitSet<T> { + fn default() -> Self { + GrowableBitSet::new_empty() + } +} + impl<T: Idx> GrowableBitSet<T> { /// Ensure that the set can hold at least `min_domain_size` elements. pub fn ensure(&mut self, min_domain_size: usize) { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index cff848eeb6a..147061dafeb 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -286,6 +286,26 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { + fn to_trace( + tcx: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + match (a, b) { + (ty::Term::Ty(a), ty::Term::Ty(b)) => { + ToTrace::to_trace(tcx, cause, a_is_expected, a, b) + } + (ty::Term::Const(a), ty::Term::Const(b)) => { + ToTrace::to_trace(tcx, cause, a_is_expected, a, b) + } + (_, _) => todo!(), + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 5f228d1e203..ae79e14db18 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -23,6 +23,7 @@ #![feature(min_specialization)] #![feature(label_break_value)] #![recursion_limit = "512"] // For rustdoc +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 96af16c6687..a1a1168a21d 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -93,7 +93,7 @@ pub enum ProjectionCacheEntry<'tcx> { Recur, Error, NormalizedTy { - ty: NormalizedTy<'tcx>, + ty: Normalized<'tcx, ty::Term<'tcx>>, /// If we were able to successfully evaluate the /// corresponding cache entry key during predicate /// evaluation, then this field stores the final @@ -174,7 +174,11 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { } /// Indicates that `key` was normalized to `value`. - pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { + pub fn insert_term( + &mut self, + key: ProjectionCacheKey<'tcx>, + value: Normalized<'tcx, ty::Term<'tcx>>, + ) { debug!( "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index b911b108a73..eebeabbd452 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -6,6 +6,7 @@ #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] mod callbacks; pub mod interface; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index be31eb89f1b..7a3d77466c5 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -999,7 +999,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().check_private_in_public(()); }, { - sess.time("death_checking", || rustc_passes::dead::check_crate(tcx)); + tcx.hir() + .par_for_each_module(|module| tcx.ensure().check_mod_deathness(module)); }, { sess.time("unused_lib_feature_checking", || { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 9b24f43f7fd..734b32bb92f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2833,7 +2833,7 @@ impl ClashingExternDeclarations { return true; } let tcx = cx.tcx; - if a == b || rustc_middle::ty::TyS::same_type(a, b) { + if a == b { // All nominally-same types are structurally same, too. true } else { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index cb08e952586..5da77b9f946 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -143,7 +143,11 @@ impl LintStore { &self.lints } - pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> { + pub fn get_lint_groups<'t>( + &'t self, + ) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> + 't { + // This function is not used in a way which observes the order of lints. + #[cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] self.lint_groups .iter() .filter(|(_, LintGroup { depr, .. })| { @@ -153,7 +157,6 @@ impl LintStore { .map(|(k, LintGroup { lint_ids, from_plugin, .. })| { (*k, lint_ids.clone(), *from_plugin) }) - .collect() } pub fn register_early_pass( diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index d8e1162890c..fa8cbeaaf51 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{GenericArg, HirId, Item, ItemKind, Node, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_hir::{Expr, ExprKind, GenericArg, Path, PathSegment, QPath}; +use rustc_hir::{HirId, Item, ItemKind, Node, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -49,6 +50,63 @@ impl LateLintPass<'_> for DefaultHashTypes { } declare_tool_lint! { + pub rustc::POTENTIAL_QUERY_INSTABILITY, + Allow, + "require explicit opt-in when using potentially unstable methods or functions", + report_in_external_macro: true +} + +declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]); + +impl LateLintPass<'_> for QueryStability { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to + // error if there are resolution failures. + // + // As internal lints are currently always run if there are `unstable_options`, + // they are added to the lint store of rustdoc. Internal lints are also + // not used via the `lint_mod` query. Crate lints run outside of a query + // so rustdoc currently doesn't disable them. + // + // Instead of relying on this, either change crate lints to a query disabled by + // rustdoc, only run internal lints if the user is explicitly opting in + // or figure out a different way to avoid running lints for rustdoc. + if cx.tcx.sess.opts.actually_rustdoc { + return; + } + + let (span, def_id, substs) = match expr.kind { + ExprKind::MethodCall(segment, _, _) + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => + { + (segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)) + }, + _ => { + let &ty::FnDef(def_id, substs) = + cx.typeck_results() + .node_type(expr.hir_id) + .kind() else { return }; + (expr.span, def_id, substs) + } + }; + if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) { + let def_id = instance.def_id(); + if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { + cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| { + let msg = format!( + "using `{}` can result in unstable query results", + cx.tcx.item_name(def_id) + ); + lint.build(&msg) + .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale") + .emit(); + }) + } + } + } +} + +declare_tool_lint! { pub rustc::USAGE_OF_TY_TYKIND, Allow, "usage of `ty::TyKind` outside of the `ty::sty` module", diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a87f2b2768d..69863b5ff82 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -30,12 +30,14 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(crate_visibility_modifier)] +#![feature(if_let_guard)] #![feature(iter_order_by)] #![feature(let_else)] #![feature(never_type)] #![feature(nll)] #![feature(control_flow_enum)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_middle; @@ -493,6 +495,8 @@ fn register_internals(store: &mut LintStore) { store.register_early_pass(|| Box::new(LintPassImpl)); store.register_lints(&DefaultHashTypes::get_lints()); store.register_late_pass(|| Box::new(DefaultHashTypes)); + store.register_lints(&QueryStability::get_lints()); + store.register_late_pass(|| Box::new(QueryStability)); store.register_lints(&ExistingDocKeyword::get_lints()); store.register_late_pass(|| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); @@ -505,6 +509,7 @@ fn register_internals(store: &mut LintStore) { None, vec![ LintId::of(DEFAULT_HASH_TYPES), + LintId::of(POTENTIAL_QUERY_INSTABILITY), LintId::of(USAGE_OF_TY_TYKIND), LintId::of(PASS_BY_VALUE), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4af68233f0d..f4eba25475e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1793,6 +1793,10 @@ declare_lint! { Warn, "detects name collision with an existing but unstable method", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::Custom( + "once this associated item is added to the standard library, \ + the ambiguity may cause an error or change in behavior!" + ), reference: "issue #48919 <https://github.com/rust-lang/rust/issues/48919>", // Note: this item represents future incompatibility of all unstable functions in the // standard library, and thus should never be removed or changed to an error. @@ -2335,6 +2339,10 @@ declare_lint! { Warn, "reservation of a two-phased borrow conflicts with other shared borrows", @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::Custom( + "this borrowing pattern was not meant to be accepted, \ + and may become a hard error in the future" + ), reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>", }; } @@ -3046,6 +3054,7 @@ declare_lint_pass! { DEREF_INTO_DYN_SUPERTRAIT, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, + SUSPICIOUS_AUTO_TRAIT_IMPLS, ] } @@ -3622,3 +3631,37 @@ declare_lint! { Warn, "duplicated attribute" } + +declare_lint! { + /// The `suspicious_auto_trait_impls` lint checks for potentially incorrect + /// implementations of auto traits. + /// + /// ### Example + /// + /// ```rust + /// struct Foo<T>(T); + /// + /// unsafe impl<T> Send for Foo<*const T> {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A type can implement auto traits, e.g. `Send`, `Sync` and `Unpin`, + /// in two different ways: either by writing an explicit impl or if + /// all fields of the type implement that auto trait. + /// + /// The compiler disables the automatic implementation if an explicit one + /// exists for given type constructor. The exact rules governing this + /// are currently unsound and quite subtle and and will be modified in the future. + /// This change will cause the automatic implementation to be disabled in more + /// cases, potentially breaking some code. + pub SUSPICIOUS_AUTO_TRAIT_IMPLS, + Warn, + "the rules governing auto traits will change in the future", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange, + reference: "issue #93367 <https://github.com/rust-lang/rust/issues/93367>", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3b5d636124d..1f834b7212f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -163,12 +163,17 @@ pub enum FutureIncompatibilityReason { /// This will be an error in a future release, and /// Cargo should create a report even for dependencies FutureReleaseErrorReportNow, + /// Code that changes meaning in some way in a + /// future release. + FutureReleaseSemanticsChange, /// Previously accepted code that will become an /// error in the provided edition EditionError(Edition), /// Code that changes meaning in some way in /// the provided edition EditionSemanticsChange(Edition), + /// A custom reason. + Custom(&'static str), } impl FutureIncompatibilityReason { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 918c3b9daf1..046245080de 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -9,6 +9,7 @@ #![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] extern crate proc_macro; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 920eca7a717..e85cb413deb 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -56,6 +56,7 @@ #![feature(nonzero_ops)] #![feature(unwrap_infallible)] #![recursion_limit = "512"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate bitflags; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index c6226c69f30..17c77c1bbd8 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -221,7 +221,6 @@ pub fn struct_lint_level<'s, 'd>( decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b>) + 'd>, ) { // Check for future incompatibility lints and issue a stronger warning. - let lint_id = LintId::of(lint); let future_incompatible = lint.future_incompatible; let has_future_breakage = future_incompatible.map_or( @@ -345,31 +344,29 @@ pub fn struct_lint_level<'s, 'd>( err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); if let Some(future_incompatible) = future_incompatible { - let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { - "once this associated item is added to the standard library, the ambiguity may \ - cause an error or change in behavior!" - .to_owned() - } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { - "this borrowing pattern was not meant to be accepted, and may become a hard error \ - in the future" - .to_owned() - } else if let FutureIncompatibilityReason::EditionError(edition) = - future_incompatible.reason - { - let current_edition = sess.edition(); - format!( - "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!", - current_edition, edition - ) - } else if let FutureIncompatibilityReason::EditionSemanticsChange(edition) = - future_incompatible.reason - { - format!("this changes meaning in Rust {}", edition) - } else { - "this was previously accepted by the compiler but is being phased out; \ - it will become a hard error in a future release!" - .to_owned() + let explanation = match future_incompatible.reason { + FutureIncompatibilityReason::FutureReleaseError + | FutureIncompatibilityReason::FutureReleaseErrorReportNow => { + "this was previously accepted by the compiler but is being phased out; \ + it will become a hard error in a future release!" + .to_owned() + } + FutureIncompatibilityReason::FutureReleaseSemanticsChange => { + "this will change its meaning in a future release!".to_owned() + } + FutureIncompatibilityReason::EditionError(edition) => { + let current_edition = sess.edition(); + format!( + "this is accepted in the current edition (Rust {}) but is a hard error in Rust {}!", + current_edition, edition + ) + } + FutureIncompatibilityReason::EditionSemanticsChange(edition) => { + format!("this changes meaning in Rust {}", edition) + } + FutureIncompatibilityReason::Custom(reason) => reason.to_owned(), }; + if future_incompatible.explain_reason { err.warn(&explanation); } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 12ece9e6afb..8e87a262192 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -758,6 +758,22 @@ rustc_queries! { desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) } } + /// Return the live symbols in the crate for dead code check. + /// + /// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and + /// their respective impl (i.e., part of the derive macro) + query live_symbols_and_ignored_derived_traits(_: ()) -> ( + FxHashSet<LocalDefId>, + FxHashMap<LocalDefId, Vec<(DefId, DefId)>> + ) { + storage(ArenaCacheSelector<'tcx>) + desc { "find live symbols in crate" } + } + + query check_mod_deathness(key: LocalDefId) -> () { + desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } + } + query check_mod_impl_wf(key: LocalDefId) -> () { desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e7a8e71ce71..78878487a9b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -867,6 +867,9 @@ impl<'tcx> Term<'tcx> { pub fn ty(&self) -> Option<Ty<'tcx>> { if let Term::Ty(ty) = self { Some(ty) } else { None } } + pub fn ct(&self) -> Option<&'tcx Const<'tcx>> { + if let Term::Const(c) = self { Some(c) } else { None } + } } /// This kind of predicate has no *direct* correspondent in the diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 9f8053d4a4e..9e32c0162e6 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -144,6 +144,23 @@ impl<'tcx> TyCtxt<'tcx> { }); } + pub fn non_blanket_impls_for_ty( + self, + def_id: DefId, + self_ty: Ty<'tcx>, + ) -> impl Iterator<Item = DefId> + 'tcx { + let impls = self.trait_impls_of(def_id); + if let Some(simp) = + fast_reject::simplify_type(self, self_ty, SimplifyParams::No, StripReferences::No) + { + if let Some(impls) = impls.non_blanket_impls.get(&simp) { + return impls.iter().copied(); + } + } + + [].iter().copied() + } + /// Applies function to every impl that could possibly match the self type `self_ty` and returns /// the first non-none value. pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>( diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 96c27d649e4..3e3473bea0e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -893,19 +893,6 @@ impl<'tcx> ty::TyS<'tcx> { } } - pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind(), &b.kind()) { - (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { - if did_a != did_b { - return false; - } - - substs_a.types().zip(substs_b.types()).all(|(a, b)| Self::same_type(a, b)) - } - _ => a == b, - } - } - /// Peel off all reference types in this type until there are none left. /// /// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`. diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 38bb00f985a..12ea740d48a 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -9,6 +9,7 @@ #![feature(once_cell)] #![feature(min_specialization)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 1b9fddec2be..2ed14b91778 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{ self, subst::{GenericArgKind, Subst, SubstsRef}, - PredicateKind, Ty, TyCtxt, TyS, + PredicateKind, Ty, TyCtxt, }; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; use rustc_span::{symbol::sym, Span}; @@ -88,7 +88,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { for generic_inner_ty in arg_def.walk() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { // If the inner type matches the type bound by `Pointer` - if TyS::same_type(inner_ty, bound_ty) { + if inner_ty == bound_ty { // Do a substitution using the parameters from the callsite let subst_ty = inner_ty.subst(self.tcx, substs_ref); if let Some((fn_id, fn_substs)) = diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 8e1601fb719..129efc2b523 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -10,6 +10,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 21ac174ba90..bbc65b09ece 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -4,6 +4,7 @@ #![feature(control_flow_enum)] #![feature(let_else)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ec4cefa3537..ca511f7b814 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -62,7 +62,7 @@ impl CheckAttrVisitor<'_> { fn check_attributes( &self, hir_id: HirId, - span: &Span, + span: Span, target: Target, item: Option<ItemLike<'_>>, ) { @@ -81,7 +81,7 @@ impl CheckAttrVisitor<'_> { } sym::target_feature => self.check_target_feature(hir_id, attr, span, target), sym::track_caller => { - self.check_track_caller(hir_id, &attr.span, attrs, span, target) + self.check_track_caller(hir_id, attr.span, attrs, span, target) } sym::doc => self.check_doc_attrs( attr, @@ -106,6 +106,9 @@ impl CheckAttrVisitor<'_> { sym::rustc_legacy_const_generics => { self.check_rustc_legacy_const_generics(&attr, span, target, item) } + sym::rustc_lint_query_instability => { + self.check_rustc_lint_query_instability(&attr, span, target) + } sym::rustc_clean | sym::rustc_dirty | sym::rustc_if_this_changed @@ -253,7 +256,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. - fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Fn | Target::Closure @@ -296,7 +299,7 @@ impl CheckAttrVisitor<'_> { E0518, "attribute should be applied to function or closure", ) - .span_label(*span, "not a function or closure") + .span_label(span, "not a function or closure") .emit(); false } @@ -335,7 +338,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, @@ -354,7 +357,7 @@ impl CheckAttrVisitor<'_> { attr.span, "attribute should be applied to a function definition", ) - .span_label(*span, "not a function definition") + .span_label(span, "not a function definition") .emit(); false } @@ -362,7 +365,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition. - fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, @@ -373,7 +376,7 @@ impl CheckAttrVisitor<'_> { attr.span, "attribute should be applied to a function definition", ) - .span_label(*span, "not a function definition") + .span_label(span, "not a function definition") .emit(); false } @@ -384,16 +387,16 @@ impl CheckAttrVisitor<'_> { fn check_track_caller( &self, hir_id: HirId, - attr_span: &Span, + attr_span: Span, attrs: &[Attribute], - span: &Span, + span: Span, target: Target, ) -> bool { match target { _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { struct_span_err!( self.tcx.sess, - *attr_span, + attr_span, E0736, "cannot use `#[track_caller]` with `#[naked]`", ) @@ -414,11 +417,11 @@ impl CheckAttrVisitor<'_> { _ => { struct_span_err!( self.tcx.sess, - *attr_span, + attr_span, E0739, "attribute should be applied to function" ) - .span_label(*span, "not a function") + .span_label(span, "not a function") .emit(); false } @@ -430,7 +433,7 @@ impl CheckAttrVisitor<'_> { &self, hir_id: HirId, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -450,7 +453,7 @@ impl CheckAttrVisitor<'_> { E0701, "attribute can only be applied to a struct or enum" ) - .span_label(*span, "not a struct or enum") + .span_label(span, "not a struct or enum") .emit(); false } @@ -458,7 +461,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid. - fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Trait => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -473,7 +476,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(*span, "not a trait") + .span_label(span, "not a trait") .emit(); false } @@ -484,7 +487,7 @@ impl CheckAttrVisitor<'_> { fn check_rustc_must_implement_one_of( &self, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -493,7 +496,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute can only be applied to a trait") - .span_label(*span, "not a trait") + .span_label(span, "not a trait") .emit(); false } @@ -505,7 +508,7 @@ impl CheckAttrVisitor<'_> { &self, hir_id: HirId, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -521,7 +524,7 @@ impl CheckAttrVisitor<'_> { being phased out; it will become a hard error in \ a future release!", ) - .span_label(*span, "not a function") + .span_label(span, "not a function") .emit(); }); true @@ -538,7 +541,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(*span, "not a function") + .span_label(span, "not a function") .emit(); false } @@ -1090,7 +1093,7 @@ impl CheckAttrVisitor<'_> { } /// Warns against some misuses of `#[pass_by_value]` - fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Struct | Target::Enum | Target::TyAlias => true, _ => { @@ -1100,7 +1103,7 @@ impl CheckAttrVisitor<'_> { attr.span, "`pass_by_value` attribute should be applied to a struct, enum or type alias.", ) - .span_label(*span, "is not a struct, enum or type alias") + .span_label(span, "is not a struct, enum or type alias") .emit(); false } @@ -1108,13 +1111,7 @@ impl CheckAttrVisitor<'_> { } /// Warns against some misuses of `#[must_use]` - fn check_must_use( - &self, - hir_id: HirId, - attr: &Attribute, - span: &Span, - _target: Target, - ) -> bool { + fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, _target: Target) -> bool { let node = self.tcx.hir().get(hir_id); if let Some(fn_node) = node.fn_kind() { if let rustc_hir::IsAsync::Async = fn_node.asyncness() { @@ -1125,7 +1122,7 @@ impl CheckAttrVisitor<'_> { function, not the value within", ) .span_label( - *span, + span, "this attribute does nothing, the `Future`s \ returned by async functions are already `must_use`", ) @@ -1139,14 +1136,14 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid. - fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => true, _ => { self.tcx .sess .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait") - .span_label(*span, "is not a struct, enum, or trait") + .span_label(span, "is not a struct, enum, or trait") .emit(); false } @@ -1154,7 +1151,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. - fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1174,7 +1171,7 @@ impl CheckAttrVisitor<'_> { being phased out; it will become a hard error in \ a future release!", ) - .span_label(*span, "not a function") + .span_label(span, "not a function") .emit(); }); } @@ -1182,7 +1179,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[link]` is applied to an item other than a foreign module. - fn check_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { Target::ForeignMod => {} _ => { @@ -1194,7 +1191,7 @@ impl CheckAttrVisitor<'_> { a future release!", ); - diag.span_label(*span, "not an `extern` block"); + diag.span_label(span, "not an `extern` block"); diag.emit(); }); } @@ -1202,7 +1199,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1236,7 +1233,7 @@ impl CheckAttrVisitor<'_> { } } - diag.span_label(*span, "not a foreign function or static"); + diag.span_label(span, "not a foreign function or static"); diag.emit(); }); } @@ -1244,7 +1241,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. - fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { Target::ExternCrate => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1262,7 +1259,7 @@ impl CheckAttrVisitor<'_> { attr.span, "attribute should be applied to an `extern crate` item", ) - .span_label(*span, "not an `extern crate` item") + .span_label(span, "not an `extern crate` item") .emit(); false } @@ -1278,7 +1275,7 @@ impl CheckAttrVisitor<'_> { &self, hir_id: HirId, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -1299,7 +1296,7 @@ impl CheckAttrVisitor<'_> { attr.span, "attribute should be applied to a free function, impl method or static", ) - .span_label(*span, "not a free function, impl method or static") + .span_label(span, "not a free function, impl method or static") .emit(); false } @@ -1309,14 +1306,14 @@ impl CheckAttrVisitor<'_> { fn check_rustc_layout_scalar_valid_range( &self, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { if target != Target::Struct { self.tcx .sess .struct_span_err(attr.span, "attribute should be applied to a struct") - .span_label(*span, "not a struct") + .span_label(span, "not a struct") .emit(); return false; } @@ -1341,7 +1338,7 @@ impl CheckAttrVisitor<'_> { fn check_rustc_legacy_const_generics( &self, attr: &Attribute, - span: &Span, + span: Span, target: Target, item: Option<ItemLike<'_>>, ) -> bool { @@ -1350,7 +1347,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute should be applied to a function") - .span_label(*span, "not a function") + .span_label(span, "not a function") .emit(); return false; } @@ -1436,6 +1433,25 @@ impl CheckAttrVisitor<'_> { } } + fn check_rustc_lint_query_instability( + &self, + attr: &Attribute, + span: Span, + target: Target, + ) -> bool { + let is_function = matches!(target, Target::Fn | Target::Method(..)); + if !is_function { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(span, "not a function") + .emit(); + false + } else { + true + } + } + /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool { @@ -1451,7 +1467,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1471,7 +1487,7 @@ impl CheckAttrVisitor<'_> { being phased out; it will become a hard error in \ a future release!", ) - .span_label(*span, "not a function or static") + .span_label(span, "not a function or static") .emit(); }); } @@ -1479,7 +1495,7 @@ impl CheckAttrVisitor<'_> { } /// Checks if `#[no_mangle]` is applied to a function or static. - fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { Target::Static | Target::Fn => {} Target::Method(..) if self.is_impl_item(hir_id) => {} @@ -1509,7 +1525,7 @@ impl CheckAttrVisitor<'_> { being phased out; it will become a hard error in \ a future release!", ) - .span_label(*span, format!("foreign {}", foreign_item_kind)) + .span_label(span, format!("foreign {}", foreign_item_kind)) .note("symbol names in extern blocks are not mangled") .span_suggestion( attr.span, @@ -1532,7 +1548,7 @@ impl CheckAttrVisitor<'_> { being phased out; it will become a hard error in \ a future release!", ) - .span_label(*span, "not a free function, impl method or static") + .span_label(span, "not a free function, impl method or static") .emit(); }); } @@ -1543,7 +1559,7 @@ impl CheckAttrVisitor<'_> { fn check_repr( &self, attrs: &[Attribute], - span: &Span, + span: Span, target: Target, item: Option<ItemLike<'_>>, hir_id: HirId, @@ -1677,7 +1693,7 @@ impl CheckAttrVisitor<'_> { "{}", &format!("attribute should be applied to {} {}", article, allowed_targets) ) - .span_label(*span, &format!("not {} {}", article, allowed_targets)) + .span_label(span, &format!("not {} {}", article, allowed_targets)) .emit(); } @@ -1740,7 +1756,7 @@ impl CheckAttrVisitor<'_> { &self, hir_id: HirId, attr: &Attribute, - span: &Span, + span: Span, target: Target, attrs: &[Attribute], ) -> bool { @@ -1773,7 +1789,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute should be applied to a macro") - .span_label(*span, "not a macro") + .span_label(span, "not a macro") .emit(); false } @@ -1786,7 +1802,7 @@ impl CheckAttrVisitor<'_> { &self, hir_id: HirId, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -1807,7 +1823,7 @@ impl CheckAttrVisitor<'_> { self.tcx .sess .struct_span_err(attr.span, "attribute should be applied to `const fn`") - .span_label(*span, "not a `const fn`") + .span_label(span, "not a `const fn`") .emit(); false } @@ -1818,7 +1834,7 @@ impl CheckAttrVisitor<'_> { fn check_default_method_body_is_const( &self, attr: &Attribute, - span: &Span, + span: Span, target: Target, ) -> bool { match target { @@ -1830,14 +1846,14 @@ impl CheckAttrVisitor<'_> { attr.span, "attribute should be applied to a trait method with body", ) - .span_label(*span, "not a trait method or missing a body") + .span_label(span, "not a trait method or missing a body") .emit(); false } } } - fn check_stability_promotable(&self, attr: &Attribute, _span: &Span, target: Target) -> bool { + fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool { match target { Target::Expression => { self.tcx @@ -1850,7 +1866,7 @@ impl CheckAttrVisitor<'_> { } } - fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: &Span, target: Target) { + fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) { match target { Target::Closure | Target::Expression | Target::Statement | Target::Arm => { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { @@ -1912,29 +1928,29 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { } let target = Target::from_item(item); - self.check_attributes(item.hir_id(), &item.span, target, Some(ItemLike::Item(item))); + self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item))); intravisit::walk_item(self, item) } fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) { let target = Target::from_generic_param(generic_param); - self.check_attributes(generic_param.hir_id, &generic_param.span, target, None); + self.check_attributes(generic_param.hir_id, generic_param.span, target, None); intravisit::walk_generic_param(self, generic_param) } fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) { let target = Target::from_trait_item(trait_item); - self.check_attributes(trait_item.hir_id(), &trait_item.span, target, None); + self.check_attributes(trait_item.hir_id(), trait_item.span, target, None); intravisit::walk_trait_item(self, trait_item) } fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) { - self.check_attributes(struct_field.hir_id, &struct_field.span, Target::Field, None); + self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None); intravisit::walk_field_def(self, struct_field); } fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { - self.check_attributes(arm.hir_id, &arm.span, Target::Arm, None); + self.check_attributes(arm.hir_id, arm.span, Target::Arm, None); intravisit::walk_arm(self, arm); } @@ -1942,7 +1958,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { let target = Target::from_foreign_item(f_item); self.check_attributes( f_item.hir_id(), - &f_item.span, + f_item.span, target, Some(ItemLike::ForeignItem(f_item)), ); @@ -1951,14 +1967,14 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { let target = target_from_impl_item(self.tcx, impl_item); - self.check_attributes(impl_item.hir_id(), &impl_item.span, target, None); + self.check_attributes(impl_item.hir_id(), impl_item.span, target, None); intravisit::walk_impl_item(self, impl_item) } fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { // When checking statements ignore expressions, they will be checked later. if let hir::StmtKind::Local(ref l) = stmt.kind { - self.check_attributes(l.hir_id, &stmt.span, Target::Statement, None); + self.check_attributes(l.hir_id, stmt.span, Target::Statement, None); } intravisit::walk_stmt(self, stmt) } @@ -1969,7 +1985,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { _ => Target::Expression, }; - self.check_attributes(expr.hir_id, &expr.span, target, None); + self.check_attributes(expr.hir_id, expr.span, target, None); intravisit::walk_expr(self, expr) } @@ -1979,12 +1995,12 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { generics: &'tcx hir::Generics<'tcx>, item_id: HirId, ) { - self.check_attributes(variant.id, &variant.span, Target::Variant, None); + self.check_attributes(variant.id, variant.span, Target::Variant, None); intravisit::walk_variant(self, variant, generics, item_id) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - self.check_attributes(param.hir_id, ¶m.span, Target::Param, None); + self.check_attributes(param.hir_id, param.span, Target::Param, None); intravisit::walk_param(self, param); } @@ -2076,7 +2092,7 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { let check_attr_visitor = &mut CheckAttrVisitor { tcx }; tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor()); if module_def_id.is_top_level_module() { - check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None); + check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 7f15aacc532..e7e56711b33 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -13,6 +13,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; @@ -52,7 +53,7 @@ struct MarkSymbolVisitor<'tcx> { // maps from ADTs to ignored derived traits (e.g. Debug and Clone) // and the span of their respective impl (i.e., part of the derive // macro) - ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>, + ignored_derived_traits: FxHashMap<LocalDefId, Vec<(DefId, DefId)>>, } impl<'tcx> MarkSymbolVisitor<'tcx> { @@ -258,12 +259,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap(); if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { - let impl_span = self.tcx.def_span(impl_of); - if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) { - v.push((impl_span, trait_of)); - } else { + if let Some(adt_def_id) = adt_def.did.as_local() { self.ignored_derived_traits - .insert(adt_def.did, vec![(impl_span, trait_of)]); + .entry(adt_def_id) + .or_default() + .push((trait_of, impl_of)); } } return true; @@ -563,8 +563,8 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, - access_levels: &privacy::AccessLevels, ) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) { + let access_levels = &tcx.privacy_access_levels(()); let worklist = access_levels .map .iter() @@ -584,11 +584,11 @@ fn create_and_seed_worklist<'tcx>( (life_seeder.worklist, life_seeder.struct_constructors) } -fn find_live<'tcx>( +fn live_symbols_and_ignored_derived_traits<'tcx>( tcx: TyCtxt<'tcx>, - access_levels: &privacy::AccessLevels, -) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) { - let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels); + (): (), +) -> (FxHashSet<LocalDefId>, FxHashMap<LocalDefId, Vec<(DefId, DefId)>>) { + let (worklist, struct_constructors) = create_and_seed_worklist(tcx); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, @@ -608,8 +608,8 @@ fn find_live<'tcx>( struct DeadVisitor<'tcx> { tcx: TyCtxt<'tcx>, - live_symbols: FxHashSet<LocalDefId>, - ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>, + live_symbols: &'tcx FxHashSet<LocalDefId>, + ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>, } impl<'tcx> DeadVisitor<'tcx> { @@ -682,12 +682,10 @@ impl<'tcx> DeadVisitor<'tcx> { let hir = self.tcx.hir(); if let Some(encl_scope) = hir.get_enclosing_scope(id) { if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) { - if let Some(ign_traits) = - self.ignored_derived_traits.get(&encl_def_id.to_def_id()) - { + if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) { let traits_str = ign_traits .iter() - .map(|(_, t)| format!("`{}`", self.tcx.item_name(*t))) + .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id))) .collect::<Vec<_>>() .join(" and "); let plural_s = pluralize!(ign_traits.len()); @@ -703,7 +701,10 @@ impl<'tcx> DeadVisitor<'tcx> { traits_str, is_are ); - let multispan = ign_traits.iter().map(|(s, _)| *s).collect::<Vec<_>>(); + let multispan = ign_traits + .iter() + .map(|(_, impl_id)| self.tcx.def_span(*impl_id)) + .collect::<Vec<_>>(); err.span_note(multispan, &msg); } } @@ -761,6 +762,9 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> { } } + // This visitor should only visit a single module at a time. + fn visit_mod(&mut self, _: &'tcx hir::Mod<'tcx>, _: Span, _: hir::HirId) {} + fn visit_variant( &mut self, variant: &'tcx hir::Variant<'tcx>, @@ -836,9 +840,16 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> { } } -pub fn check_crate(tcx: TyCtxt<'_>) { - let access_levels = &tcx.privacy_access_levels(()); - let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels); +fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) { + let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(()); let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits }; - tcx.hir().walk_toplevel_module(&mut visitor); + let (module, _, module_id) = tcx.hir().get_module(module); + // Do not use an ItemLikeVisitor since we may want to skip visiting some items + // when a surrounding one is warned against or `_`. + intravisit::walk_mod(&mut visitor, module, module_id); +} + +pub(crate) fn provide(providers: &mut Providers) { + *providers = + Providers { live_symbols_and_ignored_derived_traits, check_mod_deathness, ..*providers }; } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 2075fee7171..3130513c40e 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -13,6 +13,7 @@ #![feature(nll)] #![feature(try_blocks)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_middle; @@ -44,6 +45,7 @@ mod weak_lang_items; pub fn provide(providers: &mut Providers) { check_attr::provide(providers); check_const::provide(providers); + dead::provide(providers); diagnostic_items::provide(providers); entry::provide(providers); lang_items::provide(providers); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d59c12fc2fa..7c511ccbd57 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -4,6 +4,7 @@ #![feature(try_blocks)] #![feature(associated_type_defaults)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] use rustc_ast::MacroDef; use rustc_attr as attr; diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index de9d4253537..bf859decc70 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -7,6 +7,7 @@ #![feature(once_cell)] #![feature(rustc_attrs)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 0436e07e2d4..750ac76a771 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -5,6 +5,7 @@ #![feature(let_else)] #![feature(min_specialization)] #![feature(extern_types)] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2c678e71ae1..6aed3223480 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -400,6 +400,8 @@ struct DiagnosticMetadata<'ast> { /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`. current_where_predicate: Option<&'ast WherePredicate>, + + current_type_path: Option<&'ast Ty>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -472,8 +474,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } fn visit_ty(&mut self, ty: &'ast Ty) { let prev = self.diagnostic_metadata.current_trait_object; + let prev_ty = self.diagnostic_metadata.current_type_path; match ty.kind { TyKind::Path(ref qself, ref path) => { + self.diagnostic_metadata.current_type_path = Some(ty); self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); } TyKind::ImplicitSelf => { @@ -490,6 +494,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } visit::walk_ty(self, ty); self.diagnostic_metadata.current_trait_object = prev; + self.diagnostic_metadata.current_type_path = prev_ty; } fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { self.smart_resolve_path( @@ -1936,7 +1941,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; - // get_from_node_id this.r.use_injections.push(UseError { err, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 7e1e5c78805..d05f139e3bf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -26,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use std::iter; +use std::ops::Deref; use tracing::debug; @@ -265,6 +266,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } + self.detect_assoct_type_constraint_meant_as_path(base_span, &mut err); + // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { err.code(rustc_errors::error_code!(E0411)); @@ -603,6 +606,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { (err, candidates) } + fn detect_assoct_type_constraint_meant_as_path( + &self, + base_span: Span, + err: &mut DiagnosticBuilder<'_>, + ) { + let Some(ty) = self.diagnostic_metadata.current_type_path else { return; }; + let TyKind::Path(_, path) = &ty.kind else { return; }; + for segment in &path.segments { + let Some(params) = &segment.args else { continue; }; + let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { continue; }; + for param in ¶ms.args { + let ast::AngleBracketedArg::Constraint(constraint) = param else { continue; }; + let ast::AssocConstraintKind::Bound { bounds } = &constraint.kind else { + continue; + }; + for bound in bounds { + let ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None) + = bound else + { + continue; + }; + if base_span == trait_ref.span { + err.span_suggestion_verbose( + constraint.ident.span.between(trait_ref.span), + "you might have meant to write a path instead of an associated type bound", + "::".to_string(), + Applicability::MachineApplicable, + ); + } + } + } + } + } + fn get_single_associated_item( &mut self, path: &[Segment], diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 45cc64ea194..d5ad95ace97 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -18,6 +18,7 @@ #![feature(nll)] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 570fa873a23..c14b459570f 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -2,6 +2,7 @@ #![feature(if_let_guard)] #![feature(nll)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] mod dump_visitor; mod dumper; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a756de4c0fc..d2d5b06ad67 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1188,7 +1188,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { "Compiler information to print on stdout", "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\ target-cpus|target-features|relocation-models|code-models|\ - tls-models|target-spec-json|native-static-libs|stack-protector-strategies\ + tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\ link-args]", ), opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 399b616915e..383250cd68f 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -3,6 +3,7 @@ #![feature(min_specialization)] #![feature(once_cell)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 2c3db35bb66..823a927fd8c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -21,6 +21,7 @@ #![feature(negative_impls)] #![feature(nll)] #![feature(min_specialization)] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 198391cbe9c..18627cd2c09 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1171,6 +1171,7 @@ symbols! { rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, rustc_legacy_const_generics, + rustc_lint_query_instability, rustc_macro_transparency, rustc_main, rustc_mir, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c5e85b14421..f4d1f41902a 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -91,6 +91,7 @@ #![feature(never_type)] #![feature(nll)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_middle; diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs index 38aaee64a4d..13706e8c217 100644 --- a/compiler/rustc_target/src/abi/call/s390x.rs +++ b/compiler/rustc_target/src/abi/call/s390x.rs @@ -2,7 +2,7 @@ // for a pre-z13 machine or using -mno-vx. use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{HasDataLayout, TyAbiInterface}; fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 { @@ -12,24 +12,6 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { } } -fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool -where - Ty: TyAbiInterface<'a, C>, - C: HasDataLayout, -{ - match layout.abi { - abi::Abi::Scalar(scalar) => scalar.value.is_float(), - abi::Abi::Aggregate { .. } => { - if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { - is_single_fp_element(cx, layout.field(cx, 0)) - } else { - false - } - } - _ => false, - } -} - fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) where Ty: TyAbiInterface<'a, C> + Copy, @@ -40,7 +22,7 @@ where return; } - if is_single_fp_element(cx, arg.layout) { + if arg.layout.is_single_fp_element(cx) { match arg.layout.size.bytes() { 4 => arg.cast_to(Reg::f32()), 8 => arg.cast_to(Reg::f64()), diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index 28064d85bf1..d169087dfbd 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; -use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout}; +use crate::abi::{HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; #[derive(PartialEq)] @@ -8,24 +8,6 @@ pub enum Flavor { Fastcall, } -fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool -where - Ty: TyAbiInterface<'a, C> + Copy, - C: HasDataLayout, -{ - match layout.abi { - abi::Abi::Scalar(scalar) => scalar.value.is_float(), - abi::Abi::Aggregate { .. } => { - if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { - is_single_fp_element(cx, layout.field(cx, 0)) - } else { - false - } - } - _ => false, - } -} - pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor) where Ty: TyAbiInterface<'a, C> + Copy, @@ -44,7 +26,7 @@ where if t.abi_return_struct_as_int { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. - if !t.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) { + if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { match fn_abi.ret.layout.size.bytes() { 4 => fn_abi.ret.cast_to(Reg::f32()), 8 => fn_abi.ret.cast_to(Reg::f64()), diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a57ad8f2bbd..7f1fd28b30d 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1276,6 +1276,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { { Ty::ty_and_layout_pointee_info_at(self, cx, offset) } + + pub fn is_single_fp_element<C>(self, cx: &C) -> bool + where + Ty: TyAbiInterface<'a, C>, + C: HasDataLayout, + { + match self.abi { + Abi::Scalar(scalar) => scalar.value.is_float(), + Abi::Aggregate { .. } => { + if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { + self.field(cx, 0).is_single_fp_element(cx) + } else { + false + } + } + _ => false, + } + } } impl<'a, Ty> TyAndLayout<'a, Ty> { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index c2484f2d8f6..aefbb398286 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -7,6 +7,7 @@ pub fn target() -> Target { base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; + base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 17e7b481890..0041f596405 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -22,6 +22,7 @@ #![feature(crate_visibility_modifier)] #![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 687bd16ba30..6cb19416cd7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1373,19 +1373,31 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::ObjectCastObligation(_) | ObligationCauseCode::OpaqueType ); - // FIXME(associated_const_equality): Handle Consts here - let data_ty = data.term.ty().unwrap(); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( is_normalized_ty_expected, normalized_ty, - data_ty, + data.term, ) { - values = Some(infer::ValuePairs::Types(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data_ty, - ))); - + values = Some(match (normalized_ty, data.term) { + (ty::Term::Ty(normalized_ty), ty::Term::Ty(ty)) => { + infer::ValuePairs::Types(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + ty, + )) + } + (ty::Term::Const(normalized_ct), ty::Term::Const(ct)) => { + infer::ValuePairs::Consts(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ct, + ct, + )) + } + (_, _) => span_bug!( + obligation.cause.span, + "found const or type where other expected" + ), + }); err_buf = error; err = &err_buf; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8c0dbe9b064..6634f3e364d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1555,7 +1555,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // `erase_late_bound_regions`. let ty_erased = self.tcx.erase_late_bound_regions(ty); let ty_erased = self.tcx.erase_regions(ty_erased); - let eq = ty::TyS::same_type(ty_erased, target_ty_erased); + let eq = ty_erased == target_ty_erased; debug!( "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ target_ty_erased={:?} eq={:?}", @@ -2496,7 +2496,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, trait_pred, - normalized_ty, + normalized_ty.ty().unwrap(), ); debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); if self.predicate_may_hold(&try_obligation) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 346590a2de2..e7897887df7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -200,7 +200,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { debug!(?normalized_ty); - normalized_ty + normalized_ty.ty().unwrap() } fn register_predicate_obligation( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 087fc6034d9..5e7d4c8b415 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -22,12 +22,13 @@ use crate::traits::error_reporting::InferCtxtExt as _; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -44,7 +45,7 @@ pub(super) struct InProgress; /// When attempting to resolve `<T as TraitRef>::Name` ... #[derive(Debug)] -pub enum ProjectionTyError<'tcx> { +pub enum ProjectionError<'tcx> { /// ...we found multiple sources of information and couldn't resolve the ambiguity. TooManyCandidates, @@ -53,7 +54,7 @@ pub enum ProjectionTyError<'tcx> { } #[derive(PartialEq, Eq, Debug)] -enum ProjectionTyCandidate<'tcx> { +enum ProjectionCandidate<'tcx> { /// From a where-clause in the env or object type ParamEnv(ty::PolyProjectionPredicate<'tcx>), @@ -67,28 +68,28 @@ enum ProjectionTyCandidate<'tcx> { Select(Selection<'tcx>), } -enum ProjectionTyCandidateSet<'tcx> { +enum ProjectionCandidateSet<'tcx> { None, - Single(ProjectionTyCandidate<'tcx>), + Single(ProjectionCandidate<'tcx>), Ambiguous, Error(SelectionError<'tcx>), } -impl<'tcx> ProjectionTyCandidateSet<'tcx> { +impl<'tcx> ProjectionCandidateSet<'tcx> { fn mark_ambiguous(&mut self) { - *self = ProjectionTyCandidateSet::Ambiguous; + *self = ProjectionCandidateSet::Ambiguous; } fn mark_error(&mut self, err: SelectionError<'tcx>) { - *self = ProjectionTyCandidateSet::Error(err); + *self = ProjectionCandidateSet::Error(err); } // Returns true if the push was successful, or false if the candidate // was discarded -- this could be because of ambiguity, or because // a higher-priority candidate is already there. - fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { - use self::ProjectionTyCandidate::*; - use self::ProjectionTyCandidateSet::*; + fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool { + use self::ProjectionCandidate::*; + use self::ProjectionCandidateSet::*; // This wacky variable is just used to try and // make code readable and avoid confusing paths. @@ -196,7 +197,9 @@ fn project_and_unify_type<'cx, 'tcx>( debug!(?obligation, "project_and_unify_type"); let mut obligations = vec![]; - let normalized_ty = match opt_normalize_projection_type( + + let infcx = selcx.infcx(); + let normalized = match opt_normalize_projection_type( selcx, obligation.param_env, obligation.predicate.projection_ty, @@ -208,13 +211,11 @@ fn project_and_unify_type<'cx, 'tcx>( Ok(None) => return Ok(Ok(None)), Err(InProgress) => return Ok(Err(InProgress)), }; - - debug!(?normalized_ty, ?obligations, "project_and_unify_type result"); - - let infcx = selcx.infcx(); - // FIXME(associated_const_equality): Handle consts here as well as types. - let obligation_pred_ty = obligation.predicate.term.ty().unwrap(); - match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) { + debug!(?normalized, ?obligations, "project_and_unify_type result"); + match infcx + .at(&obligation.cause, obligation.param_env) + .eq(normalized, obligation.predicate.term) + { Ok(InferOk { obligations: inferred_obligations, value: () }) => { obligations.extend(inferred_obligations); Ok(Ok(Some(obligations))) @@ -441,7 +442,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { obligations.len = ?self.obligations.len(), "AssocTypeNormalizer: normalized type" ); - normalized_ty + normalized_ty.ty().unwrap() } ty::Projection(data) => { @@ -471,6 +472,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { ) .ok() .flatten() + .map(|term| term.ty().unwrap()) .map(|normalized_ty| { PlaceholderReplacer::replace_placeholders( infcx, @@ -793,7 +795,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Ty<'tcx> { +) -> Term<'tcx> { opt_normalize_projection_type( selcx, param_env, @@ -809,7 +811,10 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( // and a deferred predicate to resolve this when more type // information is available. - selcx.infcx().infer_projection(param_env, projection_ty, cause, depth + 1, obligations) + selcx + .infcx() + .infer_projection(param_env, projection_ty, cause, depth + 1, obligations) + .into() }) } @@ -831,7 +836,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Result<Option<Ty<'tcx>>, InProgress> { +) -> Result<Option<Term<'tcx>>, InProgress> { let infcx = selcx.infcx(); // Don't use the projection cache in intercrate mode - // the `infcx` may be re-used between intercrate in non-intercrate @@ -907,15 +912,15 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( debug!("opt_normalize_projection_type: found error"); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - return Ok(Some(result.value)); + return Ok(Some(result.value.into())); } } let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); - match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(Progress { - ty: projected_ty, + match project(selcx, &obligation) { + Ok(Projected::Progress(Progress { + term: projected_term, obligations: mut projected_obligations, })) => { // if projection succeeded, then what we get out of this @@ -923,10 +928,9 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // an impl, where-clause etc) and hence we must // re-normalize it - let projected_ty = selcx.infcx().resolve_vars_if_possible(projected_ty); - debug!(?projected_ty, ?depth, ?projected_obligations); + let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term); - let mut result = if projected_ty.has_projections() { + let mut result = if projected_term.has_projections() { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, @@ -934,13 +938,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( depth + 1, &mut projected_obligations, ); - let normalized_ty = normalizer.fold(projected_ty); - - debug!(?normalized_ty, ?depth); + let normalized_ty = normalizer.fold(projected_term); Normalized { value: normalized_ty, obligations: projected_obligations } } else { - Normalized { value: projected_ty, obligations: projected_obligations } + Normalized { value: projected_term, obligations: projected_obligations } }; let mut deduped: SsoHashSet<_> = Default::default(); @@ -952,28 +954,27 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( }); if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } obligations.extend(result.obligations); - Ok(Some(result.value)) + Ok(Some(result.value.into())) } - Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!(?projected_ty, "opt_normalize_projection_type: no progress"); + Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: vec![] }; if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } // No need to extend `obligations`. Ok(Some(result.value)) } - Err(ProjectionTyError::TooManyCandidates) => { + Err(ProjectionError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); if use_cache { infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); } Ok(None) } - Err(ProjectionTyError::TraitSelectionError(_)) => { + Err(ProjectionError::TraitSelectionError(_)) => { debug!("opt_normalize_projection_type: ERROR"); // if we got an error processing the `T as Trait` part, // just return `ty::err` but add the obligation `T : @@ -985,7 +986,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( } let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); - Ok(Some(result.value)) + Ok(Some(result.value.into())) } } } @@ -1032,30 +1033,22 @@ fn normalize_to_error<'a, 'tcx>( Normalized { value: new_value, obligations: vec![trait_obligation] } } -enum ProjectedTy<'tcx> { +enum Projected<'tcx> { Progress(Progress<'tcx>), - NoProgress(Ty<'tcx>), + NoProgress(ty::Term<'tcx>), } struct Progress<'tcx> { - ty: Ty<'tcx>, + term: ty::Term<'tcx>, obligations: Vec<PredicateObligation<'tcx>>, } impl<'tcx> Progress<'tcx> { fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.ty_error(), obligations: vec![] } + Progress { term: tcx.ty_error().into(), obligations: vec![] } } fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { - debug!( - self.obligations.len = ?self.obligations.len(), - obligations.len = obligations.len(), - "with_addl_obligations" - ); - - debug!(?self.obligations, ?obligations, "with_addl_obligations"); - self.obligations.append(&mut obligations); self } @@ -1066,22 +1059,21 @@ impl<'tcx> Progress<'tcx> { /// IMPORTANT: /// - `obligation` must be fully normalized #[tracing::instrument(level = "info", skip(selcx))] -fn project_type<'cx, 'tcx>( +fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, -) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { +) -> Result<Projected<'tcx>, ProjectionError<'tcx>> { if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) { - debug!("project: overflow!"); // This should really be an immediate error, but some existing code // relies on being able to recover from this. - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow)); } if obligation.predicate.references_error() { - return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); + return Ok(Projected::Progress(Progress::error(selcx.tcx()))); } - let mut candidates = ProjectionTyCandidateSet::None; + let mut candidates = ProjectionCandidateSet::None; // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks @@ -1092,7 +1084,7 @@ fn project_type<'cx, 'tcx>( assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); - if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates { + if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates { // Avoid normalization cycle from selection (see // `assemble_candidates_from_object_ty`). // FIXME(lazy_normalization): Lazy normalization should save us from @@ -1102,19 +1094,22 @@ fn project_type<'cx, 'tcx>( }; match candidates { - ProjectionTyCandidateSet::Single(candidate) => { - Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate))) + ProjectionCandidateSet::Single(candidate) => { + Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate))) } - ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( + ProjectionCandidateSet::None => Ok(Projected::NoProgress( + // FIXME(associated_const_generics): this may need to change in the future? + // need to investigate whether or not this is fine. selcx .tcx() - .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), + .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs) + .into(), )), // Error occurred while trying to processing impls. - ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), + ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)), // Inherent ambiguity that prevents us from even enumerating the // candidates. - ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), + ProjectionCandidateSet::Ambiguous => Err(ProjectionError::TooManyCandidates), } } @@ -1124,14 +1119,13 @@ fn project_type<'cx, 'tcx>( fn assemble_candidates_from_param_env<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { - debug!("assemble_candidates_from_param_env(..)"); assemble_candidates_from_predicates( selcx, obligation, candidate_set, - ProjectionTyCandidate::ParamEnv, + ProjectionCandidate::ParamEnv, obligation.param_env.caller_bounds().iter(), false, ); @@ -1150,7 +1144,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( fn assemble_candidates_from_trait_def<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); @@ -1173,7 +1167,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( selcx, obligation, candidate_set, - ProjectionTyCandidate::TraitDef, + ProjectionCandidate::TraitDef, bounds.iter(), true, ) @@ -1191,7 +1185,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( fn assemble_candidates_from_object_ty<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_object_ty(..)"); @@ -1218,7 +1212,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( selcx, obligation, candidate_set, - ProjectionTyCandidate::Object, + ProjectionCandidate::Object, env_predicates, false, ); @@ -1231,14 +1225,13 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( fn assemble_candidates_from_predicates<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, + ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>, env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>, potentially_unnormalized_candidates: bool, ) { let infcx = selcx.infcx(); for predicate in env_predicates { - debug!(?predicate); let bound_predicate = predicate.kind(); if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); @@ -1253,8 +1246,6 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( ) }); - debug!(?data, ?is_match, ?same_def_id); - if is_match { candidate_set.push_candidate(ctor(data)); @@ -1275,7 +1266,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + candidate_set: &mut ProjectionCandidateSet<'tcx>, ) { // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: @@ -1299,10 +1290,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( super::ImplSource::Closure(_) | super::ImplSource::Generator(_) | super::ImplSource::FnPointer(_) - | super::ImplSource::TraitAlias(_) => { - debug!(?impl_source); - true - } + | super::ImplSource::TraitAlias(_) => true, super::ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in @@ -1327,7 +1315,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. let node_item = - assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) + assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) .map_err(|ErrorReported| ())?; if node_item.is_final() { @@ -1500,7 +1488,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; if eligible { - if candidate_set.push_candidate(ProjectionTyCandidate::Select(impl_source)) { + if candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)) { Ok(()) } else { Err(()) @@ -1514,30 +1502,32 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate: ProjectionTyCandidate<'tcx>, + candidate: ProjectionCandidate<'tcx>, ) -> Progress<'tcx> { debug!(?obligation, ?candidate, "confirm_candidate"); let mut progress = match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) - | ProjectionTyCandidate::Object(poly_projection) => { + ProjectionCandidate::ParamEnv(poly_projection) + | ProjectionCandidate::Object(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection, false) } - ProjectionTyCandidate::TraitDef(poly_projection) => { + ProjectionCandidate::TraitDef(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection, true) } - ProjectionTyCandidate::Select(impl_source) => { + ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } }; + // When checking for cycle during evaluation, we compare predicates with // "syntactic" equality. Since normalization generally introduces a type // with new region variables, we need to resolve them to existing variables // when possible for this to work. See `auto-trait-projection-recursion.rs` // for a case where this matters. - if progress.ty.has_infer_regions() { - progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty); + if progress.term.has_infer_regions() { + progress.term = + progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx())); } progress } @@ -1804,7 +1794,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take // a term instead. - Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations } + Progress { term: cache_entry.term, obligations: nested_obligations } } Err(e) => { let msg = format!( @@ -1813,7 +1803,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ); debug!("confirm_param_env_candidate: {}", msg); let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); - Progress { ty: err, obligations: vec![] } + Progress { term: err.into(), obligations: vec![] } } } } @@ -1830,9 +1820,9 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { + let assoc_ty = match assoc_def(selcx, impl_def_id, assoc_item_id) { Ok(assoc_ty) => assoc_ty, - Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested }, + Err(ErrorReported) => return Progress { term: tcx.ty_error().into(), obligations: nested }, }; if !assoc_ty.item.defaultness.has_value() { @@ -1844,7 +1834,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.name, obligation.predicate ); - return Progress { ty: tcx.ty_error(), obligations: nested }; + return Progress { term: tcx.ty_error().into(), obligations: nested }; } // If we're trying to normalize `<Vec<u32> as X>::A<S>` using //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then: @@ -1856,15 +1846,25 @@ fn confirm_impl_candidate<'cx, 'tcx>( let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); let ty = tcx.type_of(assoc_ty.item.def_id); + let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); + let term: ty::Term<'tcx> = if is_const { + let identity_substs = + crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); + let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id); + let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs)); + tcx.mk_const(ty::Const { ty, val }).into() + } else { + ty.into() + }; if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { let err = tcx.ty_error_with_message( obligation.cause.span, "impl item and trait item have different parameter counts", ); - Progress { ty: err, obligations: nested } + Progress { term: err.into(), obligations: nested } } else { assoc_ty_own_obligations(selcx, obligation, &mut nested); - Progress { ty: ty.subst(tcx, substs), obligations: nested } + Progress { term: term.subst(tcx, substs), obligations: nested } } } @@ -1905,10 +1905,10 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( /// /// Based on the "projection mode", this lookup may in fact only examine the /// topmost impl. See the comments for `Reveal` for more details. -fn assoc_ty_def( +fn assoc_def( selcx: &SelectionContext<'_, '_>, impl_def_id: DefId, - assoc_ty_def_id: DefId, + assoc_def_id: DefId, ) -> Result<specialization_graph::LeafDef, ErrorReported> { let tcx = selcx.tcx(); let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; @@ -1920,7 +1920,7 @@ fn assoc_ty_def( // for the associated item at the given impl. // If there is no such item in that impl, this function will fail with a // cycle error if the specialization graph is currently being built. - if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) { + if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) { let item = tcx.associated_item(impl_item_id); let impl_node = specialization_graph::Node::Impl(impl_def_id); return Ok(specialization_graph::LeafDef { @@ -1931,7 +1931,7 @@ fn assoc_ty_def( } let ancestors = trait_def.ancestors(tcx, impl_def_id)?; - if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) { + if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) { Ok(assoc_item) } else { // This is saying that neither the trait nor @@ -1942,7 +1942,7 @@ fn assoc_ty_def( // should have failed in astconv. bug!( "No associated type `{}` for {}", - tcx.item_name(assoc_ty_def_id), + tcx.item_name(assoc_def_id), tcx.def_path_str(impl_def_id) ) } diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index a8e376838e2..1de50bae31b 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -36,7 +36,10 @@ fn normalize_projection_ty<'tcx>( &mut obligations, ); fulfill_cx.register_predicate_obligations(infcx, obligations); - Ok(NormalizationResult { normalized_ty: answer }) + // FIXME(associated_const_equality): All users of normalize_projection_ty expected + // a type, but there is the possibility it could've been a const now. Maybe change + // it to a Term later? + Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() }) }, ) } diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index fb7fdacf5e6..1717959acc1 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -322,7 +322,7 @@ fn is_type_structurally_recursive_inner<'tcx>( // struct Foo { Option<Option<Foo>> } for &seen_adt in iter { - if ty::TyS::same_type(ty, seen_adt) { + if ty == seen_adt { debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty); return Representability::ContainsRecursive; } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 16fc9a01a27..3e2d7fc3820 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1145,7 +1145,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead // of calling `filter_by_name_and_kind`. - let assoc_ty = tcx + let assoc_item = tcx .associated_items(candidate.def_id()) .filter_by_name_unhygienic(assoc_ident.name) .find(|i| { @@ -1153,35 +1153,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident }) .expect("missing associated type"); - // FIXME(associated_const_equality): need to handle assoc_consts here as well. - if assoc_ty.kind == ty::AssocKind::Const { - tcx.sess - .struct_span_err(path_span, &format!("associated const equality is incomplete")) - .span_label(path_span, "cannot yet relate associated const") - .emit(); - return Err(ErrorReported); - } - if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { + if !assoc_item.vis.is_accessible_from(def_scope, tcx) { + let kind = match assoc_item.kind { + ty::AssocKind::Type => "type", + ty::AssocKind::Const => "const", + _ => unreachable!(), + }; tcx.sess .struct_span_err( binding.span, - &format!("associated type `{}` is private", binding.item_name), + &format!("associated {kind} `{}` is private", binding.item_name), ) - .span_label(binding.span, "private associated type") + .span_label(binding.span, &format!("private associated {kind}")) .emit(); } - tcx.check_stability(assoc_ty.def_id, Some(hir_ref_id), binding.span, None); + tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None); if !speculative { dup_bindings - .entry(assoc_ty.def_id) + .entry(assoc_item.def_id) .and_modify(|prev_span| { self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified { span: binding.span, prev_span: *prev_span, item_name: binding.item_name, - def_path: tcx.def_path_str(assoc_ty.container.id()), + def_path: tcx.def_path_str(assoc_item.container.id()), }); }) .or_insert(binding.span); @@ -1189,7 +1186,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Include substitutions for generic parameters of associated types let projection_ty = candidate.map_bound(|trait_ref| { - let ident = Ident::new(assoc_ty.name, binding.item_name.span); + let ident = Ident::new(assoc_item.name, binding.item_name.span); let item_segment = hir::PathSegment { ident, hir_id: Some(binding.hir_id), @@ -1201,7 +1198,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item( tcx, path_span, - assoc_ty.def_id, + assoc_item.def_id, &item_segment, trait_ref.substs, ); @@ -1212,14 +1209,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); ty::ProjectionTy { - item_def_id: assoc_ty.def_id, + item_def_id: assoc_item.def_id, substs: substs_trait_ref_and_assoc_item, } }); if !speculative { // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref or assoc_ty. These are not well-formed. + // declared in the trait-ref or assoc_item. These are not well-formed. // // Example: // @@ -1260,6 +1257,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // the "projection predicate" for: // // `<T as Iterator>::Item = u32` + let assoc_item_def_id = projection_ty.skip_binder().item_def_id; + let def_kind = tcx.def_kind(assoc_item_def_id); + match (def_kind, term) { + (hir::def::DefKind::AssocTy, ty::Term::Ty(_)) + | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (), + (_, _) => { + let got = if let ty::Term::Ty(_) = term { "type" } else { "const" }; + let expected = def_kind.descr(assoc_item_def_id); + tcx.sess + .struct_span_err( + binding.span, + &format!("mismatch in bind of {expected}, got {got}"), + ) + .span_note( + tcx.def_span(assoc_item_def_id), + &format!("{expected} defined here does not match {got}"), + ) + .emit(); + } + } bounds.projection_bounds.push(( projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs index 21a8d7b5634..4b8f01e3535 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs @@ -37,21 +37,27 @@ pub fn compute_drop_ranges<'a, 'tcx>( def_id: DefId, body: &'tcx Body<'tcx>, ) -> DropRanges { - let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body); + if super::ENABLE_DROP_TRACKING { + let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body); - let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0); - let mut drop_ranges = build_control_flow_graph( - fcx.tcx.hir(), - fcx.tcx, - &fcx.typeck_results.borrow(), - consumed_borrowed_places, - body, - num_exprs, - ); + let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0); + let mut drop_ranges = build_control_flow_graph( + fcx.tcx.hir(), + fcx.tcx, + &fcx.typeck_results.borrow(), + consumed_borrowed_places, + body, + num_exprs, + ); - drop_ranges.propagate_to_fixpoint(); + drop_ranges.propagate_to_fixpoint(); - DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes } + DropRanges { tracked_value_map: drop_ranges.tracked_value_map, nodes: drop_ranges.nodes } + } else { + // If drop range tracking is not enabled, skip all the analysis and produce an + // empty set of DropRanges. + DropRanges { tracked_value_map: FxHashMap::default(), nodes: IndexVec::new() } + } } /// Applies `f` to consumable node in the HIR subtree pointed to by `place`. diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index e954b4cf512..777bd640669 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -1,24 +1,33 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. +use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_errors::ErrorReported; use rustc_hir as hir; +use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::LocalDefId; +use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; +use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor}; +use rustc_session::lint; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use rustc_trait_selection::traits; +use std::ops::ControlFlow; pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] { let mut errors = Vec::new(); - for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) { + for (&trait_def_id, impls_of_trait) in tcx.all_local_trait_impls(()) { for &impl_of_trait in impls_of_trait { match orphan_check_impl(tcx, impl_of_trait) { Ok(()) => {} Err(ErrorReported) => errors.push(impl_of_trait), } } + + if tcx.trait_is_auto(trait_def_id) { + lint_auto_trait_impls(tcx, trait_def_id, impls_of_trait); + } } tcx.arena.alloc_slice(&errors) } @@ -265,3 +274,201 @@ fn emit_orphan_check_error<'tcx>( Err(ErrorReported) } + +#[derive(Default)] +struct AreUniqueParamsVisitor { + seen: GrowableBitSet<u32>, +} + +#[derive(Copy, Clone)] +enum NotUniqueParam<'tcx> { + DuplicateParam(GenericArg<'tcx>), + NotParam(GenericArg<'tcx>), +} + +impl<'tcx> TypeVisitor<'tcx> for AreUniqueParamsVisitor { + type BreakTy = NotUniqueParam<'tcx>; + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + match t.kind() { + ty::Param(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(t.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(t.into())), + } + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + match r { + ty::ReEarlyBound(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(r.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(r.into())), + } + } + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + match c.val { + ty::ConstKind::Param(p) => { + if self.seen.insert(p.index) { + ControlFlow::CONTINUE + } else { + ControlFlow::Break(NotUniqueParam::DuplicateParam(c.into())) + } + } + _ => ControlFlow::Break(NotUniqueParam::NotParam(c.into())), + } + } +} + +/// Lint impls of auto traits if they are likely to have +/// unsound or surprising effects on auto impls. +fn lint_auto_trait_impls(tcx: TyCtxt<'_>, trait_def_id: DefId, impls: &[LocalDefId]) { + let mut non_covering_impls = Vec::new(); + for &impl_def_id in impls { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if trait_ref.references_error() { + return; + } + + if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive { + return; + } + + assert_eq!(trait_ref.substs.len(), 1); + let self_ty = trait_ref.self_ty(); + let (self_type_did, substs) = match self_ty.kind() { + ty::Adt(def, substs) => (def.did, substs), + _ => { + // FIXME: should also lint for stuff like `&i32` but + // considering that auto traits are unstable, that + // isn't too important for now as this only affects + // crates using `nightly`, and std. + continue; + } + }; + + // Impls which completely cover a given root type are fine as they + // disable auto impls entirely. So only lint if the substs + // are not a permutation of the identity substs. + match substs.visit_with(&mut AreUniqueParamsVisitor::default()) { + ControlFlow::Continue(()) => {} // ok + ControlFlow::Break(arg) => { + // Ideally: + // + // - compute the requirements for the auto impl candidate + // - check whether these are implied by the non covering impls + // - if not, emit the lint + // + // What we do here is a bit simpler: + // + // - badly check if an auto impl candidate definitely does not apply + // for the given simplified type + // - if so, do not lint + if fast_reject_auto_impl(tcx, trait_def_id, self_ty) { + // ok + } else { + non_covering_impls.push((impl_def_id, self_type_did, arg)); + } + } + } + } + + for &(impl_def_id, self_type_did, arg) in &non_covering_impls { + tcx.struct_span_lint_hir( + lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, + tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.def_span(impl_def_id), + |err| { + let mut err = err.build(&format!( + "cross-crate traits with a default impl, like `{}`, \ + should not be specialized", + tcx.def_path_str(trait_def_id), + )); + let item_span = tcx.def_span(self_type_did); + let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); + err.span_note( + item_span, + &format!( + "try using the same sequence of generic parameters as the {} definition", + self_descr, + ), + ); + match arg { + NotUniqueParam::DuplicateParam(arg) => { + err.note(&format!("`{}` is mentioned multiple times", arg)); + } + NotUniqueParam::NotParam(arg) => { + err.note(&format!("`{}` is not a generic parameter", arg)); + } + } + err.emit(); + }, + ); + } +} + +fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>) -> bool { + struct DisableAutoTraitVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + self_ty_root: Ty<'tcx>, + seen: FxHashSet<DefId>, + } + + impl<'tcx> TypeVisitor<'tcx> for DisableAutoTraitVisitor<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + let tcx = self.tcx; + if t != self.self_ty_root { + for impl_def_id in tcx.non_blanket_impls_for_ty(self.trait_def_id, t) { + match tcx.impl_polarity(impl_def_id) { + ImplPolarity::Negative => return ControlFlow::BREAK, + ImplPolarity::Reservation => {} + // FIXME(@lcnr): That's probably not good enough, idk + // + // We might just want to take the rustdoc code and somehow avoid + // explicit impls for `Self`. + ImplPolarity::Positive => return ControlFlow::CONTINUE, + } + } + } + + match t.kind() { + ty::Adt(def, substs) => { + // @lcnr: This is the only place where cycles can happen. We avoid this + // by only visiting each `DefId` once. + // + // This will be is incorrect in subtle cases, but I don't care :) + if self.seen.insert(def.did) { + for ty in def.all_fields().map(|field| field.ty(tcx, substs)) { + ty.visit_with(self)?; + } + } + + ControlFlow::CONTINUE + } + _ => t.super_visit_with(self), + } + } + } + + let self_ty_root = match self_ty.kind() { + ty::Adt(def, _) => tcx.mk_adt(def, InternalSubsts::identity_for_item(tcx, def.did)), + _ => unimplemented!("unexpected self ty {:?}", self_ty), + }; + + self_ty_root + .visit_with(&mut DisableAutoTraitVisitor { + tcx, + self_ty_root, + trait_def_id, + seen: FxHashSet::default(), + }) + .is_break() +} diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index b99e44f2105..5cb0d309ff4 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,5 +1,6 @@ use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; +use rustc_hir::def::CtorOf; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit; @@ -160,21 +161,36 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // We've encountered an `AnonConst` in some path, so we need to // figure out which generic parameter it corresponds to and return // the relevant type. - let filtered = path - .segments - .iter() - .filter_map(|seg| seg.args.map(|args| (args.args, seg))) - .find_map(|(args, seg)| { - args.iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) - .map(|index| (index, seg)) - }); + let filtered = path.segments.iter().find_map(|seg| { + seg.args? + .args + .iter() + .filter(|arg| arg.is_ty_or_const()) + .position(|arg| arg.id() == hir_id) + .map(|index| (index, seg)) + }); + + // FIXME(associated_const_generics): can we blend this with iteration above? let (arg_index, segment) = match filtered { None => { - tcx.sess - .delay_span_bug(tcx.def_span(def_id), "no arg matching AnonConst in path"); - return None; + let binding_filtered = path.segments.iter().find_map(|seg| { + seg.args? + .bindings + .iter() + .filter_map(TypeBinding::opt_const) + .position(|ct| ct.hir_id == hir_id) + .map(|idx| (idx, seg)) + }); + match binding_filtered { + Some(inner) => inner, + None => { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "no arg matching AnonConst in path", + ); + return None; + } + } } Some(inner) => inner, }; @@ -182,7 +198,6 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // Try to use the segment resolution if it is valid, otherwise we // default to the path resolution. let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); - use def::CtorOf; let generics = match res { Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx .generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()), @@ -483,15 +498,49 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .discr_type() .to_ty(tcx), + Node::TraitRef(trait_ref @ &TraitRef { + path, .. + }) if let Some((binding, seg)) = + path + .segments + .iter() + .find_map(|seg| { + seg.args?.bindings + .iter() + .find_map(|binding| if binding.opt_const()?.hir_id == hir_id { + Some((binding, seg)) + } else { + None + }) + }) => + { + // FIXME(associated_const_equality) when does this unwrap fail? I have no idea what case it would. + let trait_def_id = trait_ref.trait_def_id().unwrap(); + let assoc_items = tcx.associated_items(trait_def_id); + let assoc_item = assoc_items.find_by_name_and_kind( + tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), + ); + if let Some(assoc_item) = assoc_item { + tcx.type_of(assoc_item.def_id) + } else { + // FIXME(associated_const_equality): add a useful error message here. + tcx.ty_error_with_message( + DUMMY_SP, + &format!("Could not find associated const on trait"), + ) + } + } + Node::GenericParam(&GenericParam { hir_id: param_hir_id, kind: GenericParamKind::Const { default: Some(ct), .. }, .. }) if ct.hir_id == hir_id => tcx.type_of(tcx.hir().local_def_id(param_hir_id)), - x => tcx.ty_error_with_message( + x => + tcx.ty_error_with_message( DUMMY_SP, - &format!("unexpected const parent in type_of(): {:?}", x), + &format!("unexpected const parent in type_of(): {x:?}"), ), } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 6a9f154844a..7b004fa086b 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -69,6 +69,7 @@ This API is completely unstable and subject to change. #![feature(control_flow_enum)] #![feature(hash_drain_filter)] #![recursion_limit = "256"] +#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] #[macro_use] extern crate tracing; |
