Merge pull request #4837 from rust-lang/rustup-2026-01-30
Automatic Rustup
This commit is contained in:
commit
ca86fb5aa9
338 changed files with 12824 additions and 7869 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/21.1-2025-08-01
|
||||
branch = rustc/22.1-2026-01-27
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
|
|
|||
16
Cargo.lock
16
Cargo.lock
|
|
@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
|||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7125972258312e79827b60c9eb93938334100245081cf701a2dee981b17427"
|
||||
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
|
||||
dependencies = [
|
||||
"askama_macros",
|
||||
"itoa",
|
||||
|
|
@ -197,9 +197,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.15.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
|
||||
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
|
|
@ -214,18 +214,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_macros"
|
||||
version = "0.15.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
|
||||
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.15.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c63392767bb2df6aa65a6e1e3b80fd89bb7af6d58359b924c0695620f1512e"
|
||||
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
type Item = Symbol;
|
||||
const CONVERT: ConvertFn<Self::Item> =
|
||||
|items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
|
||||
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(items, first_span);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
|
|||
cx.emit_err(NullOnObjcClass { span: nv.value_span });
|
||||
return None;
|
||||
}
|
||||
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcObjcClass { classname, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
|
|||
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
|
||||
return None;
|
||||
}
|
||||
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
|||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::Confusables {
|
||||
Some(AttributeKind::RustcConfusables {
|
||||
symbols: self.confusables,
|
||||
first_span: self.first_span.unwrap(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ impl<S: Stage> SingleAttributeParser<S> for DummyParser {
|
|||
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
||||
|
||||
fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::Dummy)
|
||||
Some(AttributeKind::RustcDummy)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
|
|||
Allow(Target::Static),
|
||||
Allow(Target::ForeignStatic),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
|
||||
}
|
||||
|
||||
pub(crate) struct LinkOrdinalParser;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser {
|
|||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
|
||||
}
|
||||
|
||||
pub(crate) struct PubTransparentParser;
|
||||
|
|
@ -23,7 +23,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PubTransparentParser {
|
|||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
|
||||
}
|
||||
|
||||
pub(crate) struct PassByValueParser;
|
||||
|
|
@ -35,7 +35,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for PassByValueParser {
|
|||
Allow(Target::Enum),
|
||||
Allow(Target::TyAlias),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
|||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::BodyStability { stability, span })
|
||||
Some(AttributeKind::RustcBodyStability { stability, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ConstStabilityIndirectParser {
|
|||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect;
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -258,7 +258,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
|||
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::ConstStability { stability, span })
|
||||
Some(AttributeKind::RustcConstStability { stability, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,11 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
|||
cx.duplicate_key(arg.span(), key);
|
||||
}
|
||||
}
|
||||
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcSkipDuringMethodDispatch {
|
||||
array,
|
||||
boxed_slice,
|
||||
span: cx.attr_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +63,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
|
||||
}
|
||||
|
||||
pub(crate) struct TypeConstParser;
|
||||
|
|
@ -91,7 +95,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct DynIncompatibleTraitParser;
|
||||
|
|
@ -99,7 +103,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
|
||||
}
|
||||
|
||||
// Specialization
|
||||
|
|
@ -109,7 +113,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
|
||||
}
|
||||
|
||||
pub(crate) struct UnsafeSpecializationMarkerParser;
|
||||
|
|
@ -117,7 +121,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
||||
}
|
||||
|
||||
// Coherence
|
||||
|
|
@ -127,7 +131,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
|
||||
}
|
||||
|
||||
pub(crate) struct AllowIncoherentImplParser;
|
||||
|
|
@ -136,7 +140,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
|
|||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct FundamentalParser;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
}
|
||||
None => None,
|
||||
}
|
||||
.map(AttributeKind::MacroTransparency)
|
||||
.map(AttributeKind::RustcMacroTransparency)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ pub(crate) fn allowed_targets_applied(
|
|||
];
|
||||
const IMPL_LIKE: &[Target] =
|
||||
&[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
|
||||
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
|
||||
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum, Target::Union];
|
||||
|
||||
let mut added_fake_targets = Vec::new();
|
||||
filter_targets(
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
|||
|
||||
let placeholder_region = ty::Region::new_placeholder(
|
||||
tcx,
|
||||
ty::Placeholder::new(adjusted_universe.into(), placeholder.bound),
|
||||
ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.bound),
|
||||
);
|
||||
|
||||
let error_region =
|
||||
|
|
@ -179,7 +179,7 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
|||
adjusted_universe.map(|adjusted| {
|
||||
ty::Region::new_placeholder(
|
||||
tcx,
|
||||
ty::Placeholder::new(adjusted.into(), error_placeholder.bound),
|
||||
ty::PlaceholderRegion::new(adjusted.into(), error_placeholder.bound),
|
||||
)
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -7,7 +8,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{BytePos, DUMMY_SP, ExpnKind, MacroKind, Span};
|
||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use tracing::debug;
|
||||
|
|
@ -472,49 +473,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field =>
|
||||
{
|
||||
let closure_kind_ty = closure_args.as_closure().kind_ty();
|
||||
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
|
||||
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
|
||||
Some(ty::ClosureKind::FnOnce) => {
|
||||
bug!("closure kind does not match first argument type")
|
||||
}
|
||||
None => bug!("closure kind not inferred by borrowck"),
|
||||
};
|
||||
let capture_description =
|
||||
format!("captured variable in an `{closure_kind}` closure");
|
||||
|
||||
let upvar = &self.upvars[upvar_field.index()];
|
||||
let upvar_hir_id = upvar.get_root_variable();
|
||||
let upvar_name = upvar.to_string(tcx);
|
||||
let upvar_span = tcx.hir_span(upvar_hir_id);
|
||||
|
||||
let place_name = self.describe_any_place(move_place.as_ref());
|
||||
|
||||
let place_description =
|
||||
if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
|
||||
format!("{place_name}, a {capture_description}")
|
||||
} else {
|
||||
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
|
||||
};
|
||||
|
||||
debug!(
|
||||
"report: closure_kind_ty={:?} closure_kind={:?} place_description={:?}",
|
||||
closure_kind_ty, closure_kind, place_description,
|
||||
);
|
||||
|
||||
let closure_span = tcx.def_span(def_id);
|
||||
|
||||
self.cannot_move_out_of(span, &place_description)
|
||||
.with_span_label(upvar_span, "captured outer variable")
|
||||
.with_span_label(
|
||||
closure_span,
|
||||
format!("captured by this `{closure_kind}` closure"),
|
||||
)
|
||||
.with_span_help(
|
||||
self.get_closure_bound_clause_span(*def_id),
|
||||
"`Fn` and `FnMut` closures require captured values to be able to be \
|
||||
consumed multiple times, but `FnOnce` closures may consume them only once",
|
||||
)
|
||||
self.report_closure_move_error(
|
||||
span,
|
||||
move_place,
|
||||
*def_id,
|
||||
closure_args.as_closure().kind_ty(),
|
||||
upvar_field,
|
||||
ty::Asyncness::No,
|
||||
)
|
||||
}
|
||||
ty::CoroutineClosure(def_id, closure_args)
|
||||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field
|
||||
&& self
|
||||
.get_closure_bound_clause_span(*def_id, ty::Asyncness::Yes)
|
||||
.is_some() =>
|
||||
{
|
||||
self.report_closure_move_error(
|
||||
span,
|
||||
move_place,
|
||||
*def_id,
|
||||
closure_args.as_coroutine_closure().kind_ty(),
|
||||
upvar_field,
|
||||
ty::Asyncness::Yes,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let source = self.borrowed_content_source(deref_base);
|
||||
|
|
@ -563,45 +545,134 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
|
||||
fn report_closure_move_error(
|
||||
&self,
|
||||
span: Span,
|
||||
move_place: Place<'tcx>,
|
||||
def_id: DefId,
|
||||
closure_kind_ty: Ty<'tcx>,
|
||||
upvar_field: FieldIdx,
|
||||
asyncness: ty::Asyncness,
|
||||
) -> Diag<'infcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let closure_kind = match closure_kind_ty.to_opt_closure_kind() {
|
||||
Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind,
|
||||
Some(ty::ClosureKind::FnOnce) => {
|
||||
bug!("closure kind does not match first argument type")
|
||||
}
|
||||
None => bug!("closure kind not inferred by borrowck"),
|
||||
};
|
||||
|
||||
let async_prefix = if asyncness.is_async() { "Async" } else { "" };
|
||||
let capture_description =
|
||||
format!("captured variable in an `{async_prefix}{closure_kind}` closure");
|
||||
|
||||
let upvar = &self.upvars[upvar_field.index()];
|
||||
let upvar_hir_id = upvar.get_root_variable();
|
||||
let upvar_name = upvar.to_string(tcx);
|
||||
let upvar_span = tcx.hir_span(upvar_hir_id);
|
||||
|
||||
let place_name = self.describe_any_place(move_place.as_ref());
|
||||
|
||||
let place_description = if self.is_upvar_field_projection(move_place.as_ref()).is_some() {
|
||||
format!("{place_name}, a {capture_description}")
|
||||
} else {
|
||||
format!("{place_name}, as `{upvar_name}` is a {capture_description}")
|
||||
};
|
||||
|
||||
debug!(?closure_kind_ty, ?closure_kind, ?place_description);
|
||||
|
||||
let closure_span = tcx.def_span(def_id);
|
||||
|
||||
let help_msg = format!(
|
||||
"`{async_prefix}Fn` and `{async_prefix}FnMut` closures require captured values to \
|
||||
be able to be consumed multiple times, but `{async_prefix}FnOnce` closures may \
|
||||
consume them only once"
|
||||
);
|
||||
|
||||
let mut err = self
|
||||
.cannot_move_out_of(span, &place_description)
|
||||
.with_span_label(upvar_span, "captured outer variable")
|
||||
.with_span_label(
|
||||
closure_span,
|
||||
format!("captured by this `{async_prefix}{closure_kind}` closure"),
|
||||
);
|
||||
|
||||
if let Some(bound_span) = self.get_closure_bound_clause_span(def_id, asyncness) {
|
||||
err.span_help(bound_span, help_msg);
|
||||
} else if !asyncness.is_async() {
|
||||
// For sync closures, always emit the help message even without a span.
|
||||
// For async closures, we only enter this branch if we found a valid span
|
||||
// (due to the match guard), so no fallback is needed.
|
||||
err.help(help_msg);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn get_closure_bound_clause_span(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
asyncness: ty::Asyncness,
|
||||
) -> Option<Span> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let typeck_result = tcx.typeck(self.mir_def_id());
|
||||
// Check whether the closure is an argument to a call, if so,
|
||||
// get the instantiated where-bounds of that call.
|
||||
let closure_hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
|
||||
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return DUMMY_SP };
|
||||
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None };
|
||||
|
||||
let predicates = match parent.kind {
|
||||
hir::ExprKind::Call(callee, _) => {
|
||||
let Some(ty) = typeck_result.node_type_opt(callee.hir_id) else { return DUMMY_SP };
|
||||
let ty::FnDef(fn_def_id, args) = ty.kind() else { return DUMMY_SP };
|
||||
let ty = typeck_result.node_type_opt(callee.hir_id)?;
|
||||
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
|
||||
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
|
||||
}
|
||||
hir::ExprKind::MethodCall(..) => {
|
||||
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
|
||||
return DUMMY_SP;
|
||||
};
|
||||
let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?;
|
||||
let args = typeck_result.node_args(parent.hir_id);
|
||||
tcx.predicates_of(method).instantiate(tcx, args)
|
||||
}
|
||||
_ => return DUMMY_SP,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
|
||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`
|
||||
// or `AsyncFn[Mut]`.
|
||||
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
|
||||
if let Some(clause) = pred.as_trait_clause()
|
||||
&& let ty::Closure(clause_closure_def_id, _) = clause.self_ty().skip_binder().kind()
|
||||
&& *clause_closure_def_id == def_id
|
||||
&& (tcx.lang_items().fn_mut_trait() == Some(clause.def_id())
|
||||
|| tcx.lang_items().fn_trait() == Some(clause.def_id()))
|
||||
{
|
||||
// Found `<TyOfCapturingClosure as FnMut>`
|
||||
// We point at the `Fn()` or `FnMut()` bound that coerced the closure, which
|
||||
// could be changed to `FnOnce()` to avoid the move error.
|
||||
return *span;
|
||||
let dominated_by_fn_trait = self
|
||||
.closure_clause_kind(*pred, def_id, asyncness)
|
||||
.is_some_and(|kind| matches!(kind, ty::ClosureKind::Fn | ty::ClosureKind::FnMut));
|
||||
if dominated_by_fn_trait {
|
||||
// Found `<TyOfCapturingClosure as FnMut>` or
|
||||
// `<TyOfCapturingClosure as AsyncFnMut>`.
|
||||
// We point at the bound that coerced the closure, which could be changed
|
||||
// to `FnOnce()` or `AsyncFnOnce()` to avoid the move error.
|
||||
return Some(*span);
|
||||
}
|
||||
}
|
||||
DUMMY_SP
|
||||
None
|
||||
}
|
||||
|
||||
/// If `pred` is a trait clause binding the closure `def_id` to `Fn`/`FnMut`/`FnOnce`
|
||||
/// (or their async equivalents based on `asyncness`), returns the corresponding
|
||||
/// `ClosureKind`. Otherwise returns `None`.
|
||||
fn closure_clause_kind(
|
||||
&self,
|
||||
pred: ty::Clause<'tcx>,
|
||||
def_id: DefId,
|
||||
asyncness: ty::Asyncness,
|
||||
) -> Option<ty::ClosureKind> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let clause = pred.as_trait_clause()?;
|
||||
let kind = match asyncness {
|
||||
ty::Asyncness::Yes => tcx.async_fn_trait_kind_from_def_id(clause.def_id()),
|
||||
ty::Asyncness::No => tcx.fn_trait_kind_from_def_id(clause.def_id()),
|
||||
}?;
|
||||
match clause.self_ty().skip_binder().kind() {
|
||||
ty::Closure(id, _) | ty::CoroutineClosure(id, _) if *id == def_id => Some(kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
||||
|
|
|
|||
|
|
@ -62,57 +62,23 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||
enum PlaceholderReachability {
|
||||
/// This SCC reaches no placeholders.
|
||||
NoPlaceholders,
|
||||
/// This SCC reaches at least one placeholder.
|
||||
Placeholders {
|
||||
/// The largest-universed placeholder we can reach
|
||||
max_universe: (UniverseIndex, RegionVid),
|
||||
struct PlaceholderReachability {
|
||||
/// The largest-universed placeholder we can reach
|
||||
max_universe: (UniverseIndex, RegionVid),
|
||||
|
||||
/// The placeholder with the smallest ID
|
||||
min_placeholder: RegionVid,
|
||||
/// The placeholder with the smallest ID
|
||||
min_placeholder: RegionVid,
|
||||
|
||||
/// The placeholder with the largest ID
|
||||
max_placeholder: RegionVid,
|
||||
},
|
||||
/// The placeholder with the largest ID
|
||||
max_placeholder: RegionVid,
|
||||
}
|
||||
|
||||
impl PlaceholderReachability {
|
||||
/// Merge the reachable placeholders of two graph components.
|
||||
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
|
||||
use PlaceholderReachability::*;
|
||||
match (self, other) {
|
||||
(NoPlaceholders, NoPlaceholders) => NoPlaceholders,
|
||||
(NoPlaceholders, p @ Placeholders { .. })
|
||||
| (p @ Placeholders { .. }, NoPlaceholders) => p,
|
||||
(
|
||||
Placeholders {
|
||||
min_placeholder: min_pl,
|
||||
max_placeholder: max_pl,
|
||||
max_universe: max_u,
|
||||
},
|
||||
Placeholders { min_placeholder, max_placeholder, max_universe },
|
||||
) => Placeholders {
|
||||
min_placeholder: min_pl.min(min_placeholder),
|
||||
max_placeholder: max_pl.max(max_placeholder),
|
||||
max_universe: max_u.max(max_universe),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> {
|
||||
match self {
|
||||
Self::NoPlaceholders => None,
|
||||
Self::Placeholders { max_universe, .. } => Some(*max_universe),
|
||||
}
|
||||
}
|
||||
|
||||
/// If we have reached placeholders, determine if they can
|
||||
/// be named from this universe.
|
||||
fn can_be_named_by(&self, from: UniverseIndex) -> bool {
|
||||
self.max_universe()
|
||||
.is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe))
|
||||
fn merge(&mut self, other: &Self) {
|
||||
self.max_universe = self.max_universe.max(other.max_universe);
|
||||
self.min_placeholder = self.min_placeholder.min(other.min_placeholder);
|
||||
self.max_placeholder = self.max_placeholder.max(other.max_placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +86,7 @@ impl PlaceholderReachability {
|
|||
/// the values of its elements. This annotates a single SCC.
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
pub(crate) struct RegionTracker {
|
||||
reachable_placeholders: PlaceholderReachability,
|
||||
reachable_placeholders: Option<PlaceholderReachability>,
|
||||
|
||||
/// The largest universe nameable from this SCC.
|
||||
/// It is the smallest nameable universes of all
|
||||
|
|
@ -135,13 +101,13 @@ impl RegionTracker {
|
|||
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
|
||||
let reachable_placeholders =
|
||||
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
|
||||
PlaceholderReachability::Placeholders {
|
||||
Some(PlaceholderReachability {
|
||||
max_universe: (definition.universe, rvid),
|
||||
min_placeholder: rvid,
|
||||
max_placeholder: rvid,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
PlaceholderReachability::NoPlaceholders
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
|
|
@ -159,43 +125,46 @@ impl RegionTracker {
|
|||
}
|
||||
|
||||
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
|
||||
if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
|
||||
universe
|
||||
} else {
|
||||
UniverseIndex::ROOT
|
||||
}
|
||||
self.reachable_placeholders.map(|pls| pls.max_universe.0).unwrap_or(UniverseIndex::ROOT)
|
||||
}
|
||||
|
||||
/// Can all reachable placeholders be named from `from`?
|
||||
/// True vacuously in case no placeholders were reached.
|
||||
fn placeholders_can_be_named_by(&self, from: UniverseIndex) -> bool {
|
||||
self.reachable_placeholders.is_none_or(|pls| from.can_name(pls.max_universe.0))
|
||||
}
|
||||
|
||||
/// Determine if we can name all the placeholders in `other`.
|
||||
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
|
||||
other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
|
||||
// HACK: We first check whether we can name the highest existential universe
|
||||
// of `other`. This only exists to avoid errors in case that scc already
|
||||
// depends on a placeholder it cannot name itself.
|
||||
self.max_nameable_universe().can_name(other.max_nameable_universe())
|
||||
|| other.placeholders_can_be_named_by(self.max_nameable_universe.0)
|
||||
}
|
||||
|
||||
/// If this SCC reaches a placeholder it can't name, return it.
|
||||
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
|
||||
self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
|
||||
!self.max_nameable_universe().can_name(placeholder_universe)
|
||||
})
|
||||
self.reachable_placeholders
|
||||
.filter(|pls| !self.max_nameable_universe().can_name(pls.max_universe.0))
|
||||
.map(|pls| pls.max_universe)
|
||||
}
|
||||
}
|
||||
|
||||
impl scc::Annotation for RegionTracker {
|
||||
fn merge_scc(self, other: Self) -> Self {
|
||||
fn update_scc(&mut self, other: &Self) {
|
||||
trace!("{:?} << {:?}", self.representative, other.representative);
|
||||
|
||||
Self {
|
||||
representative: self.representative.min(other.representative),
|
||||
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
|
||||
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
|
||||
}
|
||||
self.representative = self.representative.min(other.representative);
|
||||
self.update_reachable(other);
|
||||
}
|
||||
|
||||
fn merge_reached(self, other: Self) -> Self {
|
||||
Self {
|
||||
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
|
||||
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
|
||||
representative: self.representative,
|
||||
}
|
||||
fn update_reachable(&mut self, other: &Self) {
|
||||
self.max_nameable_universe = self.max_nameable_universe.min(other.max_nameable_universe);
|
||||
match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) {
|
||||
(None, None) | (Some(_), None) => (),
|
||||
(None, Some(theirs)) => self.reachable_placeholders = Some(*theirs),
|
||||
(Some(ours), Some(theirs)) => ours.merge(theirs),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ fn render_region_vid<'tcx>(
|
|||
format!(" (for<{}>)", tcx.item_name(def_id))
|
||||
}
|
||||
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
|
||||
ty::BoundRegionKind::NamedAnon(_) => {
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use rustc_middle::ty::{self, RegionVid};
|
|||
use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::BorrowIndex;
|
||||
use crate::polonius::LiveLoans;
|
||||
use crate::{BorrowIndex, TyCtxt};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
|
|
@ -420,18 +420,18 @@ impl ToElementIndex<'_> for RegionVid {
|
|||
impl<'tcx> ToElementIndex<'tcx> for ty::PlaceholderRegion<'tcx> {
|
||||
fn add_to_row<N: Idx>(self, values: &mut RegionValues<'tcx, N>, row: N) -> bool
|
||||
where
|
||||
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
||||
{
|
||||
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
|
||||
let index = values.placeholder_indices.lookup_index(placeholder);
|
||||
values.placeholders.insert(row, index)
|
||||
}
|
||||
|
||||
fn contained_in_row<N: Idx>(self, values: &RegionValues<'tcx, N>, row: N) -> bool
|
||||
where
|
||||
Self: Into<ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
||||
{
|
||||
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
|
||||
let index = values.placeholder_indices.lookup_index(placeholder);
|
||||
values.placeholders.contains(row, index)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -775,7 +775,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
ty::BoundRegionKind::Anon => sym::anon,
|
||||
ty::BoundRegionKind::Named(def_id) => tcx.item_name(def_id),
|
||||
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||
ty::BoundRegionKind::NamedAnon(_) => {
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
let infcx = self.type_checker.infcx;
|
||||
let mut lazy_universe = None;
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
regions: &mut |br: ty::BoundRegion<'tcx>| {
|
||||
// The first time this closure is called, create a
|
||||
// new universe for the placeholders we will make
|
||||
// from here out.
|
||||
|
|
@ -191,10 +191,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
|
||||
placeholder_reg
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -218,7 +218,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
let infcx = self.type_checker.infcx;
|
||||
let mut reg_map = FxHashMap::default();
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
regions: &mut |br: ty::BoundRegion<'tcx>| {
|
||||
if let Some(ex_reg_var) = reg_map.get(&br) {
|
||||
*ex_reg_var
|
||||
} else {
|
||||
|
|
@ -230,10 +230,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
ex_reg_var
|
||||
}
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -268,7 +268,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
ty::BoundRegionKind::Anon => sym::anon,
|
||||
ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
|
||||
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||
ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => bug!("only used for pretty printing"),
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
|
|
|
|||
|
|
@ -188,19 +188,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
load
|
||||
}
|
||||
}
|
||||
|
||||
fn memset(&mut self, ptr: &'ll Value, fill_byte: &'ll Value, size: &'ll Value, align: Align) {
|
||||
unsafe {
|
||||
llvm::LLVMRustBuildMemSet(
|
||||
self.llbuilder,
|
||||
ptr,
|
||||
align.bytes() as c_uint,
|
||||
fill_byte,
|
||||
size,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty string, to be used where LLVM expects an instruction name, indicating
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ pub(crate) struct OffloadGlobals<'ll> {
|
|||
pub launcher_fn: &'ll llvm::Value,
|
||||
pub launcher_ty: &'ll llvm::Type,
|
||||
|
||||
pub bin_desc: &'ll llvm::Type,
|
||||
|
||||
pub kernel_args_ty: &'ll llvm::Type,
|
||||
|
||||
pub offload_entry_ty: &'ll llvm::Type,
|
||||
|
|
@ -31,8 +29,8 @@ pub(crate) struct OffloadGlobals<'ll> {
|
|||
|
||||
pub ident_t_global: &'ll llvm::Value,
|
||||
|
||||
pub register_lib: &'ll llvm::Value,
|
||||
pub unregister_lib: &'ll llvm::Value,
|
||||
// FIXME(offload): Drop this, once we fully automated our offload compilation pipeline, since
|
||||
// LLVM will initialize them for us if it sees gpu kernels being registered.
|
||||
pub init_rtls: &'ll llvm::Value,
|
||||
}
|
||||
|
||||
|
|
@ -44,15 +42,6 @@ impl<'ll> OffloadGlobals<'ll> {
|
|||
let (begin_mapper, _, end_mapper, mapper_fn_ty) = gen_tgt_data_mappers(cx);
|
||||
let ident_t_global = generate_at_one(cx);
|
||||
|
||||
let tptr = cx.type_ptr();
|
||||
let ti32 = cx.type_i32();
|
||||
let tgt_bin_desc_ty = vec![ti32, tptr, tptr, tptr];
|
||||
let bin_desc = cx.type_named_struct("struct.__tgt_bin_desc");
|
||||
cx.set_struct_body(bin_desc, &tgt_bin_desc_ty, false);
|
||||
|
||||
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
|
||||
let register_lib = declare_offload_fn(&cx, "__tgt_register_lib", reg_lib_decl);
|
||||
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
|
||||
let init_ty = cx.type_func(&[], cx.type_void());
|
||||
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
|
||||
|
||||
|
|
@ -63,20 +52,84 @@ impl<'ll> OffloadGlobals<'ll> {
|
|||
OffloadGlobals {
|
||||
launcher_fn,
|
||||
launcher_ty,
|
||||
bin_desc,
|
||||
kernel_args_ty,
|
||||
offload_entry_ty,
|
||||
begin_mapper,
|
||||
end_mapper,
|
||||
mapper_fn_ty,
|
||||
ident_t_global,
|
||||
register_lib,
|
||||
unregister_lib,
|
||||
init_rtls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We need to register offload before using it. We also should unregister it once we are done, for
|
||||
// good measures. Previously we have done so before and after each individual offload intrinsic
|
||||
// call, but that comes at a performance cost. The repeated (un)register calls might also confuse
|
||||
// the LLVM ompOpt pass, which tries to move operations to a better location. The easiest solution,
|
||||
// which we copy from clang, is to just have those two calls once, in the global ctor/dtor section
|
||||
// of the final binary.
|
||||
pub(crate) fn register_offload<'ll>(cx: &CodegenCx<'ll, '_>) {
|
||||
// First we check quickly whether we already have done our setup, in which case we return early.
|
||||
// Shouldn't be needed for correctness.
|
||||
let register_lib_name = "__tgt_register_lib";
|
||||
if cx.get_function(register_lib_name).is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void());
|
||||
let register_lib = declare_offload_fn(&cx, register_lib_name, reg_lib_decl);
|
||||
let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl);
|
||||
|
||||
let ptr_null = cx.const_null(cx.type_ptr());
|
||||
let const_struct = cx.const_struct(&[cx.get_const_i32(0), ptr_null, ptr_null, ptr_null], false);
|
||||
let omp_descriptor =
|
||||
add_global(cx, ".omp_offloading.descriptor", const_struct, InternalLinkage);
|
||||
// @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries }
|
||||
// @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 0, ptr null, ptr null, ptr null }
|
||||
|
||||
let atexit = cx.type_func(&[cx.type_ptr()], cx.type_i32());
|
||||
let atexit_fn = declare_offload_fn(cx, "atexit", atexit);
|
||||
|
||||
let desc_ty = cx.type_func(&[], cx.type_void());
|
||||
let reg_name = ".omp_offloading.descriptor_reg";
|
||||
let unreg_name = ".omp_offloading.descriptor_unreg";
|
||||
let desc_reg_fn = declare_offload_fn(cx, reg_name, desc_ty);
|
||||
let desc_unreg_fn = declare_offload_fn(cx, unreg_name, desc_ty);
|
||||
llvm::set_linkage(desc_reg_fn, InternalLinkage);
|
||||
llvm::set_linkage(desc_unreg_fn, InternalLinkage);
|
||||
llvm::set_section(desc_reg_fn, c".text.startup");
|
||||
llvm::set_section(desc_unreg_fn, c".text.startup");
|
||||
|
||||
// define internal void @.omp_offloading.descriptor_reg() section ".text.startup" {
|
||||
// entry:
|
||||
// call void @__tgt_register_lib(ptr @.omp_offloading.descriptor)
|
||||
// %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg)
|
||||
// ret void
|
||||
// }
|
||||
let bb = Builder::append_block(cx, desc_reg_fn, "entry");
|
||||
let mut a = Builder::build(cx, bb);
|
||||
a.call(reg_lib_decl, None, None, register_lib, &[omp_descriptor], None, None);
|
||||
a.call(atexit, None, None, atexit_fn, &[desc_unreg_fn], None, None);
|
||||
a.ret_void();
|
||||
|
||||
// define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" {
|
||||
// entry:
|
||||
// call void @__tgt_unregister_lib(ptr @.omp_offloading.descriptor)
|
||||
// ret void
|
||||
// }
|
||||
let bb = Builder::append_block(cx, desc_unreg_fn, "entry");
|
||||
let mut a = Builder::build(cx, bb);
|
||||
a.call(reg_lib_decl, None, None, unregister_lib, &[omp_descriptor], None, None);
|
||||
a.ret_void();
|
||||
|
||||
// @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.omp_offloading.descriptor_reg, ptr null }]
|
||||
let args = vec![cx.get_const_i32(101), desc_reg_fn, ptr_null];
|
||||
let const_struct = cx.const_struct(&args, false);
|
||||
let arr = cx.const_array(cx.val_ty(const_struct), &[const_struct]);
|
||||
add_global(cx, "llvm.global_ctors", arr, AppendingLinkage);
|
||||
}
|
||||
|
||||
pub(crate) struct OffloadKernelDims<'ll> {
|
||||
num_workgroups: &'ll Value,
|
||||
threads_per_block: &'ll Value,
|
||||
|
|
@ -487,9 +540,6 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
let tgt_decl = offload_globals.launcher_fn;
|
||||
let tgt_target_kernel_ty = offload_globals.launcher_ty;
|
||||
|
||||
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
|
||||
let tgt_bin_desc = offload_globals.bin_desc;
|
||||
|
||||
let tgt_kernel_decl = offload_globals.kernel_args_ty;
|
||||
let begin_mapper_decl = offload_globals.begin_mapper;
|
||||
let end_mapper_decl = offload_globals.end_mapper;
|
||||
|
|
@ -513,12 +563,9 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
// Step 0)
|
||||
// %struct.__tgt_bin_desc = type { i32, ptr, ptr, ptr }
|
||||
// %6 = alloca %struct.__tgt_bin_desc, align 8
|
||||
unsafe {
|
||||
llvm::LLVMRustPositionBuilderPastAllocas(&builder.llbuilder, builder.llfn());
|
||||
}
|
||||
let tgt_bin_desc_alloca = builder.direct_alloca(tgt_bin_desc, Align::EIGHT, "EmptyDesc");
|
||||
|
||||
let ty = cx.type_array(cx.type_ptr(), num_args);
|
||||
// Baseptr are just the input pointer to the kernel, stored in a local alloca
|
||||
|
|
@ -536,7 +583,6 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
unsafe {
|
||||
llvm::LLVMPositionBuilderAtEnd(&builder.llbuilder, bb);
|
||||
}
|
||||
builder.memset(tgt_bin_desc_alloca, cx.get_const_i8(0), cx.get_const_i64(32), Align::EIGHT);
|
||||
|
||||
// Now we allocate once per function param, a copy to be passed to one of our maps.
|
||||
let mut vals = vec![];
|
||||
|
|
@ -574,15 +620,9 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
geps.push(gep);
|
||||
}
|
||||
|
||||
let mapper_fn_ty = cx.type_func(&[cx.type_ptr()], cx.type_void());
|
||||
let register_lib_decl = offload_globals.register_lib;
|
||||
let unregister_lib_decl = offload_globals.unregister_lib;
|
||||
let init_ty = cx.type_func(&[], cx.type_void());
|
||||
let init_rtls_decl = offload_globals.init_rtls;
|
||||
|
||||
// FIXME(offload): Later we want to add them to the wrapper code, rather than our main function.
|
||||
// call void @__tgt_register_lib(ptr noundef %6)
|
||||
builder.call(mapper_fn_ty, None, None, register_lib_decl, &[tgt_bin_desc_alloca], None, None);
|
||||
// call void @__tgt_init_all_rtls()
|
||||
builder.call(init_ty, None, None, init_rtls_decl, &[], None, None);
|
||||
|
||||
|
|
@ -679,6 +719,4 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>(
|
|||
num_args,
|
||||
s_ident_t,
|
||||
);
|
||||
|
||||
builder.call(mapper_fn_ty, None, None, unregister_lib_decl, &[tgt_bin_desc_alloca], None, None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
pub(crate) fn const_null(&self, t: &'ll Type) -> &'ll Value {
|
||||
unsafe { llvm::LLVMConstNull(t) }
|
||||
}
|
||||
|
||||
pub(crate) fn const_struct(&self, elts: &[&'ll Value], packed: bool) -> &'ll Value {
|
||||
struct_in_context(self.llcx(), elts, packed)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ use tracing::debug;
|
|||
use crate::abi::FnAbiLlvmExt;
|
||||
use crate::builder::Builder;
|
||||
use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
|
||||
use crate::builder::gpu_offload::{OffloadKernelDims, gen_call_handling, gen_define_handling};
|
||||
use crate::builder::gpu_offload::{
|
||||
OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload,
|
||||
};
|
||||
use crate::context::CodegenCx;
|
||||
use crate::declare::declare_raw_fn;
|
||||
use crate::errors::{
|
||||
|
|
@ -1402,6 +1404,7 @@ fn codegen_offload<'ll, 'tcx>(
|
|||
return;
|
||||
}
|
||||
};
|
||||
register_offload(cx);
|
||||
let offload_data = gen_define_handling(&cx, &metadata, target_symbol, offload_globals);
|
||||
gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals, &offload_dims);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1208,10 +1208,23 @@ impl<'a> Linker for EmLinker<'a> {
|
|||
|
||||
fn set_output_kind(
|
||||
&mut self,
|
||||
_output_kind: LinkOutputKind,
|
||||
output_kind: LinkOutputKind,
|
||||
_crate_type: CrateType,
|
||||
_out_filename: &Path,
|
||||
) {
|
||||
match output_kind {
|
||||
LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe => {
|
||||
self.cmd.arg("-sMAIN_MODULE=2");
|
||||
}
|
||||
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
|
||||
self.cmd.arg("-sSIDE_MODULE=2");
|
||||
}
|
||||
// -fno-pie is the default on Emscripten.
|
||||
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {}
|
||||
LinkOutputKind::WasiReactorExe => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ fn process_builtin_attrs(
|
|||
},
|
||||
AttributeKind::FfiConst(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST,
|
||||
AttributeKind::FfiPure(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE,
|
||||
AttributeKind::StdInternalSymbol(_) => {
|
||||
AttributeKind::RustcStdInternalSymbol(_) => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
||||
}
|
||||
AttributeKind::Linkage(linkage, span) => {
|
||||
|
|
@ -217,10 +217,10 @@ fn process_builtin_attrs(
|
|||
AttributeKind::Sanitize { span, .. } => {
|
||||
interesting_spans.sanitize = Some(*span);
|
||||
}
|
||||
AttributeKind::ObjcClass { classname, .. } => {
|
||||
AttributeKind::RustcObjcClass { classname, .. } => {
|
||||
codegen_fn_attrs.objc_class = Some(*classname);
|
||||
}
|
||||
AttributeKind::ObjcSelector { methname, .. } => {
|
||||
AttributeKind::RustcObjcSelector { methname, .. } => {
|
||||
codegen_fn_attrs.objc_selector = Some(*methname);
|
||||
}
|
||||
AttributeKind::EiiForeignItem => {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub fn rustc_allow_const_fn_unstable(
|
|||
) -> bool {
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
|
||||
|
||||
find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms, _) if syms.contains(&feature_gate))
|
||||
find_attr!(attrs, AttributeKind::RustcAllowConstFnUnstable(syms, _) if syms.contains(&feature_gate))
|
||||
}
|
||||
|
||||
/// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
|
||||
|
|
|
|||
178
compiler/rustc_const_eval/src/const_eval/dyn_trait.rs
Normal file
178
compiler/rustc_const_eval/src/const_eval/dyn_trait.rs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult, Scalar, interp_ok};
|
||||
use rustc_middle::ty::{Region, Ty};
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::const_eval::CompileTimeMachine;
|
||||
use crate::interpret::{Immediate, InterpCx, MPlaceTy, MemoryKind, Writeable};
|
||||
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
||||
pub(crate) fn write_dyn_trait_type_info(
|
||||
&mut self,
|
||||
dyn_place: impl Writeable<'tcx, CtfeProvenance>,
|
||||
data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
|
||||
region: Region<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tcx = self.tcx.tcx;
|
||||
|
||||
// Find the principal trait ref (for super trait collection), collect auto traits,
|
||||
// and collect all projection predicates (used when computing TypeId for each supertrait).
|
||||
let mut principal: Option<ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>> = None;
|
||||
let mut auto_traits_def_ids: Vec<ty::Binder<'tcx, DefId>> = Vec::new();
|
||||
let mut projections: Vec<ty::Binder<'tcx, ty::ExistentialProjection<'tcx>>> = Vec::new();
|
||||
|
||||
for b in data.iter() {
|
||||
match b.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(tr) => principal = Some(b.rebind(tr)),
|
||||
ty::ExistentialPredicate::AutoTrait(did) => auto_traits_def_ids.push(b.rebind(did)),
|
||||
ty::ExistentialPredicate::Projection(p) => projections.push(b.rebind(p)),
|
||||
}
|
||||
}
|
||||
|
||||
// This is to make principal dyn type include Trait and projection predicates, excluding auto traits.
|
||||
let principal_ty: Option<Ty<'tcx>> = principal.map(|_tr| {
|
||||
let preds = tcx
|
||||
.mk_poly_existential_predicates_from_iter(data.iter().filter(|b| {
|
||||
!matches!(b.skip_binder(), ty::ExistentialPredicate::AutoTrait(_))
|
||||
}));
|
||||
Ty::new_dynamic(tcx, preds, region)
|
||||
});
|
||||
|
||||
// DynTrait { predicates: &'static [Trait] }
|
||||
for (field_idx, field) in
|
||||
dyn_place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&dyn_place, field_idx)?;
|
||||
match field.name {
|
||||
sym::predicates => {
|
||||
self.write_dyn_trait_predicates_slice(
|
||||
&field_place,
|
||||
principal_ty,
|
||||
&auto_traits_def_ids,
|
||||
region,
|
||||
)?;
|
||||
}
|
||||
other => {
|
||||
span_bug!(self.tcx.def_span(field.did), "unimplemented DynTrait field {other}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn mk_dyn_principal_auto_trait_ty(
|
||||
&self,
|
||||
auto_trait_def_id: ty::Binder<'tcx, DefId>,
|
||||
region: Region<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx.tcx;
|
||||
|
||||
// Preserve the binder vars from the original auto-trait predicate.
|
||||
let pred_inner = ty::ExistentialPredicate::AutoTrait(auto_trait_def_id.skip_binder());
|
||||
let pred = ty::Binder::bind_with_vars(pred_inner, auto_trait_def_id.bound_vars());
|
||||
|
||||
let preds = tcx.mk_poly_existential_predicates_from_iter([pred].into_iter());
|
||||
Ty::new_dynamic(tcx, preds, region)
|
||||
}
|
||||
|
||||
fn write_dyn_trait_predicates_slice(
|
||||
&mut self,
|
||||
slice_place: &impl Writeable<'tcx, CtfeProvenance>,
|
||||
principal_ty: Option<Ty<'tcx>>,
|
||||
auto_trait_def_ids: &[ty::Binder<'tcx, DefId>],
|
||||
region: Region<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tcx = self.tcx.tcx;
|
||||
|
||||
// total entries in DynTrait predicates
|
||||
let total_len = principal_ty.map(|_| 1).unwrap_or(0) + auto_trait_def_ids.len();
|
||||
|
||||
// element type = DynTraitPredicate
|
||||
let slice_ty = slice_place.layout().ty.builtin_deref(false).unwrap(); // [DynTraitPredicate]
|
||||
let elem_ty = slice_ty.sequence_element_type(tcx); // DynTraitPredicate
|
||||
|
||||
let arr_layout = self.layout_of(Ty::new_array(tcx, elem_ty, total_len as u64))?;
|
||||
let arr_place = self.allocate(arr_layout, MemoryKind::Stack)?;
|
||||
let mut elems = self.project_array_fields(&arr_place)?;
|
||||
|
||||
// principal entry (if any) - NOT an auto trait
|
||||
if let Some(principal_ty) = principal_ty {
|
||||
let Some((_i, elem_place)) = elems.next(self)? else {
|
||||
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (principal)");
|
||||
};
|
||||
self.write_dyn_trait_predicate(elem_place, principal_ty, false)?;
|
||||
}
|
||||
|
||||
// auto trait entries - these ARE auto traits
|
||||
for auto in auto_trait_def_ids {
|
||||
let Some((_i, elem_place)) = elems.next(self)? else {
|
||||
span_bug!(self.tcx.span, "DynTrait.predicates length computed wrong (auto)");
|
||||
};
|
||||
let auto_ty = self.mk_dyn_principal_auto_trait_ty(*auto, region);
|
||||
self.write_dyn_trait_predicate(elem_place, auto_ty, true)?;
|
||||
}
|
||||
|
||||
let arr_place = arr_place.map_provenance(CtfeProvenance::as_immutable);
|
||||
let imm = Immediate::new_slice(arr_place.ptr(), total_len as u64, self);
|
||||
self.write_immediate(imm, slice_place)
|
||||
}
|
||||
|
||||
fn write_dyn_trait_predicate(
|
||||
&mut self,
|
||||
predicate_place: MPlaceTy<'tcx>,
|
||||
trait_ty: Ty<'tcx>,
|
||||
is_auto: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
// DynTraitPredicate { trait_ty: Trait }
|
||||
for (field_idx, field) in predicate_place
|
||||
.layout
|
||||
.ty
|
||||
.ty_adt_def()
|
||||
.unwrap()
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&predicate_place, field_idx)?;
|
||||
match field.name {
|
||||
sym::trait_ty => {
|
||||
// Now write the Trait struct
|
||||
self.write_trait(field_place, trait_ty, is_auto)?;
|
||||
}
|
||||
other => {
|
||||
span_bug!(
|
||||
self.tcx.def_span(field.did),
|
||||
"unimplemented DynTraitPredicate field {other}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
fn write_trait(
|
||||
&mut self,
|
||||
trait_place: MPlaceTy<'tcx>,
|
||||
trait_ty: Ty<'tcx>,
|
||||
is_auto: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Trait { ty: TypeId, is_auto: bool }
|
||||
for (field_idx, field) in
|
||||
trait_place.layout.ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
|
||||
{
|
||||
let field_place = self.project_field(&trait_place, field_idx)?;
|
||||
match field.name {
|
||||
sym::ty => {
|
||||
self.write_type_id(trait_ty, &field_place)?;
|
||||
}
|
||||
sym::is_auto => {
|
||||
self.write_scalar(Scalar::from_bool(is_auto), &field_place)?;
|
||||
}
|
||||
other => {
|
||||
span_bug!(self.tcx.def_span(field.did), "unimplemented Trait field {other}")
|
||||
}
|
||||
}
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ use tracing::instrument;
|
|||
use crate::interpret::InterpCx;
|
||||
|
||||
mod dummy_machine;
|
||||
mod dyn_trait;
|
||||
mod error;
|
||||
mod eval_queries;
|
||||
mod fn_queries;
|
||||
|
|
|
|||
|
|
@ -129,13 +129,18 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
|
|||
|
||||
variant
|
||||
}
|
||||
ty::Dynamic(predicates, region) => {
|
||||
let (variant, variant_place) = downcast(sym::DynTrait)?;
|
||||
let dyn_place = self.project_field(&variant_place, FieldIdx::ZERO)?;
|
||||
self.write_dyn_trait_type_info(dyn_place, *predicates, *region)?;
|
||||
variant
|
||||
}
|
||||
ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Pat(_, _)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::UnsafeBinder(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
|
|
|
|||
|
|
@ -27,26 +27,18 @@ mod tests;
|
|||
/// the max/min element of the SCC, or all of the above.
|
||||
///
|
||||
/// Concretely, the both merge operations must commute, e.g. where `merge`
|
||||
/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)`
|
||||
/// is `update_scc` and `update_reached`: `a.merge(b) == b.merge(a)`
|
||||
///
|
||||
/// In general, what you want is probably always min/max according
|
||||
/// to some ordering, potentially with side constraints (min x such
|
||||
/// that P holds).
|
||||
pub trait Annotation: Debug + Copy {
|
||||
/// Merge two existing annotations into one during
|
||||
/// path compression.o
|
||||
fn merge_scc(self, other: Self) -> Self;
|
||||
/// path compression.
|
||||
fn update_scc(&mut self, other: &Self);
|
||||
|
||||
/// Merge a successor into this annotation.
|
||||
fn merge_reached(self, other: Self) -> Self;
|
||||
|
||||
fn update_scc(&mut self, other: Self) {
|
||||
*self = self.merge_scc(other)
|
||||
}
|
||||
|
||||
fn update_reachable(&mut self, other: Self) {
|
||||
*self = self.merge_reached(other)
|
||||
}
|
||||
fn update_reachable(&mut self, other: &Self);
|
||||
}
|
||||
|
||||
/// An accumulator for annotations.
|
||||
|
|
@ -70,12 +62,8 @@ impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
|
|||
|
||||
/// The empty annotation, which does nothing.
|
||||
impl Annotation for () {
|
||||
fn merge_reached(self, _other: Self) -> Self {
|
||||
()
|
||||
}
|
||||
fn merge_scc(self, _other: Self) -> Self {
|
||||
()
|
||||
}
|
||||
fn update_reachable(&mut self, _other: &Self) {}
|
||||
fn update_scc(&mut self, _other: &Self) {}
|
||||
}
|
||||
|
||||
/// Strongly connected components (SCC) of a graph. The type `N` is
|
||||
|
|
@ -614,7 +602,7 @@ where
|
|||
*min_depth = successor_min_depth;
|
||||
*min_cycle_root = successor_node;
|
||||
}
|
||||
current_component_annotation.update_scc(successor_annotation);
|
||||
current_component_annotation.update_scc(&successor_annotation);
|
||||
}
|
||||
// The starting node `node` is succeeded by a fully identified SCC
|
||||
// which is now added to the set under `scc_index`.
|
||||
|
|
@ -629,7 +617,7 @@ where
|
|||
// the `successors_stack` for later.
|
||||
trace!(?node, ?successor_scc_index);
|
||||
successors_stack.push(successor_scc_index);
|
||||
current_component_annotation.update_reachable(successor_annotation);
|
||||
current_component_annotation.update_reachable(&successor_annotation);
|
||||
}
|
||||
// `node` has no more (direct) successors; search recursively.
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ impl Maxes {
|
|||
}
|
||||
|
||||
impl Annotation for MaxReached {
|
||||
fn merge_scc(self, other: Self) -> Self {
|
||||
Self(std::cmp::max(other.0, self.0))
|
||||
fn update_scc(&mut self, other: &Self) {
|
||||
self.0 = self.0.max(other.0);
|
||||
}
|
||||
|
||||
fn merge_reached(self, other: Self) -> Self {
|
||||
Self(std::cmp::max(other.0, self.0))
|
||||
fn update_reachable(&mut self, other: &Self) {
|
||||
self.0 = self.0.max(other.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,13 +75,12 @@ impl Annotations<usize> for MinMaxes {
|
|||
}
|
||||
|
||||
impl Annotation for MinMaxIn {
|
||||
fn merge_scc(self, other: Self) -> Self {
|
||||
Self { min: std::cmp::min(self.min, other.min), max: std::cmp::max(self.max, other.max) }
|
||||
fn update_scc(&mut self, other: &Self) {
|
||||
self.min = self.min.min(other.min);
|
||||
self.max = self.max.max(other.max);
|
||||
}
|
||||
|
||||
fn merge_reached(self, _other: Self) -> Self {
|
||||
self
|
||||
}
|
||||
fn update_reachable(&mut self, _other: &Self) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -963,13 +963,16 @@ impl SyntaxExtension {
|
|||
let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
|
||||
|
||||
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
|
||||
if let Some(sp) = find_attr!(attrs, AttributeKind::ConstStability { span, .. } => *span) {
|
||||
if let Some(sp) =
|
||||
find_attr!(attrs, AttributeKind::RustcConstStability { span, .. } => *span)
|
||||
{
|
||||
sess.dcx().emit_err(errors::MacroConstStability {
|
||||
span: sp,
|
||||
head_span: sess.source_map().guess_head_span(span),
|
||||
});
|
||||
}
|
||||
if let Some(sp) = find_attr!(attrs, AttributeKind::BodyStability{ span, .. } => *span) {
|
||||
if let Some(sp) = find_attr!(attrs, AttributeKind::RustcBodyStability{ span, .. } => *span)
|
||||
{
|
||||
sess.dcx().emit_err(errors::MacroBodyStability {
|
||||
span: sp,
|
||||
head_span: sess.source_map().guess_head_span(span),
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ pub fn compile_declarative_macro(
|
|||
}
|
||||
assert!(!kinds.is_empty());
|
||||
|
||||
let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
|
||||
let transparency = find_attr!(attrs, AttributeKind::RustcMacroTransparency(x) => *x)
|
||||
.unwrap_or(Transparency::fallback(macro_rules));
|
||||
|
||||
if let Some(guar) = guar {
|
||||
|
|
|
|||
|
|
@ -746,31 +746,15 @@ pub enum AttributeKind {
|
|||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
Align { align: Align, span: Span },
|
||||
|
||||
/// Represents `#[rustc_allow_const_fn_unstable]`.
|
||||
AllowConstFnUnstable(ThinVec<Symbol>, Span),
|
||||
|
||||
/// Represents `#[rustc_allow_incoherent_impl]`.
|
||||
AllowIncoherentImpl(Span),
|
||||
|
||||
/// Represents `#[allow_internal_unsafe]`.
|
||||
AllowInternalUnsafe(Span),
|
||||
|
||||
/// Represents `#[allow_internal_unstable]`.
|
||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
|
||||
|
||||
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
|
||||
AsPtr(Span),
|
||||
|
||||
/// Represents `#[automatically_derived]`
|
||||
AutomaticallyDerived(Span),
|
||||
|
||||
/// Represents `#[rustc_default_body_unstable]`.
|
||||
BodyStability {
|
||||
stability: DefaultBodyStability,
|
||||
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents the trace attribute of `#[cfg_attr]`
|
||||
CfgAttrTrace,
|
||||
|
||||
|
|
@ -780,9 +764,6 @@ pub enum AttributeKind {
|
|||
/// Represents `#[cfi_encoding]`
|
||||
CfiEncoding { encoding: Symbol },
|
||||
|
||||
/// Represents `#[rustc_coinductive]`.
|
||||
Coinductive(Span),
|
||||
|
||||
/// Represents `#[cold]`.
|
||||
Cold(Span),
|
||||
|
||||
|
|
@ -792,26 +773,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[compiler_builtins]`.
|
||||
CompilerBuiltins,
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
Confusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
// FIXME(jdonszelmann): remove when target validation code is moved
|
||||
first_span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[const_continue]`.
|
||||
ConstContinue(Span),
|
||||
|
||||
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
|
||||
ConstStability {
|
||||
stability: PartialConstStability,
|
||||
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable_indirect]`.
|
||||
ConstStabilityIndirect,
|
||||
|
||||
/// Represents `#[coroutine]`.
|
||||
Coroutine(Span),
|
||||
|
||||
|
|
@ -830,9 +794,6 @@ pub enum AttributeKind {
|
|||
/// Represents `#[debugger_visualizer]`.
|
||||
DebuggerVisualizer(ThinVec<DebugVisualizer>),
|
||||
|
||||
/// Represents `#[rustc_deny_explicit_impl]`.
|
||||
DenyExplicitImpl(Span),
|
||||
|
||||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
Deprecation { deprecation: Deprecation, span: Span },
|
||||
|
||||
|
|
@ -848,12 +809,6 @@ pub enum AttributeKind {
|
|||
/// i.e. doc comments.
|
||||
DocComment { style: AttrStyle, kind: DocFragmentKind, span: Span, comment: Symbol },
|
||||
|
||||
/// Represents `#[rustc_dummy]`.
|
||||
Dummy,
|
||||
|
||||
/// Represents `#[rustc_dyn_incompatible_trait]`.
|
||||
DynIncompatibleTrait(Span),
|
||||
|
||||
/// Implementation detail of `#[eii]`
|
||||
EiiDeclaration(EiiDecl),
|
||||
|
||||
|
|
@ -920,9 +875,6 @@ pub enum AttributeKind {
|
|||
/// Represents [`#[macro_export]`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path).
|
||||
MacroExport { span: Span, local_inner_macros: bool },
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
/// Represents `#[macro_use]`.
|
||||
MacroUse { span: Span, arguments: MacroUseArgs },
|
||||
|
||||
|
|
@ -978,24 +930,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[non_exhaustive]`
|
||||
NonExhaustive(Span),
|
||||
|
||||
/// Represents `#[rustc_objc_class]`
|
||||
ObjcClass { classname: Symbol, span: Span },
|
||||
|
||||
/// Represents `#[rustc_objc_selector]`
|
||||
ObjcSelector { methname: Symbol, span: Span },
|
||||
|
||||
/// Represents `#[optimize(size|speed)]`
|
||||
Optimize(OptimizeAttr, Span),
|
||||
|
||||
/// Represents `#[panic_runtime]`
|
||||
PanicRuntime,
|
||||
|
||||
/// Represents `#[rustc_paren_sugar]`.
|
||||
ParenSugar(Span),
|
||||
|
||||
/// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
|
||||
PassByValue(Span),
|
||||
|
||||
/// Represents `#[patchable_function_entry]`
|
||||
PatchableFunctionEntry { prefix: u8, entry: u8 },
|
||||
|
||||
|
|
@ -1023,9 +963,6 @@ pub enum AttributeKind {
|
|||
/// Represents `#[profiler_runtime]`
|
||||
ProfilerRuntime,
|
||||
|
||||
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
|
||||
PubTransparent(Span),
|
||||
|
||||
/// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
|
||||
RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
|
|
@ -1041,15 +978,55 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_allocator_zeroed_variant]`
|
||||
RustcAllocatorZeroedVariant { name: Symbol },
|
||||
|
||||
/// Represents `#[rustc_allow_const_fn_unstable]`.
|
||||
RustcAllowConstFnUnstable(ThinVec<Symbol>, Span),
|
||||
|
||||
/// Represents `#[rustc_allow_incoherent_impl]`.
|
||||
RustcAllowIncoherentImpl(Span),
|
||||
|
||||
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
|
||||
RustcAsPtr(Span),
|
||||
|
||||
/// Represents `#[rustc_default_body_unstable]`.
|
||||
RustcBodyStability {
|
||||
stability: DefaultBodyStability,
|
||||
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
/// Represents `#[rustc_builtin_macro]`.
|
||||
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
|
||||
|
||||
/// Represents `#[rustc_coherence_is_core]`
|
||||
RustcCoherenceIsCore(Span),
|
||||
|
||||
/// Represents `#[rustc_coinductive]`.
|
||||
RustcCoinductive(Span),
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
RustcConfusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
// FIXME(jdonszelmann): remove when target validation code is moved
|
||||
first_span: Span,
|
||||
},
|
||||
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
|
||||
RustcConstStability {
|
||||
stability: PartialConstStability,
|
||||
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable_indirect]`.
|
||||
RustcConstStabilityIndirect,
|
||||
|
||||
/// Represents `#[rustc_deallocator]`
|
||||
RustcDeallocator,
|
||||
|
||||
/// Represents `#[rustc_deny_explicit_impl]`.
|
||||
RustcDenyExplicitImpl(Span),
|
||||
|
||||
/// Represents `#[rustc_dummy]`.
|
||||
RustcDummy,
|
||||
|
||||
/// Represents `#[rustc_dump_def_parents]`
|
||||
RustcDumpDefParents,
|
||||
|
||||
|
|
@ -1065,6 +1042,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_dump_vtable]`
|
||||
RustcDumpVtable(Span),
|
||||
|
||||
/// Represents `#[rustc_dyn_incompatible_trait]`.
|
||||
RustcDynIncompatibleTrait(Span),
|
||||
|
||||
/// Represents `#[rustc_has_incoherent_inherent_impls]`
|
||||
RustcHasIncoherentInherentImpls,
|
||||
|
||||
|
|
@ -1089,6 +1069,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_lint_untracked_query_information]`
|
||||
RustcLintUntrackedQueryInformation,
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
RustcMacroTransparency(Transparency),
|
||||
|
||||
/// Represents `#[rustc_main]`.
|
||||
RustcMain,
|
||||
|
||||
|
|
@ -1104,15 +1087,30 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_nounwind]`
|
||||
RustcNounwind,
|
||||
|
||||
/// Represents `#[rustc_objc_class]`
|
||||
RustcObjcClass { classname: Symbol, span: Span },
|
||||
|
||||
/// Represents `#[rustc_objc_selector]`
|
||||
RustcObjcSelector { methname: Symbol, span: Span },
|
||||
|
||||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
/// Represents `#[rustc_offload_kernel]`
|
||||
RustcOffloadKernel,
|
||||
|
||||
/// Represents `#[rustc_paren_sugar]`.
|
||||
RustcParenSugar(Span),
|
||||
|
||||
/// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
|
||||
RustcPassByValue(Span),
|
||||
|
||||
/// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]`
|
||||
RustcPassIndirectlyInNonRusticAbis(Span),
|
||||
|
||||
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
|
||||
RustcPubTransparent(Span),
|
||||
|
||||
/// Represents `#[rustc_reallocator]`
|
||||
RustcReallocator,
|
||||
|
||||
|
|
@ -1130,6 +1128,18 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
|
||||
RustcSimdMonomorphizeLaneLimit(Limit),
|
||||
|
||||
/// Represents `#[rustc_skip_during_method_dispatch]`.
|
||||
RustcSkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
|
||||
|
||||
/// Represents `#[rustc_specialization_trait]`.
|
||||
RustcSpecializationTrait(Span),
|
||||
|
||||
/// Represents `#[rustc_std_internal_symbol]`.
|
||||
RustcStdInternalSymbol(Span),
|
||||
|
||||
/// Represents `#[rustc_unsafe_specialization_marker]`.
|
||||
RustcUnsafeSpecializationMarker(Span),
|
||||
|
||||
/// Represents `#[rustc_variance]`
|
||||
RustcVariance,
|
||||
|
||||
|
|
@ -1151,22 +1161,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[should_panic]`
|
||||
ShouldPanic { reason: Option<Symbol>, span: Span },
|
||||
|
||||
/// Represents `#[rustc_skip_during_method_dispatch]`.
|
||||
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
|
||||
|
||||
/// Represents `#[rustc_specialization_trait]`.
|
||||
SpecializationTrait(Span),
|
||||
|
||||
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
|
||||
Stability {
|
||||
stability: Stability,
|
||||
/// Span of the attribute.
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_std_internal_symbol]`.
|
||||
StdInternalSymbol(Span),
|
||||
|
||||
/// Represents `#[target_feature(enable = "...")]` and
|
||||
/// `#[unsafe(force_target_feature(enable = "...")]`.
|
||||
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
|
||||
|
|
@ -1183,9 +1183,6 @@ pub enum AttributeKind {
|
|||
/// Represents `#[type_length_limit]`
|
||||
TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
/// Represents `#[rustc_unsafe_specialization_marker]`.
|
||||
UnsafeSpecializationMarker(Span),
|
||||
|
||||
/// Represents `#[unstable_feature_bound]`.
|
||||
UnstableFeatureBound(ThinVec<(Symbol, Span)>),
|
||||
|
||||
|
|
|
|||
|
|
@ -19,37 +19,26 @@ impl AttributeKind {
|
|||
match self {
|
||||
// tidy-alphabetical-start
|
||||
Align { .. } => No,
|
||||
AllowConstFnUnstable(..) => No,
|
||||
AllowIncoherentImpl(..) => No,
|
||||
AllowInternalUnsafe(..) => Yes,
|
||||
AllowInternalUnstable(..) => Yes,
|
||||
AsPtr(..) => Yes,
|
||||
AutomaticallyDerived(..) => Yes,
|
||||
BodyStability { .. } => No,
|
||||
CfgAttrTrace => Yes,
|
||||
CfgTrace(..) => Yes,
|
||||
CfiEncoding { .. } => Yes,
|
||||
Coinductive(..) => No,
|
||||
Cold(..) => No,
|
||||
CollapseDebugInfo(..) => Yes,
|
||||
CompilerBuiltins => No,
|
||||
Confusables { .. } => Yes,
|
||||
ConstContinue(..) => No,
|
||||
ConstStability { .. } => Yes,
|
||||
ConstStabilityIndirect => No,
|
||||
Coroutine(..) => No,
|
||||
Coverage(..) => No,
|
||||
CrateName { .. } => No,
|
||||
CrateType(_) => No,
|
||||
CustomMir(_, _, _) => Yes,
|
||||
DebuggerVisualizer(..) => No,
|
||||
DenyExplicitImpl(..) => No,
|
||||
Deprecation { .. } => Yes,
|
||||
DoNotRecommend { .. } => Yes,
|
||||
Doc(_) => Yes,
|
||||
DocComment { .. } => Yes,
|
||||
Dummy => No,
|
||||
DynIncompatibleTrait(..) => No,
|
||||
EiiDeclaration(_) => Yes,
|
||||
EiiForeignItem => No,
|
||||
EiiImpls(..) => No,
|
||||
|
|
@ -69,7 +58,6 @@ impl AttributeKind {
|
|||
LoopMatch(..) => No,
|
||||
MacroEscape(..) => No,
|
||||
MacroExport { .. } => Yes,
|
||||
MacroTransparency(..) => Yes,
|
||||
MacroUse { .. } => No,
|
||||
Marker(..) => No,
|
||||
MayDangle(..) => No,
|
||||
|
|
@ -87,12 +75,8 @@ impl AttributeKind {
|
|||
NoMangle(..) => Yes, // Needed for rustdoc
|
||||
NoStd(..) => No,
|
||||
NonExhaustive(..) => Yes, // Needed for rustdoc
|
||||
ObjcClass { .. } => No,
|
||||
ObjcSelector { .. } => No,
|
||||
Optimize(..) => No,
|
||||
PanicRuntime => No,
|
||||
ParenSugar(..) => No,
|
||||
PassByValue(..) => Yes,
|
||||
PatchableFunctionEntry { .. } => Yes,
|
||||
Path(..) => No,
|
||||
PatternComplexityLimit { .. } => No,
|
||||
|
|
@ -102,20 +86,30 @@ impl AttributeKind {
|
|||
ProcMacroAttribute(..) => No,
|
||||
ProcMacroDerive { .. } => No,
|
||||
ProfilerRuntime => No,
|
||||
PubTransparent(..) => Yes,
|
||||
RecursionLimit { .. } => No,
|
||||
Repr { .. } => No,
|
||||
RustcAllocator => No,
|
||||
RustcAllocatorZeroed => No,
|
||||
RustcAllocatorZeroedVariant { .. } => Yes,
|
||||
RustcAllowConstFnUnstable(..) => No,
|
||||
RustcAllowIncoherentImpl(..) => No,
|
||||
RustcAsPtr(..) => Yes,
|
||||
RustcBodyStability { .. } => No,
|
||||
RustcBuiltinMacro { .. } => Yes,
|
||||
RustcCoherenceIsCore(..) => No,
|
||||
RustcCoinductive(..) => No,
|
||||
RustcConfusables { .. } => Yes,
|
||||
RustcConstStability { .. } => Yes,
|
||||
RustcConstStabilityIndirect => No,
|
||||
RustcDeallocator => No,
|
||||
RustcDenyExplicitImpl(..) => No,
|
||||
RustcDummy => No,
|
||||
RustcDumpDefParents => No,
|
||||
RustcDumpItemBounds => No,
|
||||
RustcDumpPredicates => No,
|
||||
RustcDumpUserArgs => No,
|
||||
RustcDumpVtable(..) => No,
|
||||
RustcDynIncompatibleTrait(..) => No,
|
||||
RustcHasIncoherentInherentImpls => Yes,
|
||||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
|
|
@ -124,32 +118,38 @@ impl AttributeKind {
|
|||
RustcLintOptTy => Yes,
|
||||
RustcLintQueryInstability => Yes,
|
||||
RustcLintUntrackedQueryInformation => Yes,
|
||||
RustcMacroTransparency(..) => Yes,
|
||||
RustcMain => No,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
RustcNounwind => No,
|
||||
RustcObjcClass { .. } => No,
|
||||
RustcObjcSelector { .. } => No,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
RustcOffloadKernel => Yes,
|
||||
RustcParenSugar(..) => No,
|
||||
RustcPassByValue(..) => Yes,
|
||||
RustcPassIndirectlyInNonRusticAbis(..) => No,
|
||||
RustcPubTransparent(..) => Yes,
|
||||
RustcReallocator => No,
|
||||
RustcScalableVector { .. } => Yes,
|
||||
RustcShouldNotBeCalledOnConstItems(..) => Yes,
|
||||
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
|
||||
RustcSkipDuringMethodDispatch { .. } => No,
|
||||
RustcSpecializationTrait(..) => No,
|
||||
RustcStdInternalSymbol(..) => No,
|
||||
RustcUnsafeSpecializationMarker(..) => No,
|
||||
RustcVariance => No,
|
||||
RustcVarianceOfOpaques => No,
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
SkipDuringMethodDispatch { .. } => No,
|
||||
SpecializationTrait(..) => No,
|
||||
Stability { .. } => Yes,
|
||||
StdInternalSymbol(..) => No,
|
||||
TargetFeature { .. } => No,
|
||||
ThreadLocal => No,
|
||||
TrackCaller(..) => Yes,
|
||||
TypeConst(..) => Yes,
|
||||
TypeLengthLimit { .. } => No,
|
||||
UnsafeSpecializationMarker(..) => No,
|
||||
UnstableFeatureBound(..) => No,
|
||||
Used { .. } => No,
|
||||
WindowsSubsystem(..) => No,
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
|
|||
hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
.note = parent implementation is in crate `{$cname}`
|
||||
|
||||
hir_analysis_impl_unpin_for_pin_projected_type = explicit impls for the `Unpin` trait are not permitted for structurally pinned types
|
||||
.label = impl of `Unpin` not allowed
|
||||
.help = `{$adt_name}` is structurally pinned because it is marked as `#[pin_v2]`
|
||||
|
||||
hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
|
||||
.label = impl requires at least one non-auto trait
|
||||
.note = define and implement a new trait or type instead
|
||||
|
|
|
|||
|
|
@ -1701,7 +1701,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
|||
ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),
|
||||
ty::Adt(def, args) => {
|
||||
if !def.did().is_local()
|
||||
&& !find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::PubTransparent(_))
|
||||
&& !find_attr!(
|
||||
tcx.get_all_attrs(def.did()),
|
||||
AttributeKind::RustcPubTransparent(_)
|
||||
)
|
||||
{
|
||||
let non_exhaustive = def.is_variant_list_non_exhaustive()
|
||||
|| def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);
|
||||
|
|
|
|||
|
|
@ -592,7 +592,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||
ty,
|
||||
Ty::new_placeholder(
|
||||
tcx,
|
||||
ty::Placeholder::new(
|
||||
ty::PlaceholderType::new(
|
||||
universe,
|
||||
ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
|
||||
),
|
||||
|
|
@ -2551,7 +2551,7 @@ fn param_env_with_gat_bounds<'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
|
||||
let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind<'tcx>; 8]> =
|
||||
smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).own_params.len());
|
||||
// Extend the impl's identity args with late-bound GAT vars
|
||||
let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
|
||||
|
|
@ -2587,7 +2587,7 @@ fn param_env_with_gat_bounds<'tcx>(
|
|||
ty::Const::new_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundConst { var: ty::BoundVar::from_usize(bound_vars.len() - 1) },
|
||||
ty::BoundConst::new(ty::BoundVar::from_usize(bound_vars.len() - 1)),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ pub(super) fn check_trait<'tcx>(
|
|||
checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
|
||||
checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?;
|
||||
checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
|
||||
checker.check(lang_items.unpin_trait(), visit_implementation_of_unpin)?;
|
||||
checker.check(lang_items.const_param_ty_trait(), |checker| {
|
||||
visit_implementation_of_const_param_ty(checker)
|
||||
})?;
|
||||
|
|
@ -134,6 +135,41 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_implementation_of_unpin(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = checker.tcx;
|
||||
let impl_header = checker.impl_header;
|
||||
let impl_did = checker.impl_def_id;
|
||||
debug!("visit_implementation_of_unpin: impl_did={:?}", impl_did);
|
||||
|
||||
let self_type = impl_header.trait_ref.instantiate_identity().self_ty();
|
||||
debug!("visit_implementation_of_unpin: self_type={:?}", self_type);
|
||||
|
||||
let span = tcx.def_span(impl_did);
|
||||
|
||||
if tcx.features().pin_ergonomics() {
|
||||
match self_type.kind() {
|
||||
// Soundness concerns: a type `T` annotated with `#[pin_v2]` is allowed to project
|
||||
// `Pin<&mut T>` to its field `Pin<&mut U>` safely (even if `U: !Unpin`).
|
||||
// If `T` is allowed to impl `Unpin` manually (note that `Unpin` is a safe trait,
|
||||
// which cannot carry safety properties), then `&mut U` could be obtained from
|
||||
// `&mut T` that dereferenced by `Pin<&mut T>`, which breaks the safety contract of
|
||||
// `Pin<&mut U>` for `U: !Unpin`.
|
||||
ty::Adt(adt, _) if adt.is_pin_project() => {
|
||||
return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType {
|
||||
span,
|
||||
adt_span: tcx.def_span(adt.did()),
|
||||
adt_name: tcx.item_name(adt.did()),
|
||||
}));
|
||||
}
|
||||
ty::Adt(_, _) => {}
|
||||
_ => {
|
||||
return Err(tcx.dcx().span_delayed_bug(span, "impl of `Unpin` for a non-adt type"));
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
let tcx = checker.tcx;
|
||||
let header = checker.impl_header;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
for &impl_item in items {
|
||||
if !find_attr!(
|
||||
self.tcx.get_all_attrs(impl_item),
|
||||
AttributeKind::AllowIncoherentImpl(_)
|
||||
AttributeKind::RustcAllowIncoherentImpl(_)
|
||||
) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
|
||||
|
|
@ -125,7 +125,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
for &impl_item in items {
|
||||
if !find_attr!(
|
||||
self.tcx.get_all_attrs(impl_item),
|
||||
AttributeKind::AllowIncoherentImpl(_)
|
||||
AttributeKind::RustcAllowIncoherentImpl(_)
|
||||
) {
|
||||
let span = self.tcx.def_span(impl_def_id);
|
||||
return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
|
||||
let attrs = tcx.get_all_attrs(def_id);
|
||||
|
||||
let paren_sugar = find_attr!(attrs, AttributeKind::ParenSugar(_));
|
||||
let paren_sugar = find_attr!(attrs, AttributeKind::RustcParenSugar(_));
|
||||
if paren_sugar && !tcx.features().unboxed_closures() {
|
||||
tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
|
||||
}
|
||||
|
|
@ -897,22 +897,23 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
// Only regular traits can be marker.
|
||||
let is_marker = !is_alias && find_attr!(attrs, AttributeKind::Marker(_));
|
||||
|
||||
let rustc_coinductive = find_attr!(attrs, AttributeKind::Coinductive(_));
|
||||
let rustc_coinductive = find_attr!(attrs, AttributeKind::RustcCoinductive(_));
|
||||
let is_fundamental = find_attr!(attrs, AttributeKind::Fundamental);
|
||||
|
||||
let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!(
|
||||
attrs,
|
||||
AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: _ } => [*array, *boxed_slice]
|
||||
AttributeKind::RustcSkipDuringMethodDispatch { array, boxed_slice, span: _ } => [*array, *boxed_slice]
|
||||
)
|
||||
.unwrap_or([false; 2]);
|
||||
|
||||
let specialization_kind = if find_attr!(attrs, AttributeKind::UnsafeSpecializationMarker(_)) {
|
||||
ty::trait_def::TraitSpecializationKind::Marker
|
||||
} else if find_attr!(attrs, AttributeKind::SpecializationTrait(_)) {
|
||||
ty::trait_def::TraitSpecializationKind::AlwaysApplicable
|
||||
} else {
|
||||
ty::trait_def::TraitSpecializationKind::None
|
||||
};
|
||||
let specialization_kind =
|
||||
if find_attr!(attrs, AttributeKind::RustcUnsafeSpecializationMarker(_)) {
|
||||
ty::trait_def::TraitSpecializationKind::Marker
|
||||
} else if find_attr!(attrs, AttributeKind::RustcSpecializationTrait(_)) {
|
||||
ty::trait_def::TraitSpecializationKind::AlwaysApplicable
|
||||
} else {
|
||||
ty::trait_def::TraitSpecializationKind::None
|
||||
};
|
||||
|
||||
let must_implement_one_of = find_attr!(
|
||||
attrs,
|
||||
|
|
@ -923,9 +924,9 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
.collect::<Box<[_]>>()
|
||||
);
|
||||
|
||||
let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
|
||||
let deny_explicit_impl = find_attr!(attrs, AttributeKind::RustcDenyExplicitImpl(_));
|
||||
let force_dyn_incompatible =
|
||||
find_attr!(attrs, AttributeKind::DynIncompatibleTrait(span) => *span);
|
||||
find_attr!(attrs, AttributeKind::RustcDynIncompatibleTrait(span) => *span);
|
||||
|
||||
ty::TraitDef {
|
||||
def_id: def_id.to_def_id(),
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ struct MapAndCompressBoundVars<'tcx> {
|
|||
binder: ty::DebruijnIndex,
|
||||
/// List of bound vars that remain unsubstituted because they were not
|
||||
/// mentioned in the GAT's args.
|
||||
still_bound_vars: Vec<ty::BoundVariableKind>,
|
||||
still_bound_vars: Vec<ty::BoundVariableKind<'tcx>>,
|
||||
/// Subtle invariant: If the `GenericArg` is bound, then it should be
|
||||
/// stored with the debruijn index of `INNERMOST` so it can be shifted
|
||||
/// correctly during substitution.
|
||||
|
|
@ -330,7 +330,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
|
|||
} else {
|
||||
let var = ty::BoundVar::from_usize(self.still_bound_vars.len());
|
||||
self.still_bound_vars.push(ty::BoundVariableKind::Const);
|
||||
let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst { var });
|
||||
let mapped =
|
||||
ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst::new(var));
|
||||
self.mapping.insert(old_bound.var, mapped.into());
|
||||
mapped
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ impl ResolvedArg {
|
|||
|
||||
struct BoundVarContext<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
rbv: &'a mut ResolveBoundVars,
|
||||
rbv: &'a mut ResolveBoundVars<'tcx>,
|
||||
disambiguator: &'a mut DisambiguatorState,
|
||||
scope: ScopeRef<'a>,
|
||||
scope: ScopeRef<'a, 'tcx>,
|
||||
opaque_capture_errors: RefCell<Option<OpaqueHigherRankedLifetimeCaptureErrors>>,
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ struct OpaqueHigherRankedLifetimeCaptureErrors {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Scope<'a> {
|
||||
enum Scope<'a, 'tcx> {
|
||||
/// Declares lifetimes, and each can be early-bound or late-bound.
|
||||
/// The `DebruijnIndex` of late-bound lifetimes starts at `1` and
|
||||
/// it should be shifted by the number of `Binder`s in between the
|
||||
|
|
@ -94,7 +94,7 @@ enum Scope<'a> {
|
|||
/// to append to.
|
||||
hir_id: HirId,
|
||||
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
|
||||
/// If this binder comes from a where clause, specify how it was created.
|
||||
/// This is used to diagnose inaccessible lifetimes in APIT:
|
||||
|
|
@ -110,7 +110,7 @@ enum Scope<'a> {
|
|||
/// e.g., `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`.
|
||||
Body {
|
||||
id: hir::BodyId,
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
},
|
||||
|
||||
/// Use a specific lifetime (if `Some`) or leave it unset (to be
|
||||
|
|
@ -118,7 +118,7 @@ enum Scope<'a> {
|
|||
/// for the default choice of lifetime in a trait object type.
|
||||
ObjectLifetimeDefault {
|
||||
lifetime: Option<ResolvedArg>,
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
},
|
||||
|
||||
/// When we have nested trait refs, we concatenate late bound vars for inner
|
||||
|
|
@ -126,12 +126,12 @@ enum Scope<'a> {
|
|||
/// lifetimes encountered when identifying the trait that an associated type
|
||||
/// is declared on.
|
||||
Supertrait {
|
||||
bound_vars: Vec<ty::BoundVariableKind>,
|
||||
s: ScopeRef<'a>,
|
||||
bound_vars: Vec<ty::BoundVariableKind<'tcx>>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
},
|
||||
|
||||
TraitRefBoundary {
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
},
|
||||
|
||||
/// Remap lifetimes that appear in opaque types to fresh lifetime parameters. Given:
|
||||
|
|
@ -148,7 +148,7 @@ enum Scope<'a> {
|
|||
/// Mapping from each captured lifetime `'a` to the duplicate generic parameter `'b`.
|
||||
captures: &'a RefCell<FxIndexMap<ResolvedArg, LocalDefId>>,
|
||||
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
},
|
||||
|
||||
/// Disallows capturing late-bound vars from parent scopes.
|
||||
|
|
@ -157,7 +157,7 @@ enum Scope<'a> {
|
|||
/// since we don't do something more correct like replacing any captured
|
||||
/// late-bound vars with early-bound params in the const's own generics.
|
||||
LateBoundary {
|
||||
s: ScopeRef<'a>,
|
||||
s: ScopeRef<'a, 'tcx>,
|
||||
what: &'static str,
|
||||
deny_late_regions: bool,
|
||||
},
|
||||
|
|
@ -167,7 +167,7 @@ enum Scope<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
impl<'a, 'tcx> Scope<'a, 'tcx> {
|
||||
// A helper for debugging scopes without printing parent scopes
|
||||
fn debug_truncated(&self) -> impl fmt::Debug {
|
||||
fmt::from_fn(move |f| match self {
|
||||
|
|
@ -227,7 +227,7 @@ enum BinderScopeType {
|
|||
Concatenating,
|
||||
}
|
||||
|
||||
type ScopeRef<'a> = &'a Scope<'a>;
|
||||
type ScopeRef<'a, 'tcx> = &'a Scope<'a, 'tcx>;
|
||||
|
||||
/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
|
@ -253,7 +253,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
/// You should not read the result of this query directly, but rather use
|
||||
/// `named_variable_map`, `late_bound_vars_map`, etc.
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
|
||||
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars<'_> {
|
||||
let mut rbv = ResolveBoundVars::default();
|
||||
let mut visitor = BoundVarContext {
|
||||
tcx,
|
||||
|
|
@ -287,7 +287,7 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
|
|||
rbv
|
||||
}
|
||||
|
||||
fn late_arg_as_bound_arg<'tcx>(param: &GenericParam<'tcx>) -> ty::BoundVariableKind {
|
||||
fn late_arg_as_bound_arg<'tcx>(param: &GenericParam<'tcx>) -> ty::BoundVariableKind<'tcx> {
|
||||
let def_id = param.def_id.to_def_id();
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
|
|
@ -301,7 +301,9 @@ fn late_arg_as_bound_arg<'tcx>(param: &GenericParam<'tcx>) -> ty::BoundVariableK
|
|||
/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only
|
||||
/// be used when turning early-bound vars into late-bound vars when lowering
|
||||
/// return type notation.
|
||||
fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind {
|
||||
fn generic_param_def_as_bound_arg<'tcx>(
|
||||
param: &ty::GenericParamDef,
|
||||
) -> ty::BoundVariableKind<'tcx> {
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => {
|
||||
ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(param.def_id))
|
||||
|
|
@ -329,7 +331,9 @@ fn opaque_captures_all_in_scope_lifetimes<'tcx>(opaque: &'tcx hir::OpaqueTy<'tcx
|
|||
|
||||
impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
/// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
|
||||
fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
|
||||
fn poly_trait_ref_binder_info(
|
||||
&mut self,
|
||||
) -> (Vec<ty::BoundVariableKind<'tcx>>, BinderScopeType) {
|
||||
let mut scope = self.scope;
|
||||
let mut supertrait_bound_vars = vec![];
|
||||
loop {
|
||||
|
|
@ -364,7 +368,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
|
||||
Scope::Binder { hir_id, .. } => {
|
||||
// Nested poly trait refs have the binders concatenated
|
||||
let mut full_binders =
|
||||
let mut full_binders: Vec<ty::BoundVariableKind<'tcx>> =
|
||||
self.rbv.late_bound_vars.get_mut_or_insert_default(hir_id.local_id).clone();
|
||||
full_binders.extend(supertrait_bound_vars);
|
||||
break (full_binders, BinderScopeType::Concatenating);
|
||||
|
|
@ -1094,7 +1098,7 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
|
||||
fn with<F>(&mut self, wrap_scope: Scope<'_, 'tcx>, f: F)
|
||||
where
|
||||
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
|
||||
{
|
||||
|
|
@ -1115,7 +1119,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
*self.opaque_capture_errors.borrow_mut() = this.opaque_capture_errors.into_inner();
|
||||
}
|
||||
|
||||
fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) {
|
||||
fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind<'tcx>>) {
|
||||
if let Some(old) = self.rbv.late_bound_vars.insert(hir_id.local_id, binder) {
|
||||
bug!(
|
||||
"overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}",
|
||||
|
|
@ -1931,7 +1935,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
def_id: DefId,
|
||||
assoc_ident: Ident,
|
||||
assoc_tag: ty::AssocTag,
|
||||
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
|
||||
) -> Option<(Vec<ty::BoundVariableKind<'tcx>>, &'tcx ty::AssocItem)> {
|
||||
let trait_defines_associated_item_named = |trait_def_id: DefId| {
|
||||
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
|
||||
tcx,
|
||||
|
|
@ -1942,7 +1946,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
};
|
||||
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]> =
|
||||
let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind<'tcx>; 8]>); 8]> =
|
||||
smallvec![(def_id, smallvec![])];
|
||||
let mut visited: FxHashSet<DefId> = FxHashSet::default();
|
||||
loop {
|
||||
|
|
|
|||
|
|
@ -1690,3 +1690,14 @@ pub(crate) struct EiiWithGenerics {
|
|||
pub eii_name: Symbol,
|
||||
pub impl_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_impl_unpin_for_pin_projected_type)]
|
||||
pub(crate) struct ImplUnpinForPinProjectedType {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[help]
|
||||
pub adt_span: Span,
|
||||
pub adt_name: Symbol,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
param_ty: Ty<'tcx>,
|
||||
hir_bounds: I,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind<'tcx>>,
|
||||
predicate_filter: PredicateFilter,
|
||||
overlapping_assoc_constraints: OverlappingAsssocItemConstraints,
|
||||
) where
|
||||
|
|
@ -1000,7 +1000,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
|
|||
.delayed_bug(format!("unexpected bound region kind: {:?}", br.kind));
|
||||
return ControlFlow::Break(guar);
|
||||
}
|
||||
ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -2310,7 +2310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => ty::Const::new_bound(
|
||||
tcx,
|
||||
debruijn,
|
||||
ty::BoundConst { var: ty::BoundVar::from_u32(index) },
|
||||
ty::BoundConst::new(ty::BoundVar::from_u32(index)),
|
||||
),
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
|
||||
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id),
|
||||
|
|
@ -3196,8 +3196,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
#[instrument(level = "trace", skip(self, generate_err))]
|
||||
fn validate_late_bound_regions<'cx>(
|
||||
&'cx self,
|
||||
constrained_regions: FxIndexSet<ty::BoundRegionKind>,
|
||||
referenced_regions: FxIndexSet<ty::BoundRegionKind>,
|
||||
constrained_regions: FxIndexSet<ty::BoundRegionKind<'tcx>>,
|
||||
referenced_regions: FxIndexSet<ty::BoundRegionKind<'tcx>>,
|
||||
generate_err: impl Fn(&str) -> Diag<'cx>,
|
||||
) {
|
||||
for br in referenced_regions.difference(&constrained_regions) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, MultiSpan, StashKey, listify, pluralize, struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -50,6 +52,51 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
|
|||
use crate::method::probe::UnsatisfiedPredicates;
|
||||
use crate::{Expectation, FnCtxt};
|
||||
|
||||
/// Tracks trait bounds and detects duplicates between ref and non-ref versions of self types.
|
||||
/// This is used to condense error messages when the same trait bound appears for both
|
||||
/// `T` and `&T` (or `&mut T`).
|
||||
struct TraitBoundDuplicateTracker {
|
||||
trait_def_ids: FxIndexSet<DefId>,
|
||||
seen_ref: FxIndexSet<DefId>,
|
||||
seen_non_ref: FxIndexSet<DefId>,
|
||||
has_ref_dupes: bool,
|
||||
}
|
||||
|
||||
impl TraitBoundDuplicateTracker {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
trait_def_ids: FxIndexSet::default(),
|
||||
seen_ref: FxIndexSet::default(),
|
||||
seen_non_ref: FxIndexSet::default(),
|
||||
has_ref_dupes: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Track a trait bound. `is_ref` indicates whether the self type is a reference.
|
||||
fn track(&mut self, def_id: DefId, is_ref: bool) {
|
||||
self.trait_def_ids.insert(def_id);
|
||||
if is_ref {
|
||||
if self.seen_non_ref.contains(&def_id) {
|
||||
self.has_ref_dupes = true;
|
||||
}
|
||||
self.seen_ref.insert(def_id);
|
||||
} else {
|
||||
if self.seen_ref.contains(&def_id) {
|
||||
self.has_ref_dupes = true;
|
||||
}
|
||||
self.seen_non_ref.insert(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_ref_dupes(&self) -> bool {
|
||||
self.has_ref_dupes
|
||||
}
|
||||
|
||||
fn into_trait_def_ids(self) -> FxIndexSet<DefId> {
|
||||
self.trait_def_ids
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.autoderef(span, ty)
|
||||
|
|
@ -1004,6 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_ident: Ident,
|
||||
item_kind: &str,
|
||||
bound_spans: SortedMap<Span, Vec<String>>,
|
||||
unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>,
|
||||
) {
|
||||
let mut ty_span = match rcvr_ty.kind() {
|
||||
ty::Param(param_type) => {
|
||||
|
|
@ -1012,13 +1060,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::Adt(def, _) if def.did().is_local() => Some(self.tcx.def_span(def.did())),
|
||||
_ => None,
|
||||
};
|
||||
let rcvr_ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
|
||||
let mut tracker = TraitBoundDuplicateTracker::new();
|
||||
for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
|
||||
predicate.kind().skip_binder()
|
||||
&& let self_ty = pred.trait_ref.self_ty()
|
||||
&& self_ty.peel_refs() == rcvr_ty
|
||||
{
|
||||
let is_ref = matches!(self_ty.kind(), ty::Ref(..));
|
||||
tracker.track(pred.trait_ref.def_id, is_ref);
|
||||
}
|
||||
}
|
||||
let has_ref_dupes = tracker.has_ref_dupes();
|
||||
let mut missing_trait_names = tracker
|
||||
.into_trait_def_ids()
|
||||
.into_iter()
|
||||
.map(|def_id| format!("`{}`", self.tcx.def_path_str(def_id)))
|
||||
.collect::<Vec<_>>();
|
||||
missing_trait_names.sort();
|
||||
let should_condense =
|
||||
has_ref_dupes && missing_trait_names.len() > 1 && matches!(rcvr_ty.kind(), ty::Adt(..));
|
||||
let missing_trait_list = if should_condense {
|
||||
Some(match missing_trait_names.as_slice() {
|
||||
[only] => only.clone(),
|
||||
[first, second] => format!("{first} or {second}"),
|
||||
[rest @ .., last] => format!("{} or {last}", rest.join(", ")),
|
||||
[] => String::new(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for (span, mut bounds) in bound_spans {
|
||||
if !self.tcx.sess.source_map().is_span_accessible(span) {
|
||||
continue;
|
||||
}
|
||||
bounds.sort();
|
||||
bounds.dedup();
|
||||
let pre = if Some(span) == ty_span {
|
||||
let is_ty_span = Some(span) == ty_span;
|
||||
if is_ty_span && should_condense {
|
||||
ty_span.take();
|
||||
let label = if let Some(missing_trait_list) = &missing_trait_list {
|
||||
format!(
|
||||
"{item_kind} `{item_ident}` not found for this {} because `{rcvr_ty_str}` doesn't implement {missing_trait_list}",
|
||||
rcvr_ty.prefix_string(self.tcx)
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{item_kind} `{item_ident}` not found for this {}",
|
||||
rcvr_ty.prefix_string(self.tcx)
|
||||
)
|
||||
};
|
||||
err.span_label(span, label);
|
||||
continue;
|
||||
}
|
||||
let pre = if is_ty_span {
|
||||
ty_span.take();
|
||||
format!(
|
||||
"{item_kind} `{item_ident}` not found for this {} because it ",
|
||||
|
|
@ -1248,6 +1344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_ident,
|
||||
item_kind,
|
||||
bound_spans,
|
||||
unsatisfied_predicates,
|
||||
);
|
||||
|
||||
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
|
||||
|
|
@ -1507,6 +1604,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
bound_spans: &mut SortedMap<Span, Vec<String>>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let rcvr_ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
|
||||
let mut type_params = FxIndexMap::default();
|
||||
|
||||
// Pick out the list of unimplemented traits on the receiver.
|
||||
|
|
@ -1798,6 +1896,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
|
||||
spanned_predicates.sort_by_key(|(span, _)| *span);
|
||||
for (_, (primary_spans, span_labels, predicates)) in spanned_predicates {
|
||||
let mut tracker = TraitBoundDuplicateTracker::new();
|
||||
let mut all_trait_bounds_for_rcvr = true;
|
||||
for pred in &predicates {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
let self_ty = pred.trait_ref.self_ty();
|
||||
if self_ty.peel_refs() != rcvr_ty {
|
||||
all_trait_bounds_for_rcvr = false;
|
||||
break;
|
||||
}
|
||||
let is_ref = matches!(self_ty.kind(), ty::Ref(..));
|
||||
tracker.track(pred.trait_ref.def_id, is_ref);
|
||||
}
|
||||
_ => {
|
||||
all_trait_bounds_for_rcvr = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let has_ref_dupes = tracker.has_ref_dupes();
|
||||
let trait_def_ids = tracker.into_trait_def_ids();
|
||||
let mut preds: Vec<_> = predicates
|
||||
.iter()
|
||||
.filter_map(|pred| format_pred(**pred))
|
||||
|
|
@ -1805,7 +1924,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.collect();
|
||||
preds.sort();
|
||||
preds.dedup();
|
||||
let msg = if let [pred] = &preds[..] {
|
||||
let availability_note = if all_trait_bounds_for_rcvr
|
||||
&& has_ref_dupes
|
||||
&& trait_def_ids.len() > 1
|
||||
&& matches!(rcvr_ty.kind(), ty::Adt(..))
|
||||
{
|
||||
let mut trait_names = trait_def_ids
|
||||
.into_iter()
|
||||
.map(|def_id| format!("`{}`", tcx.def_path_str(def_id)))
|
||||
.collect::<Vec<_>>();
|
||||
trait_names.sort();
|
||||
listify(&trait_names, |name| name.to_string()).map(|traits| {
|
||||
format!(
|
||||
"for `{item_ident}` to be available, `{rcvr_ty_str}` must implement {traits}"
|
||||
)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let msg = if let Some(availability_note) = availability_note {
|
||||
availability_note
|
||||
} else if let [pred] = &preds[..] {
|
||||
format!("trait bound {pred} was not satisfied")
|
||||
} else {
|
||||
format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
|
||||
|
|
@ -2103,7 +2242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for inherent_method in
|
||||
self.tcx.associated_items(inherent_impl_did).in_definition_order()
|
||||
{
|
||||
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
|
||||
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::RustcConfusables{symbols, ..} => symbols)
|
||||
&& candidates.contains(&item_name.name)
|
||||
&& inherent_method.is_fn()
|
||||
{
|
||||
|
|
@ -3281,6 +3420,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if we can suggest a derive macro for the unmet trait bound.
|
||||
/// Returns Some(list_of_derives) if possible, or None if not.
|
||||
fn consider_suggesting_derives_for_ty(
|
||||
&self,
|
||||
trait_pred: ty::TraitPredicate<'tcx>,
|
||||
adt: ty::AdtDef<'tcx>,
|
||||
) -> Option<Vec<(String, Span, Symbol)>> {
|
||||
let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?;
|
||||
|
||||
let can_derive = match diagnostic_name {
|
||||
sym::Default
|
||||
| sym::Eq
|
||||
| sym::PartialEq
|
||||
| sym::Ord
|
||||
| sym::PartialOrd
|
||||
| sym::Clone
|
||||
| sym::Copy
|
||||
| sym::Hash
|
||||
| sym::Debug => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !can_derive {
|
||||
return None;
|
||||
}
|
||||
|
||||
let trait_def_id = trait_pred.def_id();
|
||||
let self_ty = trait_pred.self_ty();
|
||||
|
||||
// We need to check if there is already a manual implementation of the trait
|
||||
// for this specific ADT to avoid suggesting `#[derive(..)]` that would conflict.
|
||||
if self.tcx.non_blanket_impls_for_ty(trait_def_id, self_ty).any(|impl_def_id| {
|
||||
self.tcx
|
||||
.type_of(impl_def_id)
|
||||
.instantiate_identity()
|
||||
.ty_adt_def()
|
||||
.is_some_and(|def| def.did() == adt.did())
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut derives = Vec::new();
|
||||
let self_name = self_ty.to_string();
|
||||
let self_span = self.tcx.def_span(adt.did());
|
||||
|
||||
for super_trait in supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref)) {
|
||||
if let Some(parent_diagnostic_name) = self.tcx.get_diagnostic_name(super_trait.def_id())
|
||||
{
|
||||
derives.push((self_name.clone(), self_span, parent_diagnostic_name));
|
||||
}
|
||||
}
|
||||
|
||||
derives.push((self_name, self_span, diagnostic_name));
|
||||
|
||||
Some(derives)
|
||||
}
|
||||
|
||||
fn note_predicate_source_and_get_derives(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -3298,35 +3494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(adt) if adt.did().is_local() => adt,
|
||||
_ => continue,
|
||||
};
|
||||
if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
|
||||
let can_derive = match diagnostic_name {
|
||||
sym::Default
|
||||
| sym::Eq
|
||||
| sym::PartialEq
|
||||
| sym::Ord
|
||||
| sym::PartialOrd
|
||||
| sym::Clone
|
||||
| sym::Copy
|
||||
| sym::Hash
|
||||
| sym::Debug => true,
|
||||
_ => false,
|
||||
};
|
||||
if can_derive {
|
||||
let self_name = trait_pred.self_ty().to_string();
|
||||
let self_span = self.tcx.def_span(adt.did());
|
||||
for super_trait in
|
||||
supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
|
||||
{
|
||||
if let Some(parent_diagnostic_name) =
|
||||
self.tcx.get_diagnostic_name(super_trait.def_id())
|
||||
{
|
||||
derives.push((self_name.clone(), self_span, parent_diagnostic_name));
|
||||
}
|
||||
}
|
||||
derives.push((self_name, self_span, diagnostic_name));
|
||||
} else {
|
||||
traits.push(trait_pred.def_id());
|
||||
}
|
||||
if let Some(new_derives) = self.consider_suggesting_derives_for_ty(trait_pred, adt) {
|
||||
derives.extend(new_derives);
|
||||
} else {
|
||||
traits.push(trait_pred.def_id());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -684,19 +684,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder::new(
|
||||
CanonicalVarKind::PlaceholderTy(ty::PlaceholderType::new(
|
||||
reverse_universe_map[&placeholder.universe],
|
||||
placeholder.bound,
|
||||
))
|
||||
}
|
||||
CanonicalVarKind::PlaceholderRegion(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderRegion(ty::Placeholder::new(
|
||||
CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new(
|
||||
reverse_universe_map[&placeholder.universe],
|
||||
placeholder.bound,
|
||||
))
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::Placeholder::new(
|
||||
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst::new(
|
||||
reverse_universe_map[&placeholder.universe],
|
||||
placeholder.bound,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ pub enum RegionVariableOrigin<'tcx> {
|
|||
|
||||
/// Region variables created when instantiating a binder with
|
||||
/// existential variables, e.g. when calling a function or method.
|
||||
BoundRegion(Span, ty::BoundRegionKind, BoundRegionConversionTime),
|
||||
BoundRegion(Span, ty::BoundRegionKind<'tcx>, BoundRegionConversionTime),
|
||||
|
||||
UpvarRegion(ty::UpvarId, Span),
|
||||
|
||||
|
|
@ -1300,13 +1300,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> BoundVarReplacerDelegate<'tcx> for ToFreshVars<'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
|
||||
self.args[br.var.index()].expect_region()
|
||||
}
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
|
||||
self.args[bt.var.index()].expect_ty()
|
||||
}
|
||||
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
|
||||
fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
|
||||
self.args[bc.var.index()].expect_const()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ pub(super) fn can_match_erased_ty<'tcx>(
|
|||
struct MatchAgainstHigherRankedOutlives<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
pattern_depth: ty::DebruijnIndex,
|
||||
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
map: FxHashMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
|
||||
|
|
@ -115,7 +115,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> {
|
|||
#[instrument(level = "trace", skip(self))]
|
||||
fn bind(
|
||||
&mut self,
|
||||
br: ty::BoundRegion,
|
||||
br: ty::BoundRegion<'tcx>,
|
||||
value: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
match self.map.entry(br) {
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let next_universe = self.create_next_universe();
|
||||
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
regions: &mut |br: ty::BoundRegion<'tcx>| {
|
||||
ty::Region::new_placeholder(self.tcx, ty::PlaceholderRegion::new(next_universe, br))
|
||||
},
|
||||
types: &mut |bound_ty: ty::BoundTy| {
|
||||
types: &mut |bound_ty: ty::BoundTy<'tcx>| {
|
||||
Ty::new_placeholder(self.tcx, ty::PlaceholderType::new(next_universe, bound_ty))
|
||||
},
|
||||
consts: &mut |bound_const: ty::BoundConst| {
|
||||
consts: &mut |bound_const: ty::BoundConst<'tcx>| {
|
||||
ty::Const::new_placeholder(
|
||||
self.tcx,
|
||||
ty::PlaceholderConst::new(next_universe, bound_const),
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& owns_allocation(cx.tcx, ty)
|
||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(fn_id), AttributeKind::AsPtr(_))
|
||||
&& find_attr!(cx.tcx.get_all_attrs(fn_id), AttributeKind::RustcAsPtr(_))
|
||||
{
|
||||
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||
cx.tcx.emit_node_span_lint(
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ where
|
|||
// When we get into a binder, we need to add its own bound vars to the scope.
|
||||
let mut added = vec![];
|
||||
for arg in t.bound_vars() {
|
||||
let arg: ty::BoundVariableKind = arg;
|
||||
let arg: ty::BoundVariableKind<'tcx> = arg;
|
||||
match arg {
|
||||
ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id))
|
||||
| ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)) => {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
|
|||
if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
|
||||
match path.res {
|
||||
Res::Def(_, def_id)
|
||||
if find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::PassByValue(_)) =>
|
||||
if find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcPassByValue(_)) =>
|
||||
{
|
||||
let name = cx.tcx.item_ident(def_id);
|
||||
let path_segment = path.segments.last().unwrap();
|
||||
|
|
@ -52,7 +52,10 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
|
|||
}
|
||||
Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
|
||||
if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind() {
|
||||
if find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::PassByValue(_)) {
|
||||
if find_attr!(
|
||||
cx.tcx.get_all_attrs(adt.did()),
|
||||
AttributeKind::RustcPassByValue(_)
|
||||
) {
|
||||
return Some(cx.tcx.def_path_str_with_args(adt.did(), args));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -539,10 +539,19 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
);
|
||||
}
|
||||
MustUsePath::Def(span, def_id, reason) => {
|
||||
let span = span.find_ancestor_not_from_macro().unwrap_or(*span);
|
||||
let ancenstor_span = span.find_ancestor_not_from_macro().unwrap_or(*span);
|
||||
let is_redundant_let_ignore = cx
|
||||
.sess()
|
||||
.source_map()
|
||||
.span_to_prev_source(ancenstor_span)
|
||||
.ok()
|
||||
.map(|prev| prev.trim_end().ends_with("let _ ="))
|
||||
.unwrap_or(false);
|
||||
let suggestion_span =
|
||||
if is_redundant_let_ignore { *span } else { ancenstor_span };
|
||||
cx.emit_span_lint(
|
||||
UNUSED_MUST_USE,
|
||||
span,
|
||||
ancenstor_span,
|
||||
UnusedDef {
|
||||
pre: descr_pre,
|
||||
post: descr_post,
|
||||
|
|
@ -551,11 +560,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
|
|||
note: *reason,
|
||||
suggestion: (!is_inner).then_some(if expr_is_from_block {
|
||||
UnusedDefSuggestion::BlockTailExpr {
|
||||
before_span: span.shrink_to_lo(),
|
||||
after_span: span.shrink_to_hi(),
|
||||
before_span: suggestion_span.shrink_to_lo(),
|
||||
after_span: suggestion_span.shrink_to_hi(),
|
||||
}
|
||||
} else {
|
||||
UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() }
|
||||
UnusedDefSuggestion::NormalExpr {
|
||||
span: suggestion_span.shrink_to_lo(),
|
||||
}
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use syn::parse::ParseStream;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Meta, Path, Token, Type, parse_quote};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
|
@ -11,7 +12,7 @@ use crate::diagnostics::error::{
|
|||
DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
|
||||
should_generate_arg, type_is_bool, type_is_unit, type_matches_path,
|
||||
};
|
||||
|
|
@ -42,19 +43,13 @@ pub(crate) struct DiagnosticDeriveVariantBuilder {
|
|||
|
||||
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
|
||||
/// has the actual diagnostic message.
|
||||
pub slug: SpannedOption<Path>,
|
||||
pub slug: Option<Path>,
|
||||
|
||||
/// Error codes are a optional part of the struct attribute - this is only set to detect
|
||||
/// multiple specifications.
|
||||
pub code: SpannedOption<()>,
|
||||
}
|
||||
|
||||
impl HasFieldMap for DiagnosticDeriveVariantBuilder {
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||
self.field_map.get(field)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticDeriveKind {
|
||||
/// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the
|
||||
/// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions
|
||||
|
|
@ -111,7 +106,7 @@ impl DiagnosticDeriveKind {
|
|||
|
||||
impl DiagnosticDeriveVariantBuilder {
|
||||
pub(crate) fn primary_message(&self) -> Option<&Path> {
|
||||
match self.slug.value_ref() {
|
||||
match self.slug.as_ref() {
|
||||
None => {
|
||||
span_err(self.span, "diagnostic slug not specified")
|
||||
.help(
|
||||
|
|
@ -169,7 +164,7 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
&self,
|
||||
attr: &Attribute,
|
||||
) -> Result<Option<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
|
||||
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, self)? else {
|
||||
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, &self.field_map)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
return Ok(None);
|
||||
|
|
@ -191,7 +186,7 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||
});
|
||||
|
||||
Ok(Some((subdiag.kind, slug, subdiag.no_span)))
|
||||
Ok(Some((subdiag.kind, slug, false)))
|
||||
}
|
||||
|
||||
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
||||
|
|
@ -209,47 +204,54 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
let name = attr.path().segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_str();
|
||||
|
||||
let mut first = true;
|
||||
|
||||
if name == "diag" {
|
||||
let mut tokens = TokenStream::new();
|
||||
attr.parse_nested_meta(|nested| {
|
||||
let path = &nested.path;
|
||||
attr.parse_args_with(|input: ParseStream<'_>| {
|
||||
let mut input = &*input;
|
||||
let slug_recovery_point = input.fork();
|
||||
|
||||
if first && (nested.input.is_empty() || nested.input.peek(Token![,])) {
|
||||
self.slug.set_once(path.clone(), path.span().unwrap());
|
||||
first = false;
|
||||
return Ok(());
|
||||
let slug = input.parse::<Path>()?;
|
||||
if input.is_empty() || input.peek(Token![,]) {
|
||||
self.slug = Some(slug);
|
||||
} else {
|
||||
input = &slug_recovery_point;
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
let Ok(nested) = nested.value() else {
|
||||
span_err(
|
||||
nested.input.span().unwrap(),
|
||||
"diagnostic slug must be the first argument",
|
||||
)
|
||||
.emit();
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if path.is_ident("code") {
|
||||
self.code.set_once((), path.span().unwrap());
|
||||
|
||||
let code = nested.parse::<syn::Expr>()?;
|
||||
tokens.extend(quote! {
|
||||
diag.code(#code);
|
||||
});
|
||||
} else {
|
||||
span_err(path.span().unwrap(), "unknown argument")
|
||||
.note("only the `code` parameter is valid after the slug")
|
||||
while !input.is_empty() {
|
||||
input.parse::<Token![,]>()?;
|
||||
// Allow trailing comma
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
let arg_name: Path = input.parse::<Path>()?;
|
||||
if input.peek(Token![,]) {
|
||||
span_err(
|
||||
arg_name.span().unwrap(),
|
||||
"diagnostic slug must be the first argument",
|
||||
)
|
||||
.emit();
|
||||
|
||||
// consume the buffer so we don't have syntax errors from syn
|
||||
let _ = nested.parse::<TokenStream>();
|
||||
continue;
|
||||
}
|
||||
let arg_name = arg_name.require_ident()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
let arg_value = input.parse::<syn::Expr>()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"code" => {
|
||||
self.code.set_once((), arg_name.span().unwrap());
|
||||
tokens.extend(quote! {
|
||||
diag.code(#arg_value);
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
span_err(arg_name.span().unwrap(), "unknown argument")
|
||||
.note("only the `code` parameter is valid after the slug")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
return Ok(tokens);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#![deny(unused_must_use)]
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::parse::ParseStream;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Meta, MetaList, Path};
|
||||
use syn::{Attribute, Meta, MetaList, Path, Token};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
use super::utils::SubdiagnosticVariant;
|
||||
|
|
@ -11,10 +12,10 @@ use crate::diagnostics::error::{
|
|||
DiagnosticDeriveError, invalid_attr, span_err, throw_invalid_attr, throw_span_err,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
||||
SpannedOption, SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment,
|
||||
new_code_ident, report_error_if_not_applied_to_applicability,
|
||||
report_error_if_not_applied_to_span, should_generate_arg,
|
||||
AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption,
|
||||
SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
|
||||
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
|
||||
should_generate_arg,
|
||||
};
|
||||
|
||||
/// The central struct for constructing the `add_to_diag` method from an annotated struct.
|
||||
|
|
@ -142,12 +143,6 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
is_enum: bool,
|
||||
}
|
||||
|
||||
impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||
self.fields.get(field)
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides frequently-needed information about the diagnostic kinds being derived for this type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KindsStatistics {
|
||||
|
|
@ -187,14 +182,12 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
|
|||
}
|
||||
|
||||
impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn identify_kind(
|
||||
&mut self,
|
||||
) -> Result<Vec<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
|
||||
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||
let mut kind_slugs = vec![];
|
||||
|
||||
for attr in self.variant.ast().attrs {
|
||||
let Some(SubdiagnosticVariant { kind, slug, no_span }) =
|
||||
SubdiagnosticVariant::from_attr(attr, self)?
|
||||
let Some(SubdiagnosticVariant { kind, slug }) =
|
||||
SubdiagnosticVariant::from_attr(attr, &self.fields)?
|
||||
else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
|
|
@ -213,7 +206,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
);
|
||||
};
|
||||
|
||||
kind_slugs.push((kind, slug, no_span));
|
||||
kind_slugs.push((kind, slug));
|
||||
}
|
||||
|
||||
Ok(kind_slugs)
|
||||
|
|
@ -437,23 +430,35 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
|
||||
let mut code = None;
|
||||
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("code") {
|
||||
let code_field = new_code_ident();
|
||||
let span = nested.path.span().unwrap();
|
||||
let formatting_init = build_suggestion_code(
|
||||
&code_field,
|
||||
nested,
|
||||
self,
|
||||
AllowMultipleAlternatives::No,
|
||||
);
|
||||
code.set_once((code_field, formatting_init), span);
|
||||
} else {
|
||||
span_err(
|
||||
nested.path.span().unwrap(),
|
||||
"`code` is the only valid nested attribute",
|
||||
)
|
||||
.emit();
|
||||
list.parse_args_with(|input: ParseStream<'_>| {
|
||||
while !input.is_empty() {
|
||||
let arg_name = input.parse::<Ident>()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"code" => {
|
||||
let code_field = new_code_ident();
|
||||
let formatting_init = build_suggestion_code(
|
||||
&code_field,
|
||||
input,
|
||||
&self.fields,
|
||||
AllowMultipleAlternatives::No,
|
||||
)?;
|
||||
code.set_once(
|
||||
(code_field, formatting_init),
|
||||
arg_name.span().unwrap(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
span_err(
|
||||
arg_name.span().unwrap(),
|
||||
"`code` is the only valid nested attribute",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
|
@ -492,8 +497,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let kind_slugs = self.identify_kind()?;
|
||||
|
||||
let kind_stats: KindsStatistics =
|
||||
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
|
||||
let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
|
||||
|
||||
let init = if kind_stats.has_multipart_suggestion {
|
||||
quote! { let mut suggestions = Vec::new(); }
|
||||
|
|
@ -526,17 +530,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
|
||||
let diag = &self.parent.diag;
|
||||
let mut calls = TokenStream::new();
|
||||
for (kind, slug, no_span) in kind_slugs {
|
||||
for (kind, slug) in kind_slugs {
|
||||
let message = format_ident!("__message");
|
||||
calls.extend(
|
||||
quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); },
|
||||
);
|
||||
|
||||
let name = format_ident!(
|
||||
"{}{}",
|
||||
if span_field.is_some() && !no_span { "span_" } else { "" },
|
||||
kind
|
||||
);
|
||||
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||
let call = match kind {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
suggestion_kind,
|
||||
|
|
@ -588,9 +588,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(span) = span_field
|
||||
&& !no_span
|
||||
{
|
||||
if let Some(span) = span_field {
|
||||
quote! { #diag.#name(#span, #message); }
|
||||
} else {
|
||||
quote! { #diag.#name(#message); }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::str::FromStr;
|
|||
use proc_macro::Span;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{ToTokens, format_ident, quote};
|
||||
use syn::meta::ParseNestedMeta;
|
||||
use syn::parse::ParseStream;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Field, LitStr, Meta, Path, Token, Type, TypeTuple, parenthesized};
|
||||
|
|
@ -261,108 +261,104 @@ impl<T> SetOnce<T> for SpannedOption<T> {
|
|||
|
||||
pub(super) type FieldMap = HashMap<String, TokenStream>;
|
||||
|
||||
pub(crate) trait HasFieldMap {
|
||||
/// Returns the binding for the field with the given name, if it exists on the type.
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream>;
|
||||
/// In the strings in the attributes supplied to this macro, we want callers to be able to
|
||||
/// reference fields in the format string. For example:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// /// Suggest `==` when users wrote `===`.
|
||||
/// #[suggestion(slug = "parser-not-javascript-eq", code = "{lhs} == {rhs}")]
|
||||
/// struct NotJavaScriptEq {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// lhs: Ident,
|
||||
/// rhs: Ident,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We want to automatically pick up that `{lhs}` refers `self.lhs` and `{rhs}` refers to
|
||||
/// `self.rhs`, then generate this call to `format!`:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// format!("{lhs} == {rhs}", lhs = self.lhs, rhs = self.rhs)
|
||||
/// ```
|
||||
///
|
||||
/// This function builds the entire call to `format!`.
|
||||
pub(super) fn build_format(
|
||||
field_map: &FieldMap,
|
||||
input: &str,
|
||||
span: proc_macro2::Span,
|
||||
) -> TokenStream {
|
||||
// This set is used later to generate the final format string. To keep builds reproducible,
|
||||
// the iteration order needs to be deterministic, hence why we use a `BTreeSet` here
|
||||
// instead of a `HashSet`.
|
||||
let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
|
||||
|
||||
/// In the strings in the attributes supplied to this macro, we want callers to be able to
|
||||
/// reference fields in the format string. For example:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// /// Suggest `==` when users wrote `===`.
|
||||
/// #[suggestion(slug = "parser-not-javascript-eq", code = "{lhs} == {rhs}")]
|
||||
/// struct NotJavaScriptEq {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// lhs: Ident,
|
||||
/// rhs: Ident,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We want to automatically pick up that `{lhs}` refers `self.lhs` and `{rhs}` refers to
|
||||
/// `self.rhs`, then generate this call to `format!`:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// format!("{lhs} == {rhs}", lhs = self.lhs, rhs = self.rhs)
|
||||
/// ```
|
||||
///
|
||||
/// This function builds the entire call to `format!`.
|
||||
fn build_format(&self, input: &str, span: proc_macro2::Span) -> TokenStream {
|
||||
// This set is used later to generate the final format string. To keep builds reproducible,
|
||||
// the iteration order needs to be deterministic, hence why we use a `BTreeSet` here
|
||||
// instead of a `HashSet`.
|
||||
let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
|
||||
// At this point, we can start parsing the format string.
|
||||
let mut it = input.chars().peekable();
|
||||
|
||||
// At this point, we can start parsing the format string.
|
||||
let mut it = input.chars().peekable();
|
||||
|
||||
// Once the start of a format string has been found, process the format string and spit out
|
||||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
||||
// the next call to `it.next()` retrieves the next character.
|
||||
while let Some(c) = it.next() {
|
||||
if c != '{' {
|
||||
continue;
|
||||
}
|
||||
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||
assert_eq!(it.next().unwrap(), '{');
|
||||
continue;
|
||||
}
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
// Once the start of a format string has been found, process the format string and spit out
|
||||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
||||
// the next call to `it.next()` retrieves the next character.
|
||||
while let Some(c) = it.next() {
|
||||
if c != '{' {
|
||||
continue;
|
||||
}
|
||||
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||
assert_eq!(it.next().unwrap(), '{');
|
||||
continue;
|
||||
}
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
// At this point, `referenced_fields` contains a set of the unique fields that were
|
||||
// referenced in the format string. Generate the corresponding "x = self.x" format
|
||||
// string parameters:
|
||||
let args = referenced_fields.into_iter().map(|field: String| {
|
||||
let field_ident = format_ident!("{}", field);
|
||||
let value = match self.get_field_binding(&field) {
|
||||
Some(value) => value.clone(),
|
||||
// This field doesn't exist. Emit a diagnostic.
|
||||
None => {
|
||||
span_err(
|
||||
span.unwrap(),
|
||||
format!("`{field}` doesn't refer to a field on this type"),
|
||||
)
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, `referenced_fields` contains a set of the unique fields that were
|
||||
// referenced in the format string. Generate the corresponding "x = self.x" format
|
||||
// string parameters:
|
||||
let args = referenced_fields.into_iter().map(|field: String| {
|
||||
let field_ident = format_ident!("{}", field);
|
||||
let value = match field_map.get(&field) {
|
||||
Some(value) => value.clone(),
|
||||
// This field doesn't exist. Emit a diagnostic.
|
||||
None => {
|
||||
span_err(span.unwrap(), format!("`{field}` doesn't refer to a field on this type"))
|
||||
.emit();
|
||||
quote! {
|
||||
"{#field}"
|
||||
}
|
||||
quote! {
|
||||
"{#field}"
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#field_ident = #value
|
||||
}
|
||||
});
|
||||
};
|
||||
quote! {
|
||||
format!(#input #(,#args)*)
|
||||
#field_ident = #value
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
format!(#input #(,#args)*)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,76 +424,63 @@ pub(super) enum AllowMultipleAlternatives {
|
|||
}
|
||||
|
||||
fn parse_suggestion_values(
|
||||
nested: ParseNestedMeta<'_>,
|
||||
nested: ParseStream<'_>,
|
||||
allow_multiple: AllowMultipleAlternatives,
|
||||
) -> syn::Result<Vec<LitStr>> {
|
||||
let values = if let Ok(val) = nested.value() {
|
||||
vec![val.parse()?]
|
||||
} else {
|
||||
let content;
|
||||
parenthesized!(content in nested.input);
|
||||
if nested.parse::<Token![=]>().is_ok() {
|
||||
return Ok(vec![nested.parse::<LitStr>()?]);
|
||||
}
|
||||
|
||||
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||
let content;
|
||||
parenthesized!(content in nested);
|
||||
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||
span_err(content.span().unwrap(), "expected exactly one string literal for `code = ...`")
|
||||
.emit();
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let literals = Punctuated::<LitStr, Token![,]>::parse_terminated(&content);
|
||||
Ok(match literals {
|
||||
Ok(p) if p.is_empty() => {
|
||||
span_err(
|
||||
nested.input.span().unwrap(),
|
||||
"expected exactly one string literal for `code = ...`",
|
||||
content.span().unwrap(),
|
||||
"expected at least one string literal for `code(...)`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
} else {
|
||||
let literals = Punctuated::<LitStr, Token![,]>::parse_terminated(&content);
|
||||
|
||||
match literals {
|
||||
Ok(p) if p.is_empty() => {
|
||||
span_err(
|
||||
content.span().unwrap(),
|
||||
"expected at least one string literal for `code(...)`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
Ok(p) => p.into_iter().collect(),
|
||||
Err(_) => {
|
||||
span_err(
|
||||
content.span().unwrap(),
|
||||
"`code(...)` must contain only string literals",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(values)
|
||||
Ok(p) => p.into_iter().collect(),
|
||||
Err(_) => {
|
||||
span_err(content.span().unwrap(), "`code(...)` must contain only string literals")
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or
|
||||
/// `#[suggestion*(code("foo", "bar"))]` attribute field
|
||||
pub(super) fn build_suggestion_code(
|
||||
code_field: &Ident,
|
||||
nested: ParseNestedMeta<'_>,
|
||||
fields: &impl HasFieldMap,
|
||||
nested: ParseStream<'_>,
|
||||
fields: &FieldMap,
|
||||
allow_multiple: AllowMultipleAlternatives,
|
||||
) -> TokenStream {
|
||||
let values = match parse_suggestion_values(nested, allow_multiple) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
) -> Result<TokenStream, syn::Error> {
|
||||
let values = parse_suggestion_values(nested, allow_multiple)?;
|
||||
|
||||
if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||
Ok(if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||
let formatted_strings: Vec<_> = values
|
||||
.into_iter()
|
||||
.map(|value| fields.build_format(&value.value(), value.span()))
|
||||
.map(|value| build_format(fields, &value.value(), value.span()))
|
||||
.collect();
|
||||
quote! { let #code_field = [#(#formatted_strings),*].into_iter(); }
|
||||
} else if let [value] = values.as_slice() {
|
||||
let formatted_str = fields.build_format(&value.value(), value.span());
|
||||
let formatted_str = build_format(fields, &value.value(), value.span());
|
||||
quote! { let #code_field = #formatted_str; }
|
||||
} else {
|
||||
// error handled previously
|
||||
quote! { let #code_field = String::new(); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Possible styles for suggestion subdiagnostics.
|
||||
|
|
@ -605,16 +588,15 @@ pub(super) enum SubdiagnosticKind {
|
|||
pub(super) struct SubdiagnosticVariant {
|
||||
pub(super) kind: SubdiagnosticKind,
|
||||
pub(super) slug: Option<Path>,
|
||||
pub(super) no_span: bool,
|
||||
}
|
||||
|
||||
impl SubdiagnosticVariant {
|
||||
/// Constructs a `SubdiagnosticVariant` from a field or type attribute such as `#[note]`,
|
||||
/// `#[error(parser::add_paren, no_span)]` or `#[suggestion(code = "...")]`. Returns the
|
||||
/// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the
|
||||
/// `SubdiagnosticKind` and the diagnostic slug, if specified.
|
||||
pub(super) fn from_attr(
|
||||
attr: &Attribute,
|
||||
fields: &impl HasFieldMap,
|
||||
fields: &FieldMap,
|
||||
) -> Result<Option<SubdiagnosticVariant>, DiagnosticDeriveError> {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
|
|
@ -694,7 +676,7 @@ impl SubdiagnosticVariant {
|
|||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||
return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
|
||||
return Ok(Some(SubdiagnosticVariant { kind, slug: None }));
|
||||
}
|
||||
SubdiagnosticKind::Suggestion { .. } => {
|
||||
throw_span_err!(span, "suggestion without `code = \"...\"`")
|
||||
|
|
@ -709,112 +691,93 @@ impl SubdiagnosticVariant {
|
|||
let mut code = None;
|
||||
let mut suggestion_kind = None;
|
||||
|
||||
let mut first = true;
|
||||
let mut slug = None;
|
||||
let mut no_span = false;
|
||||
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.input.is_empty() || nested.input.peek(Token![,]) {
|
||||
if first {
|
||||
slug = Some(nested.path);
|
||||
} else if nested.path.is_ident("no_span") {
|
||||
no_span = true;
|
||||
} else {
|
||||
span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit();
|
||||
list.parse_args_with(|input: ParseStream<'_>| {
|
||||
let mut is_first = true;
|
||||
while !input.is_empty() {
|
||||
let arg_name: Path = input.parse::<Path>()?;
|
||||
let arg_name_span = arg_name.span().unwrap();
|
||||
if input.is_empty() || input.parse::<Token![,]>().is_ok() {
|
||||
if is_first {
|
||||
slug = Some(arg_name);
|
||||
is_first = false;
|
||||
} else {
|
||||
span_err(arg_name_span, "a diagnostic slug must be the first argument to the attribute").emit();
|
||||
}
|
||||
continue
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
first = false;
|
||||
return Ok(());
|
||||
}
|
||||
match (arg_name.require_ident()?.to_string().as_str(), &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let code_init = build_suggestion_code(
|
||||
&code_field,
|
||||
&input,
|
||||
fields,
|
||||
AllowMultipleAlternatives::Yes,
|
||||
)?;
|
||||
code.set_once(code_init, arg_name_span);
|
||||
}
|
||||
(
|
||||
"applicability",
|
||||
SubdiagnosticKind::Suggestion { applicability, .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { applicability, .. },
|
||||
) => {
|
||||
input.parse::<Token![=]>()?;
|
||||
let value = input.parse::<LitStr>()?;
|
||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid applicability").emit();
|
||||
Applicability::Unspecified
|
||||
});
|
||||
applicability.set_once(value, span);
|
||||
}
|
||||
(
|
||||
"style",
|
||||
SubdiagnosticKind::Suggestion { .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. },
|
||||
) => {
|
||||
input.parse::<Token![=]>()?;
|
||||
let value = input.parse::<LitStr>()?;
|
||||
|
||||
first = false;
|
||||
let value = value.value().parse().unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid suggestion style")
|
||||
.help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`")
|
||||
.emit();
|
||||
SuggestionKind::Normal
|
||||
});
|
||||
|
||||
let nested_name = nested.path.segments.last().unwrap().ident.to_string();
|
||||
let nested_name = nested_name.as_str();
|
||||
suggestion_kind.set_once(value, span);
|
||||
}
|
||||
|
||||
let path_span = nested.path.span().unwrap();
|
||||
let val_span = nested.input.span().unwrap();
|
||||
|
||||
macro_rules! get_string {
|
||||
() => {{
|
||||
let Ok(value) = nested.value().and_then(|x| x.parse::<LitStr>()) else {
|
||||
span_err(val_span, "expected `= \"xxx\"`").emit();
|
||||
return Ok(());
|
||||
};
|
||||
value
|
||||
}};
|
||||
}
|
||||
|
||||
let mut has_errors = false;
|
||||
let input = nested.input;
|
||||
|
||||
match (nested_name, &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let code_init = build_suggestion_code(
|
||||
code_field,
|
||||
nested,
|
||||
fields,
|
||||
AllowMultipleAlternatives::Yes,
|
||||
);
|
||||
code.set_once(code_init, path_span);
|
||||
}
|
||||
(
|
||||
"applicability",
|
||||
SubdiagnosticKind::Suggestion { applicability, .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { applicability, .. },
|
||||
) => {
|
||||
let value = get_string!();
|
||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid applicability").emit();
|
||||
has_errors = true;
|
||||
Applicability::Unspecified
|
||||
});
|
||||
applicability.set_once(value, span);
|
||||
}
|
||||
(
|
||||
"style",
|
||||
SubdiagnosticKind::Suggestion { .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. },
|
||||
) => {
|
||||
let value = get_string!();
|
||||
|
||||
let value = value.value().parse().unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid suggestion style")
|
||||
.help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`")
|
||||
// Invalid nested attribute
|
||||
(_, SubdiagnosticKind::Suggestion { .. }) => {
|
||||
span_err(arg_name_span, "invalid nested attribute")
|
||||
.help(
|
||||
"only `style`, `code` and `applicability` are valid nested attributes",
|
||||
)
|
||||
.emit();
|
||||
has_errors = true;
|
||||
SuggestionKind::Normal
|
||||
});
|
||||
|
||||
suggestion_kind.set_once(value, span);
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
|
||||
span_err(arg_name_span, "invalid nested attribute")
|
||||
.help("only `style` and `applicability` are valid nested attributes")
|
||||
.emit();
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
_ => {
|
||||
span_err(arg_name_span, "no nested attribute expected here").emit();
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid nested attribute
|
||||
(_, SubdiagnosticKind::Suggestion { .. }) => {
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help(
|
||||
"only `no_span`, `style`, `code` and `applicability` are valid nested attributes",
|
||||
)
|
||||
.emit();
|
||||
has_errors = true;
|
||||
}
|
||||
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help("only `no_span`, `style` and `applicability` are valid nested attributes")
|
||||
.emit();
|
||||
has_errors = true;
|
||||
}
|
||||
_ => {
|
||||
span_err(path_span, "only `no_span` is a valid nested attribute").emit();
|
||||
has_errors = true;
|
||||
}
|
||||
if input.is_empty() { break }
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
|
||||
if has_errors {
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
|
@ -851,7 +814,7 @@ impl SubdiagnosticVariant {
|
|||
| SubdiagnosticKind::Warn => {}
|
||||
}
|
||||
|
||||
Ok(Some(SubdiagnosticVariant { kind, slug, no_span }))
|
||||
Ok(Some(SubdiagnosticVariant { kind, slug }))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ pub enum ObjectLifetimeDefault {
|
|||
/// Maps the id of each bound variable reference to the variable decl
|
||||
/// that it corresponds to.
|
||||
#[derive(Debug, Default, HashStable)]
|
||||
pub struct ResolveBoundVars {
|
||||
pub struct ResolveBoundVars<'tcx> {
|
||||
// Maps from every use of a named (not anonymous) bound var to a
|
||||
// `ResolvedArg` describing how that variable is bound.
|
||||
pub defs: SortedMap<ItemLocalId, ResolvedArg>,
|
||||
|
|
@ -59,7 +59,7 @@ pub struct ResolveBoundVars {
|
|||
// - closures
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
|
||||
pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind<'tcx>>>,
|
||||
|
||||
// List captured variables for each opaque type.
|
||||
pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
//! To improve compile times and code size for the compiler itself, query
|
||||
//! values are "erased" in some contexts (e.g. inside in-memory cache types),
|
||||
//! to reduce the number of generic instantiations created during codegen.
|
||||
//!
|
||||
//! See <https://github.com/rust-lang/rust/pull/151715> for some bootstrap-time
|
||||
//! and performance benchmarks.
|
||||
|
||||
use std::ffi::OsStr;
|
||||
use std::intrinsics::transmute_unchecked;
|
||||
use std::mem::MaybeUninit;
|
||||
|
|
@ -14,138 +21,169 @@ use crate::ty::adjustment::CoerceUnsizedInfo;
|
|||
use crate::ty::{self, Ty, TyCtxt};
|
||||
use crate::{mir, traits};
|
||||
|
||||
/// Internal implementation detail of [`Erased`].
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Erased<T: Copy> {
|
||||
// We use `MaybeUninit` here so we can store any value
|
||||
// in `data` since we aren't actually storing a `T`.
|
||||
data: MaybeUninit<T>,
|
||||
pub struct ErasedData<Storage: Copy> {
|
||||
/// We use `MaybeUninit` here to make sure it's legal to store a transmuted
|
||||
/// value that isn't actually of type `Storage`.
|
||||
data: MaybeUninit<Storage>,
|
||||
}
|
||||
|
||||
pub trait EraseType: Copy {
|
||||
type Result: Copy;
|
||||
/// Trait for types that can be erased into [`Erased<Self>`].
|
||||
///
|
||||
/// Erasing and unerasing values is performed by [`erase_val`] and [`restore_val`].
|
||||
///
|
||||
/// FIXME: This whole trait could potentially be replaced by `T: Copy` and the
|
||||
/// storage type `[u8; size_of::<T>()]` when support for that is more mature.
|
||||
pub trait Erasable: Copy {
|
||||
/// Storage type to used for erased values of this type.
|
||||
/// Should be `[u8; N]`, where N is equal to `size_of::<Self>`.
|
||||
///
|
||||
/// [`ErasedData`] wraps this storage type in `MaybeUninit` to ensure that
|
||||
/// transmutes to/from erased storage are well-defined.
|
||||
type Storage: Copy;
|
||||
}
|
||||
|
||||
// Allow `type_alias_bounds` since compilation will fail without `EraseType`.
|
||||
#[allow(type_alias_bounds)]
|
||||
pub type Erase<T: EraseType> = Erased<impl Copy>;
|
||||
/// A value of `T` that has been "erased" into some opaque storage type.
|
||||
///
|
||||
/// This is helpful for reducing the number of concrete instantiations needed
|
||||
/// during codegen when building the compiler.
|
||||
///
|
||||
/// Using an opaque type alias allows the type checker to enforce that
|
||||
/// `Erased<T>` and `Erased<U>` are still distinct types, while allowing
|
||||
/// monomorphization to see that they might actually use the same storage type.
|
||||
pub type Erased<T: Erasable> = ErasedData<impl Copy>;
|
||||
|
||||
/// Erases a value of type `T` into `Erased<T>`.
|
||||
///
|
||||
/// `Erased<T>` and `Erased<U>` are type-checked as distinct types, but codegen
|
||||
/// can see whether they actually have the same storage type.
|
||||
///
|
||||
/// FIXME: This might have soundness issues with erasable types that don't
|
||||
/// implement the same auto-traits as `[u8; _]`; see
|
||||
/// <https://github.com/rust-lang/rust/pull/151715#discussion_r2740113250>
|
||||
#[inline(always)]
|
||||
#[define_opaque(Erase)]
|
||||
pub fn erase<T: EraseType>(src: T) -> Erase<T> {
|
||||
#[define_opaque(Erased)]
|
||||
pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
|
||||
// Ensure the sizes match
|
||||
const {
|
||||
if size_of::<T>() != size_of::<T::Result>() {
|
||||
panic!("size of T must match erased type T::Result")
|
||||
if size_of::<T>() != size_of::<T::Storage>() {
|
||||
panic!("size of T must match erased type <T as Erasable>::Storage")
|
||||
}
|
||||
};
|
||||
|
||||
Erased::<<T as EraseType>::Result> {
|
||||
ErasedData::<<T as Erasable>::Storage> {
|
||||
// `transmute_unchecked` is needed here because it does not have `transmute`'s size check
|
||||
// (and thus allows to transmute between `T` and `MaybeUninit<T::Result>`) (we do the size
|
||||
// (and thus allows to transmute between `T` and `MaybeUninit<T::Storage>`) (we do the size
|
||||
// check ourselves in the `const` block above).
|
||||
//
|
||||
// `transmute_copy` is also commonly used for this (and it would work here since
|
||||
// `EraseType: Copy`), but `transmute_unchecked` better explains the intent.
|
||||
// `Erasable: Copy`), but `transmute_unchecked` better explains the intent.
|
||||
//
|
||||
// SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
|
||||
data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Result>>(src) },
|
||||
data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Storage>>(value) },
|
||||
}
|
||||
}
|
||||
|
||||
/// Restores an erased value.
|
||||
/// Restores an erased value to its real type.
|
||||
///
|
||||
/// This relies on the fact that `Erased<T>` and `Erased<U>` are type-checked
|
||||
/// as distinct types, even if they use the same storage type.
|
||||
#[inline(always)]
|
||||
#[define_opaque(Erase)]
|
||||
pub fn restore<T: EraseType>(value: Erase<T>) -> T {
|
||||
let value: Erased<<T as EraseType>::Result> = value;
|
||||
// See comment in `erase` for why we use `transmute_unchecked`.
|
||||
#[define_opaque(Erased)]
|
||||
pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
|
||||
let ErasedData { data }: ErasedData<<T as Erasable>::Storage> = erased_value;
|
||||
// See comment in `erase_val` for why we use `transmute_unchecked`.
|
||||
//
|
||||
// SAFETY: Due to the use of impl Trait in `Erase` the only way to safely create an instance
|
||||
// of `Erase` is to call `erase`, so we know that `value.data` is a valid instance of `T` of
|
||||
// the right size.
|
||||
unsafe { transmute_unchecked::<MaybeUninit<T::Result>, T>(value.data) }
|
||||
// SAFETY: Due to the use of impl Trait in `Erased` the only way to safely create an instance
|
||||
// of `Erased` is to call `erase_val`, so we know that `erased_value.data` is a valid instance
|
||||
// of `T` of the right size.
|
||||
unsafe { transmute_unchecked::<MaybeUninit<T::Storage>, T>(data) }
|
||||
}
|
||||
|
||||
impl<T> EraseType for &'_ T {
|
||||
type Result = [u8; size_of::<&'static ()>()];
|
||||
// FIXME(#151565): Using `T: ?Sized` here should let us remove the separate
|
||||
// impls for fat reference types.
|
||||
impl<T> Erasable for &'_ T {
|
||||
type Storage = [u8; size_of::<&'static ()>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for &'_ [T] {
|
||||
type Result = [u8; size_of::<&'static [()]>()];
|
||||
impl<T> Erasable for &'_ [T] {
|
||||
type Storage = [u8; size_of::<&'static [()]>()];
|
||||
}
|
||||
|
||||
impl EraseType for &'_ OsStr {
|
||||
type Result = [u8; size_of::<&'static OsStr>()];
|
||||
impl Erasable for &'_ OsStr {
|
||||
type Storage = [u8; size_of::<&'static OsStr>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for &'_ ty::List<T> {
|
||||
type Result = [u8; size_of::<&'static ty::List<()>>()];
|
||||
impl<T> Erasable for &'_ ty::List<T> {
|
||||
type Storage = [u8; size_of::<&'static ty::List<()>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> {
|
||||
type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
|
||||
impl<T> Erasable for &'_ ty::ListWithCachedTypeInfo<T> {
|
||||
type Storage = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
|
||||
}
|
||||
|
||||
impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> {
|
||||
type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
|
||||
impl<I: rustc_index::Idx, T> Erasable for &'_ rustc_index::IndexSlice<I, T> {
|
||||
type Storage = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
|
||||
type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
|
||||
impl<T> Erasable for Result<&'_ T, traits::query::NoSolution> {
|
||||
type Storage = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
|
||||
type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
|
||||
impl<T> Erasable for Result<&'_ [T], traits::query::NoSolution> {
|
||||
type Storage = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
|
||||
type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
|
||||
impl<T> Erasable for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
|
||||
type Storage = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ [T], rustc_errors::ErrorGuaranteed> {
|
||||
type Result = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()];
|
||||
impl<T> Erasable for Result<&'_ [T], rustc_errors::ErrorGuaranteed> {
|
||||
type Storage = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> {
|
||||
type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
|
||||
impl<T> Erasable for Result<&'_ T, traits::CodegenObligationError> {
|
||||
type Storage = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
|
||||
type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
|
||||
impl<T> Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
|
||||
type Storage = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> {
|
||||
type Result = [u8; size_of::<
|
||||
impl<T> Erasable for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> {
|
||||
type Storage = [u8; size_of::<
|
||||
Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>,
|
||||
>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuaranteed> {
|
||||
type Result =
|
||||
impl Erasable for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuaranteed> {
|
||||
type Storage =
|
||||
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
|
||||
type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
|
||||
impl Erasable for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
|
||||
type Storage = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
|
||||
}
|
||||
|
||||
impl EraseType
|
||||
impl Erasable
|
||||
for Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, rustc_errors::ErrorGuaranteed>
|
||||
{
|
||||
type Result = [u8; size_of::<
|
||||
type Storage = [u8; size_of::<
|
||||
Result<Option<ty::EarlyBinder<'static, ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
|
||||
>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
|
||||
type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
|
||||
impl Erasable for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
|
||||
type Storage = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<bool, &ty::layout::LayoutError<'_>> {
|
||||
type Result = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
|
||||
impl Erasable for Result<bool, &ty::layout::LayoutError<'_>> {
|
||||
type Storage = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>> {
|
||||
type Result = [u8; size_of::<
|
||||
impl Erasable for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>> {
|
||||
type Storage = [u8; size_of::<
|
||||
Result<
|
||||
rustc_abi::TyAndLayout<'static, Ty<'static>>,
|
||||
&'static ty::layout::LayoutError<'static>,
|
||||
|
|
@ -153,35 +191,36 @@ impl EraseType for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::Layou
|
|||
>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
|
||||
type Result = [u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
|
||||
impl Erasable for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
|
||||
type Storage =
|
||||
[u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<mir::ConstValue, mir::interpret::ErrorHandled> {
|
||||
type Result = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
|
||||
impl Erasable for Result<mir::ConstValue, mir::interpret::ErrorHandled> {
|
||||
type Storage = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Option<(mir::ConstValue, Ty<'_>)> {
|
||||
type Result = [u8; size_of::<Option<(mir::ConstValue, Ty<'_>)>>()];
|
||||
impl Erasable for Option<(mir::ConstValue, Ty<'_>)> {
|
||||
type Storage = [u8; size_of::<Option<(mir::ConstValue, Ty<'_>)>>()];
|
||||
}
|
||||
|
||||
impl EraseType for EvalToValTreeResult<'_> {
|
||||
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
|
||||
impl Erasable for EvalToValTreeResult<'_> {
|
||||
type Storage = [u8; size_of::<EvalToValTreeResult<'static>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
|
||||
type Result =
|
||||
impl Erasable for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
|
||||
type Storage =
|
||||
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
||||
type Result = [u8; size_of::<Result<ty::EarlyBinder<'static, Ty<'_>>, CyclePlaceholder>>()];
|
||||
impl Erasable for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
||||
type Storage = [u8; size_of::<Result<ty::EarlyBinder<'static, Ty<'_>>, CyclePlaceholder>>()];
|
||||
}
|
||||
|
||||
impl EraseType
|
||||
impl Erasable
|
||||
for Result<(&'_ [Spanned<MonoItem<'_>>], &'_ [Spanned<MonoItem<'_>>]), NormalizationErrorInMono>
|
||||
{
|
||||
type Result = [u8; size_of::<
|
||||
type Storage = [u8; size_of::<
|
||||
Result<
|
||||
(&'static [Spanned<MonoItem<'static>>], &'static [Spanned<MonoItem<'static>>]),
|
||||
NormalizationErrorInMono,
|
||||
|
|
@ -189,86 +228,89 @@ impl EraseType
|
|||
>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<&'_ TokenStream, ()> {
|
||||
type Result = [u8; size_of::<Result<&'static TokenStream, ()>>()];
|
||||
impl Erasable for Result<&'_ TokenStream, ()> {
|
||||
type Storage = [u8; size_of::<Result<&'static TokenStream, ()>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Option<&'_ T> {
|
||||
type Result = [u8; size_of::<Option<&'static ()>>()];
|
||||
impl<T> Erasable for Option<&'_ T> {
|
||||
type Storage = [u8; size_of::<Option<&'static ()>>()];
|
||||
}
|
||||
|
||||
impl<T> EraseType for Option<&'_ [T]> {
|
||||
type Result = [u8; size_of::<Option<&'static [()]>>()];
|
||||
impl<T> Erasable for Option<&'_ [T]> {
|
||||
type Storage = [u8; size_of::<Option<&'static [()]>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Option<&'_ OsStr> {
|
||||
type Result = [u8; size_of::<Option<&'static OsStr>>()];
|
||||
impl Erasable for Option<&'_ OsStr> {
|
||||
type Storage = [u8; size_of::<Option<&'static OsStr>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Option<mir::DestructuredConstant<'_>> {
|
||||
type Result = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
|
||||
impl Erasable for Option<mir::DestructuredConstant<'_>> {
|
||||
type Storage = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::ImplTraitHeader<'_> {
|
||||
type Result = [u8; size_of::<ty::ImplTraitHeader<'static>>()];
|
||||
impl Erasable for ty::ImplTraitHeader<'_> {
|
||||
type Storage = [u8; size_of::<ty::ImplTraitHeader<'static>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Option<ty::EarlyBinder<'_, Ty<'_>>> {
|
||||
type Result = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
|
||||
impl Erasable for Option<ty::EarlyBinder<'_, Ty<'_>>> {
|
||||
type Storage = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for rustc_hir::MaybeOwner<'_> {
|
||||
type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
|
||||
impl Erasable for rustc_hir::MaybeOwner<'_> {
|
||||
type Storage = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
|
||||
}
|
||||
|
||||
impl<T: EraseType> EraseType for ty::EarlyBinder<'_, T> {
|
||||
type Result = T::Result;
|
||||
impl<T: Erasable> Erasable for ty::EarlyBinder<'_, T> {
|
||||
type Storage = T::Storage;
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
|
||||
impl Erasable for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
type Storage = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
|
||||
type Result =
|
||||
impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
|
||||
type Storage =
|
||||
[u8; size_of::<ty::Binder<'static, ty::CoroutineWitnessTypes<TyCtxt<'static>>>>()];
|
||||
}
|
||||
|
||||
impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
|
||||
type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
|
||||
impl Erasable for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
|
||||
type Storage = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
|
||||
type Result = [u8; size_of::<(&'static (), &'static ())>()];
|
||||
impl<T0, T1> Erasable for (&'_ T0, &'_ T1) {
|
||||
type Storage = [u8; size_of::<(&'static (), &'static ())>()];
|
||||
}
|
||||
|
||||
impl<T0> EraseType for (solve::QueryResult<'_>, &'_ T0) {
|
||||
type Result = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()];
|
||||
impl<T0> Erasable for (solve::QueryResult<'_>, &'_ T0) {
|
||||
type Storage = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()];
|
||||
}
|
||||
|
||||
impl<T0, T1> EraseType for (&'_ T0, &'_ [T1]) {
|
||||
type Result = [u8; size_of::<(&'static (), &'static [()])>()];
|
||||
impl<T0, T1> Erasable for (&'_ T0, &'_ [T1]) {
|
||||
type Storage = [u8; size_of::<(&'static (), &'static [()])>()];
|
||||
}
|
||||
|
||||
impl<T0, T1> EraseType for (&'_ [T0], &'_ [T1]) {
|
||||
type Result = [u8; size_of::<(&'static [()], &'static [()])>()];
|
||||
impl<T0, T1> Erasable for (&'_ [T0], &'_ [T1]) {
|
||||
type Storage = [u8; size_of::<(&'static [()], &'static [()])>()];
|
||||
}
|
||||
|
||||
impl<T0> EraseType for (&'_ T0, Result<(), ErrorGuaranteed>) {
|
||||
type Result = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
|
||||
impl<T0> Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) {
|
||||
type Storage = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
|
||||
}
|
||||
|
||||
macro_rules! trivial {
|
||||
macro_rules! impl_erasable_for_simple_types {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl EraseType for $ty {
|
||||
type Result = [u8; size_of::<$ty>()];
|
||||
impl Erasable for $ty {
|
||||
type Storage = [u8; size_of::<$ty>()];
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
trivial! {
|
||||
// For concrete types with no lifetimes, the erased storage for `Foo` is
|
||||
// `[u8; size_of::<Foo>()]`.
|
||||
impl_erasable_for_simple_types! {
|
||||
// FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this.
|
||||
(),
|
||||
bool,
|
||||
Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>,
|
||||
|
|
@ -346,7 +388,6 @@ trivial! {
|
|||
rustc_middle::ty::AssocContainer,
|
||||
rustc_middle::ty::Asyncness,
|
||||
rustc_middle::ty::AsyncDestructor,
|
||||
rustc_middle::ty::BoundVariableKind,
|
||||
rustc_middle::ty::AnonConstKind,
|
||||
rustc_middle::ty::Destructor,
|
||||
rustc_middle::ty::fast_reject::SimplifiedType,
|
||||
|
|
@ -378,17 +419,23 @@ trivial! {
|
|||
usize,
|
||||
}
|
||||
|
||||
macro_rules! tcx_lifetime {
|
||||
macro_rules! impl_erasable_for_single_lifetime_types {
|
||||
($($($fake_path:ident)::+),+ $(,)?) => {
|
||||
$(
|
||||
impl<'tcx> EraseType for $($fake_path)::+<'tcx> {
|
||||
type Result = [u8; size_of::<$($fake_path)::+<'static>>()];
|
||||
impl<'tcx> Erasable for $($fake_path)::+<'tcx> {
|
||||
type Storage = [u8; size_of::<$($fake_path)::+<'static>>()];
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
tcx_lifetime! {
|
||||
// For types containing a single lifetime and no other generics, e.g.
|
||||
// `Foo<'tcx>`, the erased storage is `[u8; size_of::<Foo<'static>>()]`.
|
||||
//
|
||||
// FIXME(#151565): Some of the hand-written impls above that only use one
|
||||
// lifetime can probably be migrated here.
|
||||
impl_erasable_for_single_lifetime_types! {
|
||||
// FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this.
|
||||
rustc_middle::middle::exported_symbols::ExportedSymbol,
|
||||
rustc_middle::mir::Const,
|
||||
rustc_middle::mir::DestructuredConstant,
|
||||
|
|
@ -415,6 +462,7 @@ tcx_lifetime! {
|
|||
rustc_middle::ty::ConstConditions,
|
||||
rustc_middle::ty::inhabitedness::InhabitedPredicate,
|
||||
rustc_middle::ty::Instance,
|
||||
rustc_middle::ty::BoundVariableKind,
|
||||
rustc_middle::ty::InstanceKind,
|
||||
rustc_middle::ty::layout::FnAbiError,
|
||||
rustc_middle::ty::layout::LayoutError,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
|
|||
|
||||
use crate::dep_graph;
|
||||
use crate::query::IntoQueryParam;
|
||||
use crate::query::erase::{self, Erase, EraseType};
|
||||
use crate::query::erase::{self, Erasable, Erased};
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
|
||||
|
|
@ -63,15 +63,15 @@ pub(crate) fn query_ensure_error_guaranteed<'tcx, Cache, T>(
|
|||
check_cache: bool,
|
||||
) -> Result<(), ErrorGuaranteed>
|
||||
where
|
||||
Cache: QueryCache<Value = Erase<Result<T, ErrorGuaranteed>>>,
|
||||
Result<T, ErrorGuaranteed>: EraseType,
|
||||
Cache: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
|
||||
Result<T, ErrorGuaranteed>: Erasable,
|
||||
{
|
||||
let key = key.into_query_param();
|
||||
if let Some(res) = try_get_cached(tcx, query_cache, &key) {
|
||||
erase::restore(res).map(drop)
|
||||
erase::restore_val(res).map(drop)
|
||||
} else {
|
||||
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
|
||||
.map(erase::restore)
|
||||
.map(erase::restore_val)
|
||||
.map(|res| res.map(drop))
|
||||
// Either we actually executed the query, which means we got a full `Result`,
|
||||
// or we can just assume the query succeeded, because it was green in the
|
||||
|
|
@ -90,17 +90,17 @@ pub(crate) fn query_feed<'tcx, Cache, Value>(
|
|||
hasher: Option<fn(&mut StableHashingContext<'_>, &Value) -> Fingerprint>,
|
||||
cache: &Cache,
|
||||
key: Cache::Key,
|
||||
erased: Erase<Value>,
|
||||
erased: Erased<Value>,
|
||||
) where
|
||||
Cache: QueryCache<Value = Erase<Value>>,
|
||||
Cache: QueryCache<Value = Erased<Value>>,
|
||||
Cache::Key: DepNodeParams<TyCtxt<'tcx>>,
|
||||
Value: EraseType + Debug,
|
||||
Value: Erasable + Debug,
|
||||
{
|
||||
let value = erase::restore::<Value>(erased);
|
||||
let value = erase::restore_val::<Value>(erased);
|
||||
|
||||
match try_get_cached(tcx, cache, &key) {
|
||||
Some(old) => {
|
||||
let old = erase::restore::<Value>(old);
|
||||
let old = erase::restore_val::<Value>(old);
|
||||
if let Some(hasher) = hasher {
|
||||
let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx
|
||||
.with_stable_hashing_context(|mut hcx| {
|
||||
|
|
|
|||
|
|
@ -121,8 +121,7 @@ use crate::mir::interpret::{
|
|||
use crate::mir::mono::{
|
||||
CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
|
||||
};
|
||||
use crate::query::erase::{Erase, erase, restore};
|
||||
use crate::query::plumbing::{CyclePlaceholder, DynamicQuery};
|
||||
use crate::query::plumbing::CyclePlaceholder;
|
||||
use crate::traits::query::{
|
||||
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
|
||||
CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
|
|
@ -2116,7 +2115,7 @@ rustc_queries! {
|
|||
/// Does lifetime resolution on items. Importantly, we can't resolve
|
||||
/// lifetimes directly on things like trait methods, because of trait params.
|
||||
/// See `rustc_resolve::late::lifetimes` for details.
|
||||
query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars {
|
||||
query resolve_bound_vars(owner_id: hir::OwnerId) -> &'tcx ResolveBoundVars<'tcx> {
|
||||
arena_cache
|
||||
desc { |tcx| "resolving lifetimes for `{}`", tcx.def_path_str(owner_id) }
|
||||
}
|
||||
|
|
@ -2145,7 +2144,7 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
query late_bound_vars_map(owner_id: hir::OwnerId)
|
||||
-> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> {
|
||||
-> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind<'tcx>>> {
|
||||
desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) }
|
||||
}
|
||||
/// For an opaque type, return the list of (captured lifetime, inner generic param).
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ use crate::dep_graph;
|
|||
use crate::dep_graph::DepKind;
|
||||
use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
|
||||
use crate::query::{
|
||||
DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
|
||||
ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
|
||||
};
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
pub struct DynamicQuery<'tcx, C: QueryCache> {
|
||||
/// Stores function pointers and other metadata for a particular query.
|
||||
///
|
||||
/// Used indirectly by query plumbing in `rustc_query_system`, via a trait.
|
||||
pub struct QueryVTable<'tcx, C: QueryCache> {
|
||||
pub name: &'static str,
|
||||
pub eval_always: bool,
|
||||
pub dep_kind: DepKind,
|
||||
|
|
@ -62,7 +65,7 @@ pub struct QuerySystem<'tcx> {
|
|||
pub states: QueryStates<'tcx>,
|
||||
pub arenas: WorkerLocal<QueryArenas<'tcx>>,
|
||||
pub caches: QueryCaches<'tcx>,
|
||||
pub dynamic_queries: DynamicQueries<'tcx>,
|
||||
pub query_vtables: PerQueryVTables<'tcx>,
|
||||
|
||||
/// This provides access to the incremental compilation on-disk cache for query results.
|
||||
/// Do not access this directly. It is only meant to be used by
|
||||
|
|
@ -263,6 +266,7 @@ macro_rules! define_callbacks {
|
|||
pub mod queries {
|
||||
$(pub mod $name {
|
||||
use super::super::*;
|
||||
use $crate::query::erase::{self, Erased};
|
||||
|
||||
pub type Key<'tcx> = $($K)*;
|
||||
pub type Value<'tcx> = $V;
|
||||
|
|
@ -285,29 +289,33 @@ macro_rules! define_callbacks {
|
|||
#[inline(always)]
|
||||
pub fn provided_to_erased<'tcx>(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
value: ProvidedValue<'tcx>,
|
||||
) -> Erase<Value<'tcx>> {
|
||||
erase(query_if_arena!([$($modifiers)*]
|
||||
provided_value: ProvidedValue<'tcx>,
|
||||
) -> Erased<Value<'tcx>> {
|
||||
// Store the provided value in an arena and get a reference
|
||||
// to it, for queries with `arena_cache`.
|
||||
let value: Value<'tcx> = query_if_arena!([$($modifiers)*]
|
||||
{
|
||||
use $crate::query::arena_cached::ArenaCached;
|
||||
|
||||
if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() {
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.query_system.arenas.$name.alloc(v),
|
||||
value,
|
||||
provided_value,
|
||||
)
|
||||
} else {
|
||||
<$V as ArenaCached>::alloc_in_arena(
|
||||
|v| _tcx.arena.dropless.alloc(v),
|
||||
value,
|
||||
provided_value,
|
||||
)
|
||||
}
|
||||
}
|
||||
(value)
|
||||
))
|
||||
// Otherwise, the provided value is the value.
|
||||
(provided_value)
|
||||
);
|
||||
erase::erase_val(value)
|
||||
}
|
||||
|
||||
pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
|
||||
pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erased<$V>>;
|
||||
|
||||
// Ensure that keys grow no larger than 88 bytes by accident.
|
||||
// Increase this limit if necessary, but do try to keep the size low if possible
|
||||
|
|
@ -408,7 +416,9 @@ macro_rules! define_callbacks {
|
|||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
|
||||
{
|
||||
restore::<$V>(crate::query::inner::query_get_at(
|
||||
use $crate::query::{erase, inner};
|
||||
|
||||
erase::restore_val::<$V>(inner::query_get_at(
|
||||
self.tcx,
|
||||
self.tcx.query_system.fns.engine.$name,
|
||||
&self.tcx.query_system.caches.$name,
|
||||
|
|
@ -418,9 +428,12 @@ macro_rules! define_callbacks {
|
|||
})*
|
||||
}
|
||||
|
||||
pub struct DynamicQueries<'tcx> {
|
||||
/// Holds a `QueryVTable` for each query.
|
||||
///
|
||||
/// ("Per" just makes this pluralized name more visually distinct.)
|
||||
pub struct PerQueryVTables<'tcx> {
|
||||
$(
|
||||
pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
|
||||
pub $name: ::rustc_middle::query::plumbing::QueryVTable<'tcx, queries::$name::Storage<'tcx>>,
|
||||
)*
|
||||
}
|
||||
|
||||
|
|
@ -474,7 +487,7 @@ macro_rules! define_callbacks {
|
|||
Span,
|
||||
queries::$name::Key<'tcx>,
|
||||
QueryMode,
|
||||
) -> Option<Erase<$V>>,)*
|
||||
) -> Option<$crate::query::erase::Erased<$V>>,)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,11 +427,11 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [Spanned<MonoItem<'tcx>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> {
|
||||
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind<'tcx>> {
|
||||
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||
let len = decoder.read_usize();
|
||||
decoder.interner().mk_bound_variable_kinds_from_iter(
|
||||
(0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
|
||||
(0..len).map::<ty::BoundVariableKind<'tcx>, _>(|_| Decodable::decode(decoder)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -495,7 +495,7 @@ impl_decodable_via_ref! {
|
|||
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
&'tcx traits::ImplSource<'tcx, ()>,
|
||||
&'tcx mir::Body<'tcx>,
|
||||
&'tcx ty::List<ty::BoundVariableKind>,
|
||||
&'tcx ty::List<ty::BoundVariableKind<'tcx>>,
|
||||
&'tcx ty::List<ty::Pattern<'tcx>>,
|
||||
&'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ impl<'tcx> Const<'tcx> {
|
|||
pub fn new_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
bound_const: ty::BoundConst,
|
||||
bound_const: ty::BoundConst<'tcx>,
|
||||
) -> Const<'tcx> {
|
||||
Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const))
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ impl<'tcx> Const<'tcx> {
|
|||
pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> {
|
||||
Const::new(
|
||||
tcx,
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }),
|
||||
ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst::new(var)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -183,13 +183,13 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
|||
fn new_bound(
|
||||
interner: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
bound_const: ty::BoundConst,
|
||||
bound_const: ty::BoundConst<'tcx>,
|
||||
) -> Self {
|
||||
Const::new_bound(interner, debruijn, bound_const)
|
||||
}
|
||||
|
||||
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
|
||||
Const::new_bound(tcx, debruijn, ty::BoundConst { var })
|
||||
Const::new_bound(tcx, debruijn, ty::BoundConst::new(var))
|
||||
}
|
||||
|
||||
fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
|
||||
|
|
|
|||
|
|
@ -108,9 +108,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind<'tcx>>;
|
||||
|
||||
type BoundVarKind = ty::BoundVariableKind;
|
||||
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
|
||||
|
||||
fn mk_predefined_opaques_in_body(
|
||||
|
|
@ -144,10 +143,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
|
||||
type FnInputTys = &'tcx [Ty<'tcx>];
|
||||
type ParamTy = ParamTy;
|
||||
type BoundTy = ty::BoundTy;
|
||||
type Symbol = Symbol;
|
||||
|
||||
type PlaceholderTy = ty::PlaceholderType<'tcx>;
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
|
||||
|
|
@ -157,10 +154,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type Safety = hir::Safety;
|
||||
type Abi = ExternAbi;
|
||||
type Const = ty::Const<'tcx>;
|
||||
type PlaceholderConst = ty::PlaceholderConst<'tcx>;
|
||||
|
||||
type ParamConst = ty::ParamConst;
|
||||
type BoundConst = ty::BoundConst;
|
||||
type ValueConst = ty::Value<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
type ValTree = ty::ValTree<'tcx>;
|
||||
|
|
@ -169,8 +164,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type Region = Region<'tcx>;
|
||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||
type LateParamRegion = ty::LateParamRegion;
|
||||
type BoundRegion = ty::BoundRegion;
|
||||
type PlaceholderRegion = ty::PlaceholderRegion<'tcx>;
|
||||
|
||||
type RegionAssumptions = &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>>;
|
||||
|
||||
|
|
@ -776,6 +769,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
) -> (QueryResult<'tcx>, &'tcx inspect::Probe<TyCtxt<'tcx>>) {
|
||||
self.evaluate_root_goal_for_proof_tree_raw(canonical_goal)
|
||||
}
|
||||
|
||||
fn item_name(self, id: DefId) -> Symbol {
|
||||
let id = id.into_query_param();
|
||||
self.opt_item_name(id).unwrap_or_else(|| {
|
||||
bug!("item_name: no name for {:?}", self.def_path(id));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bidirectional_lang_item_map {
|
||||
|
|
@ -938,7 +938,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
const_: InternedSet<'tcx, WithCachedTypeInfo<ty::ConstKind<'tcx>>>,
|
||||
pat: InternedSet<'tcx, PatternKind<'tcx>>,
|
||||
const_allocation: InternedSet<'tcx, Allocation>,
|
||||
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
|
||||
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind<'tcx>>>,
|
||||
layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>,
|
||||
adt_def: InternedSet<'tcx, AdtDefData>,
|
||||
external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
|
||||
|
|
@ -2530,7 +2530,7 @@ nop_list_lift! { type_lists; Ty<'a> => Ty<'tcx> }
|
|||
nop_list_lift! {
|
||||
poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>
|
||||
}
|
||||
nop_list_lift! { bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind }
|
||||
nop_list_lift! { bound_variable_kinds; ty::BoundVariableKind<'a> => ty::BoundVariableKind<'tcx> }
|
||||
|
||||
// This is the impl for `&'a GenericArgs<'a>`.
|
||||
nop_list_lift! { args; GenericArg<'a> => GenericArg<'tcx> }
|
||||
|
|
@ -2817,7 +2817,7 @@ slice_interners!(
|
|||
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
|
||||
projs: pub mk_projs(ProjectionKind),
|
||||
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
|
||||
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
|
||||
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind<'tcx>),
|
||||
fields: pub mk_fields(FieldIdx),
|
||||
local_def_ids: intern_local_def_ids(LocalDefId),
|
||||
captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>),
|
||||
|
|
@ -3242,7 +3242,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>,
|
||||
T: CollectAndApply<ty::BoundVariableKind<'tcx>, &'tcx List<ty::BoundVariableKind<'tcx>>>,
|
||||
{
|
||||
T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
|
||||
}
|
||||
|
|
@ -3362,7 +3362,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.is_late_bound_map(id.owner).is_some_and(|set| set.contains(&id.local_id))
|
||||
}
|
||||
|
||||
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
|
||||
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind<'tcx>> {
|
||||
self.mk_bound_variable_kinds(
|
||||
&self
|
||||
.late_bound_vars_map(id.owner)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_type_ir::data_structures::DelayedMap;
|
||||
|
||||
use crate::ty::{
|
||||
self, Binder, BoundConst, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
TypeVisitableExt,
|
||||
};
|
||||
|
||||
|
|
@ -58,28 +58,28 @@ where
|
|||
/// gets mapped to the same result. `BoundVarReplacer` caches by using
|
||||
/// a `DelayedMap` which does not cache the first few types it encounters.
|
||||
pub trait BoundVarReplacerDelegate<'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>;
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>;
|
||||
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx>;
|
||||
fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx>;
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx>;
|
||||
fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx>;
|
||||
}
|
||||
|
||||
/// A simple delegate taking 3 mutable functions. The used functions must
|
||||
/// always return the same result for each bound variable, no matter how
|
||||
/// frequently they are called.
|
||||
pub struct FnMutDelegate<'a, 'tcx> {
|
||||
pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
|
||||
pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
|
||||
pub consts: &'a mut (dyn FnMut(ty::BoundConst) -> ty::Const<'tcx> + 'a),
|
||||
pub regions: &'a mut (dyn FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx> + 'a),
|
||||
pub types: &'a mut (dyn FnMut(ty::BoundTy<'tcx>) -> Ty<'tcx> + 'a),
|
||||
pub consts: &'a mut (dyn FnMut(ty::BoundConst<'tcx>) -> ty::Const<'tcx> + 'a),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
|
||||
(self.regions)(br)
|
||||
}
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
|
||||
(self.types)(bt)
|
||||
}
|
||||
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
|
||||
fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
|
||||
(self.consts)(bc)
|
||||
}
|
||||
}
|
||||
|
|
@ -207,13 +207,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
mut fld_r: F,
|
||||
) -> (T, FxIndexMap<ty::BoundRegion, ty::Region<'tcx>>)
|
||||
) -> (T, FxIndexMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>)
|
||||
where
|
||||
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||
F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let mut region_map = FxIndexMap::default();
|
||||
let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
|
||||
let real_fld_r =
|
||||
|br: ty::BoundRegion<'tcx>| *region_map.entry(br).or_insert_with(|| fld_r(br));
|
||||
let value = self.instantiate_bound_regions_uncached(value, real_fld_r);
|
||||
(value, region_map)
|
||||
}
|
||||
|
|
@ -224,7 +225,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
mut replace_regions: F,
|
||||
) -> T
|
||||
where
|
||||
F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
|
||||
F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>,
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let value = value.skip_binder();
|
||||
|
|
@ -292,14 +293,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.replace_escaping_bound_vars_uncached(
|
||||
value,
|
||||
FnMutDelegate {
|
||||
regions: &mut |r: ty::BoundRegion| {
|
||||
regions: &mut |r: ty::BoundRegion<'tcx>| {
|
||||
ty::Region::new_bound(
|
||||
self,
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion { var: shift_bv(r.var), kind: r.kind },
|
||||
)
|
||||
},
|
||||
types: &mut |t: ty::BoundTy| {
|
||||
types: &mut |t: ty::BoundTy<'tcx>| {
|
||||
Ty::new_bound(
|
||||
self,
|
||||
ty::INNERMOST,
|
||||
|
|
@ -307,11 +308,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
)
|
||||
},
|
||||
consts: &mut |c| {
|
||||
ty::Const::new_bound(
|
||||
self,
|
||||
ty::INNERMOST,
|
||||
ty::BoundConst { var: shift_bv(c.var) },
|
||||
)
|
||||
ty::Const::new_bound(self, ty::INNERMOST, ty::BoundConst::new(shift_bv(c.var)))
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
@ -333,10 +330,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
{
|
||||
struct Anonymize<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
map: &'a mut FxIndexMap<ty::BoundVar, ty::BoundVariableKind>,
|
||||
map: &'a mut FxIndexMap<ty::BoundVar, ty::BoundVariableKind<'tcx>>,
|
||||
}
|
||||
impl<'tcx> BoundVarReplacerDelegate<'tcx> for Anonymize<'_, 'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx> {
|
||||
fn replace_region(&mut self, br: ty::BoundRegion<'tcx>) -> ty::Region<'tcx> {
|
||||
let entry = self.map.entry(br.var);
|
||||
let index = entry.index();
|
||||
let var = ty::BoundVar::from_usize(index);
|
||||
|
|
@ -346,7 +343,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let br = ty::BoundRegion { var, kind };
|
||||
ty::Region::new_bound(self.tcx, ty::INNERMOST, br)
|
||||
}
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
|
||||
fn replace_ty(&mut self, bt: ty::BoundTy<'tcx>) -> Ty<'tcx> {
|
||||
let entry = self.map.entry(bt.var);
|
||||
let index = entry.index();
|
||||
let var = ty::BoundVar::from_usize(index);
|
||||
|
|
@ -355,12 +352,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
.expect_ty();
|
||||
Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
|
||||
}
|
||||
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
|
||||
fn replace_const(&mut self, bc: ty::BoundConst<'tcx>) -> ty::Const<'tcx> {
|
||||
let entry = self.map.entry(bc.var);
|
||||
let index = entry.index();
|
||||
let var = ty::BoundVar::from_usize(index);
|
||||
let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
|
||||
ty::Const::new_bound(self.tcx, ty::INNERMOST, BoundConst { var })
|
||||
ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst::new(var))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,13 +97,13 @@ pub use self::predicate::{
|
|||
RegionOutlivesPredicate, SubtypePredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate,
|
||||
};
|
||||
pub use self::region::{
|
||||
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,
|
||||
RegionKind, RegionVid,
|
||||
EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region, RegionKind, RegionVid,
|
||||
};
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||
CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
|
||||
ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
|
||||
AliasTy, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind,
|
||||
BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs,
|
||||
InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst, PlaceholderRegion,
|
||||
PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
|
|
@ -914,100 +914,6 @@ impl<'tcx> DefinitionSiteHiddenType<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub type PlaceholderRegion<'tcx> = ty::Placeholder<TyCtxt<'tcx>, BoundRegion>;
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderRegion<'tcx> {
|
||||
type Bound = BoundRegion;
|
||||
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound.var
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
ty::Placeholder::new(ui, self.bound)
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, bound: BoundRegion) -> Self {
|
||||
ty::Placeholder::new(ui, bound)
|
||||
}
|
||||
|
||||
fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
ty::Placeholder::new(ui, BoundRegion { var, kind: BoundRegionKind::Anon })
|
||||
}
|
||||
}
|
||||
|
||||
pub type PlaceholderType<'tcx> = ty::Placeholder<TyCtxt<'tcx>, BoundTy>;
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderType<'tcx> {
|
||||
type Bound = BoundTy;
|
||||
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound.var
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
ty::Placeholder::new(ui, self.bound)
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, bound: BoundTy) -> Self {
|
||||
ty::Placeholder::new(ui, bound)
|
||||
}
|
||||
|
||||
fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
ty::Placeholder::new(ui, BoundTy { var, kind: BoundTyKind::Anon })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
#[derive(TyEncodable, TyDecodable)]
|
||||
pub struct BoundConst {
|
||||
pub var: BoundVar,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundConst {
|
||||
fn var(self) -> BoundVar {
|
||||
self.var
|
||||
}
|
||||
|
||||
fn assert_eq(self, var: ty::BoundVariableKind) {
|
||||
var.expect_const()
|
||||
}
|
||||
}
|
||||
|
||||
pub type PlaceholderConst<'tcx> = ty::Placeholder<TyCtxt<'tcx>, BoundConst>;
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::PlaceholderLike<TyCtxt<'tcx>> for PlaceholderConst<'tcx> {
|
||||
type Bound = BoundConst;
|
||||
|
||||
fn universe(self) -> UniverseIndex {
|
||||
self.universe
|
||||
}
|
||||
|
||||
fn var(self) -> BoundVar {
|
||||
self.bound.var
|
||||
}
|
||||
|
||||
fn with_updated_universe(self, ui: UniverseIndex) -> Self {
|
||||
ty::Placeholder::new(ui, self.bound)
|
||||
}
|
||||
|
||||
fn new(ui: UniverseIndex, bound: BoundConst) -> Self {
|
||||
ty::Placeholder::new(ui, bound)
|
||||
}
|
||||
|
||||
fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self {
|
||||
ty::Placeholder::new(ui, BoundConst { var })
|
||||
}
|
||||
}
|
||||
|
||||
pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo<Clause<'tcx>>;
|
||||
|
||||
impl<'tcx> rustc_type_ir::Flags for Clauses<'tcx> {
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ pub struct RegionHighlightMode<'tcx> {
|
|||
/// This is used when you have a signature like `fn foo(x: &u32,
|
||||
/// y: &'a u32)` and we want to give a name to the region of the
|
||||
/// reference `x`.
|
||||
highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
|
||||
highlight_bound_region: Option<(ty::BoundRegionKind<'tcx>, usize)>,
|
||||
}
|
||||
|
||||
impl<'tcx> RegionHighlightMode<'tcx> {
|
||||
|
|
@ -246,7 +246,7 @@ impl<'tcx> RegionHighlightMode<'tcx> {
|
|||
/// Highlight the given bound region.
|
||||
/// We can only highlight one bound region at a time. See
|
||||
/// the field `highlight_bound_region` for more detailed notes.
|
||||
pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind, number: usize) {
|
||||
pub fn highlighting_bound_region(&mut self, br: ty::BoundRegionKind<'tcx>, number: usize) {
|
||||
assert!(self.highlight_bound_region.is_none());
|
||||
self.highlight_bound_region = Some((br, number));
|
||||
}
|
||||
|
|
@ -2639,12 +2639,12 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
struct RegionFolder<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
current_index: ty::DebruijnIndex,
|
||||
region_map: UnordMap<ty::BoundRegion, ty::Region<'tcx>>,
|
||||
region_map: UnordMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>,
|
||||
name: &'a mut (
|
||||
dyn FnMut(
|
||||
Option<ty::DebruijnIndex>, // Debruijn index of the folded late-bound region
|
||||
ty::DebruijnIndex, // Index corresponding to binder level
|
||||
ty::BoundRegion,
|
||||
ty::BoundRegion<'tcx>,
|
||||
) -> ty::Region<'tcx>
|
||||
+ 'a
|
||||
),
|
||||
|
|
@ -2717,7 +2717,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
&mut self,
|
||||
value: &ty::Binder<'tcx, T>,
|
||||
mode: WrapBinderMode,
|
||||
) -> Result<(T, UnordMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error>
|
||||
) -> Result<(T, UnordMap<ty::BoundRegion<'tcx>, ty::Region<'tcx>>), fmt::Error>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
|
@ -2810,12 +2810,12 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
// see issue #102392.
|
||||
let mut name = |lifetime_idx: Option<ty::DebruijnIndex>,
|
||||
binder_level_idx: ty::DebruijnIndex,
|
||||
br: ty::BoundRegion| {
|
||||
br: ty::BoundRegion<'tcx>| {
|
||||
let (name, kind) = if let Some(name) = br.kind.get_name(tcx) {
|
||||
(name, br.kind)
|
||||
} else {
|
||||
let name = next_name(self);
|
||||
(name, ty::BoundRegionKind::NamedAnon(name))
|
||||
(name, ty::BoundRegionKind::NamedForPrinting(name))
|
||||
};
|
||||
|
||||
if let Some(lt_idx) = lifetime_idx {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ impl<'tcx> Region<'tcx> {
|
|||
pub fn new_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
bound_region: ty::BoundRegion,
|
||||
bound_region: ty::BoundRegion<'tcx>,
|
||||
) -> Region<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon } = bound_region
|
||||
|
|
@ -160,7 +160,7 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
|
|||
fn new_bound(
|
||||
interner: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundRegion,
|
||||
var: ty::BoundRegion<'tcx>,
|
||||
) -> Self {
|
||||
Region::new_bound(interner, debruijn, var)
|
||||
}
|
||||
|
|
@ -388,7 +388,7 @@ pub struct LateParamRegion {
|
|||
pub kind: LateParamRegionKind,
|
||||
}
|
||||
|
||||
/// When liberating bound regions, we map their [`BoundRegionKind`]
|
||||
/// When liberating bound regions, we map their [`ty::BoundRegionKind`]
|
||||
/// to this as we need to track the index of anonymous regions. We
|
||||
/// otherwise end up liberating multiple bound regions to the same
|
||||
/// late-bound region.
|
||||
|
|
@ -397,7 +397,7 @@ pub struct LateParamRegion {
|
|||
pub enum LateParamRegionKind {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
///
|
||||
/// Unlike [`BoundRegionKind::Anon`], this tracks the index of the
|
||||
/// Unlike [`ty::BoundRegionKind::Anon`], this tracks the index of the
|
||||
/// liberated bound region.
|
||||
///
|
||||
/// We should ideally never liberate anonymous regions, but do so for the
|
||||
|
|
@ -418,12 +418,14 @@ pub enum LateParamRegionKind {
|
|||
}
|
||||
|
||||
impl LateParamRegionKind {
|
||||
pub fn from_bound(var: BoundVar, br: BoundRegionKind) -> LateParamRegionKind {
|
||||
pub fn from_bound(var: BoundVar, br: ty::BoundRegionKind<'_>) -> LateParamRegionKind {
|
||||
match br {
|
||||
BoundRegionKind::Anon => LateParamRegionKind::Anon(var.as_u32()),
|
||||
BoundRegionKind::Named(def_id) => LateParamRegionKind::Named(def_id),
|
||||
BoundRegionKind::ClosureEnv => LateParamRegionKind::ClosureEnv,
|
||||
BoundRegionKind::NamedAnon(name) => LateParamRegionKind::NamedAnon(var.as_u32(), name),
|
||||
ty::BoundRegionKind::Anon => LateParamRegionKind::Anon(var.as_u32()),
|
||||
ty::BoundRegionKind::Named(def_id) => LateParamRegionKind::Named(def_id),
|
||||
ty::BoundRegionKind::ClosureEnv => LateParamRegionKind::ClosureEnv,
|
||||
ty::BoundRegionKind::NamedForPrinting(name) => {
|
||||
LateParamRegionKind::NamedAnon(var.as_u32(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -450,81 +452,6 @@ impl LateParamRegionKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundRegionKind {
|
||||
/// An anonymous region parameter for a given fn (&T)
|
||||
Anon,
|
||||
|
||||
/// An anonymous region parameter with a `Symbol` name.
|
||||
///
|
||||
/// Used to give late-bound regions names for things like pretty printing.
|
||||
NamedAnon(Symbol),
|
||||
|
||||
/// Late-bound regions that appear in the AST.
|
||||
Named(DefId),
|
||||
|
||||
/// Anonymous region for the implicit env pointer parameter
|
||||
/// to a closure
|
||||
ClosureEnv,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub struct BoundRegion {
|
||||
pub var: BoundVar,
|
||||
pub kind: BoundRegionKind,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion {
|
||||
fn var(self) -> BoundVar {
|
||||
self.var
|
||||
}
|
||||
|
||||
fn assert_eq(self, var: ty::BoundVariableKind) {
|
||||
assert_eq!(self.kind, var.expect_region())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for BoundRegion {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.kind {
|
||||
BoundRegionKind::Anon => write!(f, "{:?}", self.var),
|
||||
BoundRegionKind::ClosureEnv => write!(f, "{:?}.Env", self.var),
|
||||
BoundRegionKind::Named(def) => {
|
||||
write!(f, "{:?}.Named({:?})", self.var, def)
|
||||
}
|
||||
BoundRegionKind::NamedAnon(symbol) => {
|
||||
write!(f, "{:?}.NamedAnon({:?})", self.var, symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundRegionKind {
|
||||
pub fn is_named(&self, tcx: TyCtxt<'_>) -> bool {
|
||||
self.get_name(tcx).is_some()
|
||||
}
|
||||
|
||||
pub fn get_name(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
|
||||
match *self {
|
||||
BoundRegionKind::Named(def_id) => {
|
||||
let name = tcx.item_name(def_id);
|
||||
if name != kw::UnderscoreLifetime { Some(name) } else { None }
|
||||
}
|
||||
BoundRegionKind::NamedAnon(name) => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> Option<DefId> {
|
||||
match *self {
|
||||
BoundRegionKind::Named(id) => Some(id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
|
|||
|
|
@ -65,21 +65,6 @@ impl<'tcx> fmt::Debug for ty::adjustment::PatAdjustment<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::BoundRegionKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::BoundRegionKind::Anon => write!(f, "BrAnon"),
|
||||
ty::BoundRegionKind::NamedAnon(name) => {
|
||||
write!(f, "BrNamedAnon({name})")
|
||||
}
|
||||
ty::BoundRegionKind::Named(did) => {
|
||||
write!(f, "BrNamed({did:?})")
|
||||
}
|
||||
ty::BoundRegionKind::ClosureEnv => write!(f, "BrEnv"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::LateParamRegion {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ReLateParam({:?}, {:?})", self.scope, self.kind)
|
||||
|
|
@ -175,15 +160,6 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::BoundTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
ty::BoundTyKind::Anon => write!(f, "{:?}", self.var),
|
||||
ty::BoundTyKind::Param(def_id) => write!(f, "{def_id:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for GenericArg<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind() {
|
||||
|
|
@ -255,7 +231,8 @@ TrivialTypeTraversalImpls! {
|
|||
crate::ty::AdtKind,
|
||||
crate::ty::AssocItem,
|
||||
crate::ty::AssocKind,
|
||||
crate::ty::BoundRegion,
|
||||
crate::ty::BoundRegion<'tcx>,
|
||||
crate::ty::BoundTy<'tcx>,
|
||||
crate::ty::ScalarInt,
|
||||
crate::ty::UserTypeAnnotationIndex,
|
||||
crate::ty::abstract_const::NotConstEvaluatable,
|
||||
|
|
@ -284,7 +261,6 @@ TrivialTypeTraversalImpls! {
|
|||
TrivialTypeTraversalAndLiftImpls! {
|
||||
// tidy-alphabetical-start
|
||||
crate::mir::RuntimeChecks,
|
||||
crate::ty::BoundTy,
|
||||
crate::ty::ParamTy,
|
||||
crate::ty::instance::ReifyReason,
|
||||
rustc_hir::def_id::DefId,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, kw, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_type_ir::walk::TypeWalker;
|
||||
|
|
@ -26,8 +26,8 @@ use crate::infer::canonical::Canonical;
|
|||
use crate::traits::ObligationCause;
|
||||
use crate::ty::InferTy::*;
|
||||
use crate::ty::{
|
||||
self, AdtDef, BoundRegionKind, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv,
|
||||
Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
self, AdtDef, Discr, GenericArg, GenericArgs, GenericArgsRef, List, ParamEnv, Region, Ty,
|
||||
TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
|
||||
};
|
||||
|
||||
// Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
|
||||
|
|
@ -40,6 +40,15 @@ pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
|
|||
pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
|
||||
pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
|
||||
pub type Placeholder<'tcx, T> = ir::Placeholder<TyCtxt<'tcx>, T>;
|
||||
pub type PlaceholderRegion<'tcx> = ir::PlaceholderRegion<TyCtxt<'tcx>>;
|
||||
pub type PlaceholderType<'tcx> = ir::PlaceholderType<TyCtxt<'tcx>>;
|
||||
pub type PlaceholderConst<'tcx> = ir::PlaceholderConst<TyCtxt<'tcx>>;
|
||||
pub type BoundTy<'tcx> = ir::BoundTy<TyCtxt<'tcx>>;
|
||||
pub type BoundConst<'tcx> = ir::BoundConst<TyCtxt<'tcx>>;
|
||||
pub type BoundRegion<'tcx> = ir::BoundRegion<TyCtxt<'tcx>>;
|
||||
pub type BoundVariableKind<'tcx> = ir::BoundVariableKind<TyCtxt<'tcx>>;
|
||||
pub type BoundRegionKind<'tcx> = ir::BoundRegionKind<TyCtxt<'tcx>>;
|
||||
pub type BoundTyKind<'tcx> = ir::BoundTyKind<TyCtxt<'tcx>>;
|
||||
|
||||
pub trait Article {
|
||||
fn article(&self) -> &'static str;
|
||||
|
|
@ -257,37 +266,6 @@ impl<'tcx> InlineConstArgs<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundVariableKind {
|
||||
Ty(BoundTyKind),
|
||||
Region(BoundRegionKind),
|
||||
Const,
|
||||
}
|
||||
|
||||
impl BoundVariableKind {
|
||||
pub fn expect_region(self) -> BoundRegionKind {
|
||||
match self {
|
||||
BoundVariableKind::Region(lt) => lt,
|
||||
_ => bug!("expected a region, but found another kind"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_ty(self) -> BoundTyKind {
|
||||
match self {
|
||||
BoundVariableKind::Ty(ty) => ty,
|
||||
_ => bug!("expected a type, but found another kind"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_const(self) {
|
||||
match self {
|
||||
BoundVariableKind::Const => (),
|
||||
_ => bug!("expected a const, but found another kind"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
|
||||
pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
|
||||
|
||||
|
|
@ -381,30 +359,6 @@ impl ParamConst {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub struct BoundTy {
|
||||
pub var: BoundVar,
|
||||
pub kind: BoundTyKind,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy {
|
||||
fn var(self) -> BoundVar {
|
||||
self.var
|
||||
}
|
||||
|
||||
fn assert_eq(self, var: ty::BoundVariableKind) {
|
||||
assert_eq!(self.kind, var.expect_ty())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable)]
|
||||
pub enum BoundTyKind {
|
||||
Anon,
|
||||
Param(DefId),
|
||||
}
|
||||
|
||||
/// Constructors for `Ty`
|
||||
impl<'tcx> Ty<'tcx> {
|
||||
/// Avoid using this in favour of more specific `new_*` methods, where possible.
|
||||
|
|
@ -479,7 +433,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
pub fn new_bound(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
index: ty::DebruijnIndex,
|
||||
bound_ty: ty::BoundTy,
|
||||
bound_ty: ty::BoundTy<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
// Use a pre-interned one when possible.
|
||||
if let ty::BoundTy { var, kind: ty::BoundTyKind::Anon } = bound_ty
|
||||
|
|
@ -961,7 +915,11 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
|||
Ty::new_placeholder(tcx, placeholder)
|
||||
}
|
||||
|
||||
fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundTy) -> Self {
|
||||
fn new_bound(
|
||||
interner: TyCtxt<'tcx>,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
var: ty::BoundTy<'tcx>,
|
||||
) -> Self {
|
||||
Ty::new_bound(interner, debruijn, var)
|
||||
}
|
||||
|
||||
|
|
@ -2135,6 +2093,12 @@ impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Symbol<TyCtxt<'tcx>> for Symbol {
|
||||
fn is_kw_underscore_lifetime(self) -> bool {
|
||||
self == kw::UnderscoreLifetime
|
||||
}
|
||||
}
|
||||
|
||||
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn collect_constrained_late_bound_regions<T>(
|
||||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
) -> FxIndexSet<ty::BoundRegionKind>
|
||||
) -> FxIndexSet<ty::BoundRegionKind<'tcx>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
|
@ -124,7 +124,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
pub fn collect_referenced_late_bound_regions<T>(
|
||||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
) -> FxIndexSet<ty::BoundRegionKind>
|
||||
) -> FxIndexSet<ty::BoundRegionKind<'tcx>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
|
@ -135,7 +135,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self,
|
||||
value: Binder<'tcx, T>,
|
||||
just_constrained: bool,
|
||||
) -> FxIndexSet<ty::BoundRegionKind>
|
||||
) -> FxIndexSet<ty::BoundRegionKind<'tcx>>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
|
@ -149,9 +149,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
/// Collects all the late-bound regions at the innermost binding level
|
||||
/// into a hash set.
|
||||
struct LateBoundRegionsCollector {
|
||||
struct LateBoundRegionsCollector<'tcx> {
|
||||
current_index: ty::DebruijnIndex,
|
||||
regions: FxIndexSet<ty::BoundRegionKind>,
|
||||
regions: FxIndexSet<ty::BoundRegionKind<'tcx>>,
|
||||
|
||||
/// `true` if we only want regions that are known to be
|
||||
/// "constrained" when you equate this type with another type. In
|
||||
|
|
@ -163,13 +163,13 @@ struct LateBoundRegionsCollector {
|
|||
just_constrained: bool,
|
||||
}
|
||||
|
||||
impl LateBoundRegionsCollector {
|
||||
impl LateBoundRegionsCollector<'_> {
|
||||
fn new(just_constrained: bool) -> Self {
|
||||
Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector<'tcx> {
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
|
||||
self.current_index.shift_in(1);
|
||||
t.super_visit_with(self);
|
||||
|
|
|
|||
|
|
@ -91,20 +91,32 @@ macro_rules! declare_passes {
|
|||
)+
|
||||
)*
|
||||
|
||||
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
|
||||
static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| {
|
||||
let mut set = FxIndexSet::default();
|
||||
// Fake marker pass
|
||||
"PreCodegen",
|
||||
set.insert("PreCodegen");
|
||||
$(
|
||||
$(
|
||||
stringify!($pass_name),
|
||||
$(
|
||||
$(
|
||||
$mod_name::$pass_name::$ident.name(),
|
||||
)*
|
||||
)?
|
||||
set.extend(pass_names!($mod_name : $pass_name $( { $($ident),* } )? ));
|
||||
)+
|
||||
)*
|
||||
].into_iter().collect());
|
||||
set
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pass_names {
|
||||
// pass groups: only pass names inside are considered pass_names
|
||||
($mod_name:ident : $pass_group:ident { $($pass_name:ident),* $(,)? }) => {
|
||||
[
|
||||
$(
|
||||
$mod_name::$pass_group::$pass_name.name(),
|
||||
)*
|
||||
]
|
||||
};
|
||||
// lone pass names: stringify the struct or enum name
|
||||
($mod_name:ident : $pass_name:ident) => {
|
||||
[stringify!($pass_name)]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -485,47 +485,33 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
if lhs_ty.is_integral() {
|
||||
let sz = lhs_ty.primitive_size(self.tcx);
|
||||
// Integer division: the RHS must be a non-zero const.
|
||||
let rhs_val = match rhs {
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(c.const_) =>
|
||||
{
|
||||
c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
match rhs_val.map(|x| x.to_uint(sz)) {
|
||||
let rhs_val = if let Operand::Constant(rhs_c) = rhs
|
||||
&& self.should_evaluate_for_promotion_checks(rhs_c.const_)
|
||||
&& let Some(rhs_val) =
|
||||
rhs_c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
// for the zero test, int vs uint does not matter
|
||||
Some(x) if x != 0 => {} // okay
|
||||
_ => return Err(Unpromotable), // value not known or 0 -- not okay
|
||||
}
|
||||
&& rhs_val.to_uint(sz) != 0
|
||||
{
|
||||
rhs_val
|
||||
} else {
|
||||
// value not known or 0 -- not okay
|
||||
return Err(Unpromotable);
|
||||
};
|
||||
// Furthermore, for signed division, we also have to exclude `int::MIN /
|
||||
// -1`.
|
||||
if lhs_ty.is_signed() {
|
||||
match rhs_val.map(|x| x.to_int(sz)) {
|
||||
Some(-1) | None => {
|
||||
// The RHS is -1 or unknown, so we have to be careful.
|
||||
// But is the LHS int::MIN?
|
||||
let lhs_val = match lhs {
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(
|
||||
c.const_,
|
||||
) =>
|
||||
{
|
||||
c.const_
|
||||
.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let lhs_min = sz.signed_int_min();
|
||||
match lhs_val.map(|x| x.to_int(sz)) {
|
||||
// okay
|
||||
Some(x) if x != lhs_min => {}
|
||||
|
||||
// value not known or int::MIN -- not okay
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
if lhs_ty.is_signed() && rhs_val.to_int(sz) == -1 {
|
||||
// The RHS is -1, so we have to be careful. But is the LHS int::MIN?
|
||||
if let Operand::Constant(lhs_c) = lhs
|
||||
&& self.should_evaluate_for_promotion_checks(lhs_c.const_)
|
||||
&& let Some(lhs_val) =
|
||||
lhs_c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
&& let lhs_min = sz.signed_int_min()
|
||||
&& lhs_val.to_int(sz) != lhs_min
|
||||
{
|
||||
// okay
|
||||
} else {
|
||||
// value not known or int::MIN -- not okay
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ use rustc_type_ir::inherent::*;
|
|||
use rustc_type_ir::solve::{Goal, QueryInput};
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, Flags, InferCtxtLike,
|
||||
Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
Interner, PlaceholderConst, PlaceholderType, TypeFlags, TypeFoldable, TypeFolder,
|
||||
TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
|
|
@ -357,13 +358,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
},
|
||||
ty::Placeholder(placeholder) => match self.canonicalize_mode {
|
||||
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
|
||||
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
PlaceholderType::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
),
|
||||
CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder),
|
||||
},
|
||||
ty::Param(_) => match self.canonicalize_mode {
|
||||
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderTy(
|
||||
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
PlaceholderType::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
),
|
||||
CanonicalizeMode::Response { .. } => panic!("param ty in response: {t:?}"),
|
||||
},
|
||||
|
|
@ -513,17 +514,23 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
ty::InferConst::Fresh(_) => todo!(),
|
||||
},
|
||||
ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode {
|
||||
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
|
||||
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
),
|
||||
CanonicalizeMode::Input { .. } => {
|
||||
CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon(
|
||||
ty::UniverseIndex::ROOT,
|
||||
self.variables.len().into(),
|
||||
))
|
||||
}
|
||||
CanonicalizeMode::Response { .. } => {
|
||||
CanonicalVarKind::PlaceholderConst(placeholder)
|
||||
}
|
||||
},
|
||||
ty::ConstKind::Param(_) => match self.canonicalize_mode {
|
||||
CanonicalizeMode::Input { .. } => CanonicalVarKind::PlaceholderConst(
|
||||
PlaceholderLike::new_anon(ty::UniverseIndex::ROOT, self.variables.len().into()),
|
||||
),
|
||||
CanonicalizeMode::Input { .. } => {
|
||||
CanonicalVarKind::PlaceholderConst(PlaceholderConst::new_anon(
|
||||
ty::UniverseIndex::ROOT,
|
||||
self.variables.len().into(),
|
||||
))
|
||||
}
|
||||
CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"),
|
||||
},
|
||||
// FIXME: See comment above -- we could fold the region separately or something.
|
||||
|
|
|
|||
|
|
@ -177,9 +177,9 @@ where
|
|||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(c) => {
|
||||
if let ty::ConstKind::Bound(index_kind, bv) = c.kind() {
|
||||
if let ty::ConstKind::Bound(index_kind, bc) = c.kind() {
|
||||
assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
|
||||
opt_values[bv.var()] = Some(*original_value);
|
||||
opt_values[bc.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use core::panic;
|
|||
use rustc_type_ir::data_structures::IndexMap;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{
|
||||
self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
TypeVisitableExt,
|
||||
self as ty, InferCtxtLike, Interner, PlaceholderConst, PlaceholderRegion, PlaceholderType,
|
||||
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
|
||||
pub struct BoundVarReplacer<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
|
|
@ -16,9 +16,9 @@ where
|
|||
// These three maps track the bound variable that were replaced by placeholders. It might be
|
||||
// nice to remove these since we already have the `kind` in the placeholder; we really just need
|
||||
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
|
||||
mapped_regions: IndexMap<I::PlaceholderRegion, I::BoundRegion>,
|
||||
mapped_types: IndexMap<I::PlaceholderTy, I::BoundTy>,
|
||||
mapped_consts: IndexMap<I::PlaceholderConst, I::BoundConst>,
|
||||
mapped_regions: IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
|
||||
mapped_types: IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
|
||||
mapped_consts: IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
|
||||
// The current depth relative to *this* folding, *not* the entire normalization. In other words,
|
||||
// the depth of binders we've passed here.
|
||||
current_index: ty::DebruijnIndex,
|
||||
|
|
@ -40,9 +40,9 @@ where
|
|||
value: T,
|
||||
) -> (
|
||||
T,
|
||||
IndexMap<I::PlaceholderRegion, I::BoundRegion>,
|
||||
IndexMap<I::PlaceholderTy, I::BoundTy>,
|
||||
IndexMap<I::PlaceholderConst, I::BoundConst>,
|
||||
IndexMap<ty::PlaceholderRegion<I>, ty::BoundRegion<I>>,
|
||||
IndexMap<ty::PlaceholderType<I>, ty::BoundTy<I>>,
|
||||
IndexMap<ty::PlaceholderConst<I>, ty::BoundConst<I>>,
|
||||
) {
|
||||
let mut replacer = BoundVarReplacer {
|
||||
infcx,
|
||||
|
|
@ -103,7 +103,7 @@ where
|
|||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, br);
|
||||
let p = PlaceholderRegion::new(universe, br);
|
||||
self.mapped_regions.insert(p, br);
|
||||
Region::new_placeholder(self.cx(), p)
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ where
|
|||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, bound_ty);
|
||||
let p = PlaceholderType::new(universe, bound_ty);
|
||||
self.mapped_types.insert(p, bound_ty);
|
||||
Ty::new_placeholder(self.cx(), p)
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ where
|
|||
if debruijn >= self.current_index =>
|
||||
{
|
||||
let universe = self.universe_for(debruijn);
|
||||
let p = PlaceholderLike::new(universe, bound_const);
|
||||
let p = PlaceholderConst::new(universe, bound_const);
|
||||
self.mapped_consts.insert(p, bound_const);
|
||||
Const::new_placeholder(self.cx(), p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ parse_bare_cr = {$double_quotes ->
|
|||
}
|
||||
.escape = escape the character
|
||||
|
||||
parse_bare_cr_in_frontmatter = bare CR not allowed in frontmatter
|
||||
|
||||
parse_bare_cr_in_raw_string = bare CR not allowed in raw string
|
||||
|
||||
parse_binder_and_polarity = `for<...>` binder not allowed with `{$polarity}` trait polarity modifier
|
||||
|
|
@ -352,7 +354,6 @@ parse_frontmatter_length_mismatch = frontmatter close does not match the opening
|
|||
parse_frontmatter_too_many_dashes = too many `-` symbols: frontmatter openings may be delimited by up to 255 `-` symbols, but found {$len_opening}
|
||||
parse_frontmatter_unclosed = unclosed frontmatter
|
||||
.note = frontmatter opening here was not closed
|
||||
|
||||
parse_function_body_equals_expr = function body cannot be `= expression;`
|
||||
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
|
||||
|
||||
|
|
|
|||
|
|
@ -829,6 +829,13 @@ pub(crate) struct FrontmatterTooManyDashes {
|
|||
pub len_opening: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_bare_cr_in_frontmatter)]
|
||||
pub(crate) struct BareCrFrontmatter {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_leading_plus_not_supported)]
|
||||
pub(crate) struct LeadingPlusNotSupported {
|
||||
|
|
|
|||
|
|
@ -598,9 +598,9 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
let s = self.str_from(start);
|
||||
let real_start = s.find("---").unwrap();
|
||||
let frontmatter_opening_pos = BytePos(real_start as u32) + start;
|
||||
let s_new = &s[real_start..];
|
||||
let within = s_new.trim_start_matches('-');
|
||||
let len_opening = s_new.len() - within.len();
|
||||
let real_s = &s[real_start..];
|
||||
let within = real_s.trim_start_matches('-');
|
||||
let len_opening = real_s.len() - within.len();
|
||||
|
||||
let frontmatter_opening_end_pos = frontmatter_opening_pos + BytePos(len_opening as u32);
|
||||
if has_invalid_preceding_whitespace {
|
||||
|
|
@ -614,8 +614,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
});
|
||||
}
|
||||
|
||||
let line_end = real_s.find('\n').unwrap_or(real_s.len());
|
||||
if invalid_infostring {
|
||||
let line_end = s[real_start..].find('\n').unwrap_or(s[real_start..].len());
|
||||
let span = self.mk_sp(
|
||||
frontmatter_opening_end_pos,
|
||||
frontmatter_opening_pos + BytePos(line_end as u32),
|
||||
|
|
@ -623,10 +623,18 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
|
|||
self.dcx().emit_err(errors::FrontmatterInvalidInfostring { span });
|
||||
}
|
||||
|
||||
let last_line_start = within.rfind('\n').map_or(0, |i| i + 1);
|
||||
let last_line = &within[last_line_start..];
|
||||
let last_line_start = real_s.rfind('\n').map_or(0, |i| i + 1);
|
||||
|
||||
let content = &real_s[line_end..last_line_start];
|
||||
if let Some(cr_offset) = content.find('\r') {
|
||||
let cr_pos = start + BytePos((real_start + line_end + cr_offset) as u32);
|
||||
let span = self.mk_sp(cr_pos, cr_pos + BytePos(1 as u32));
|
||||
self.dcx().emit_err(errors::BareCrFrontmatter { span });
|
||||
}
|
||||
|
||||
let last_line = &real_s[last_line_start..];
|
||||
let last_line_trimmed = last_line.trim_start_matches(is_horizontal_whitespace);
|
||||
let last_line_start_pos = frontmatter_opening_end_pos + BytePos(last_line_start as u32);
|
||||
let last_line_start_pos = frontmatter_opening_pos + BytePos(last_line_start as u32);
|
||||
|
||||
let frontmatter_span = self.mk_sp(frontmatter_opening_pos, self.pos);
|
||||
self.psess.gated_spans.gate(sym::frontmatter, frontmatter_span);
|
||||
|
|
|
|||
|
|
@ -2760,9 +2760,13 @@ impl<'a> Parser<'a> {
|
|||
let (mut cond, _) =
|
||||
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
|
||||
|
||||
CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
|
||||
|
||||
Ok(cond)
|
||||
let mut checker = CondChecker::new(self, let_chains_policy);
|
||||
checker.visit_expr(&mut cond);
|
||||
Ok(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
self.mk_expr_err(cond.span, guar)
|
||||
} else {
|
||||
cond
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a `let $pat = $expr` pseudo-expression.
|
||||
|
|
@ -3484,13 +3488,19 @@ impl<'a> Parser<'a> {
|
|||
let if_span = self.prev_token.span;
|
||||
let mut cond = self.parse_match_guard_condition()?;
|
||||
|
||||
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
|
||||
checker.visit_expr(&mut cond);
|
||||
|
||||
if has_let_expr(&cond) {
|
||||
let span = if_span.to(cond.span);
|
||||
self.psess.gated_spans.gate(sym::if_let_guard, span);
|
||||
}
|
||||
Ok(Some(cond))
|
||||
|
||||
Ok(Some(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
self.mk_expr_err(cond.span, guar)
|
||||
} else {
|
||||
cond
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
|
||||
|
|
@ -3511,13 +3521,23 @@ impl<'a> Parser<'a> {
|
|||
let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
|
||||
let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
|
||||
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
|
||||
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
|
||||
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
|
||||
checker.visit_expr(&mut cond);
|
||||
|
||||
let right = self.prev_token.span;
|
||||
self.dcx().emit_err(errors::ParenthesesInMatchPat {
|
||||
span: vec![left, right],
|
||||
sugg: errors::ParenthesesInMatchPatSugg { left, right },
|
||||
});
|
||||
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
|
||||
|
||||
Ok((
|
||||
self.mk_pat(span, ast::PatKind::Wild),
|
||||
(if let Some(guar) = checker.found_incorrect_let_chain {
|
||||
Some(self.mk_expr_err(cond.span, guar))
|
||||
} else {
|
||||
Some(cond)
|
||||
}),
|
||||
))
|
||||
} else {
|
||||
Ok((pat, self.parse_match_arm_guard()?))
|
||||
}
|
||||
|
|
@ -4208,6 +4228,7 @@ struct CondChecker<'a> {
|
|||
forbid_let_reason: Option<ForbiddenLetReason>,
|
||||
missing_let: Option<errors::MaybeMissingLet>,
|
||||
comparison: Option<errors::MaybeComparison>,
|
||||
found_incorrect_let_chain: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
impl<'a> CondChecker<'a> {
|
||||
|
|
@ -4218,6 +4239,7 @@ impl<'a> CondChecker<'a> {
|
|||
missing_let: None,
|
||||
comparison: None,
|
||||
let_chains_policy,
|
||||
found_incorrect_let_chain: None,
|
||||
depth: 0,
|
||||
}
|
||||
}
|
||||
|
|
@ -4236,12 +4258,19 @@ impl MutVisitor for CondChecker<'_> {
|
|||
NotSupportedOr(or_span) => {
|
||||
self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
|
||||
}
|
||||
_ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
|
||||
span,
|
||||
reason,
|
||||
missing_let: self.missing_let,
|
||||
comparison: self.comparison,
|
||||
}),
|
||||
_ => {
|
||||
let guar =
|
||||
self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
|
||||
span,
|
||||
reason,
|
||||
missing_let: self.missing_let,
|
||||
comparison: self.comparison,
|
||||
});
|
||||
if let Some(_) = self.missing_let {
|
||||
self.found_incorrect_let_chain = Some(guar);
|
||||
}
|
||||
guar
|
||||
}
|
||||
};
|
||||
*recovered = Recovered::Yes(error);
|
||||
} else if self.depth > 1 {
|
||||
|
|
|
|||
|
|
@ -758,7 +758,7 @@ impl<'input> Parser<'input> {
|
|||
}
|
||||
|
||||
/// Parses a word starting at the current position. A word is the same as a
|
||||
/// Rust identifier, except that it can't start with `_` character.
|
||||
/// Rust identifier or keyword, except that it can't be a bare `_` character.
|
||||
fn word(&mut self) -> &'input str {
|
||||
let index = self.input_vec_index;
|
||||
match self.peek() {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
span: attr_span,
|
||||
stability: Stability { level, feature },
|
||||
}
|
||||
| AttributeKind::ConstStability {
|
||||
| AttributeKind::RustcConstStability {
|
||||
span: attr_span,
|
||||
stability: PartialConstStability { level, feature, .. },
|
||||
},
|
||||
|
|
@ -168,7 +168,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span) | AttributeKind::AllowInternalUnstable(.., attr_span)) => {
|
||||
self.check_macro_only_attr(*attr_span, span, target, attrs)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_, first_span)) => {
|
||||
Attribute::Parsed(AttributeKind::RustcAllowConstFnUnstable(_, first_span)) => {
|
||||
self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::Deprecation {span: attr_span, .. }) => {
|
||||
|
|
@ -180,7 +180,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => {
|
||||
self.check_object_lifetime_default(hir_id);
|
||||
}
|
||||
&Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => {
|
||||
&Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => {
|
||||
self.check_rustc_pub_transparent(attr_span, span, attrs)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::Align { align, span: attr_span }) => {
|
||||
|
|
@ -226,29 +226,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
|
||||
Attribute::Parsed(
|
||||
// tidy-alphabetical-start
|
||||
AttributeKind::AllowIncoherentImpl(..)
|
||||
| AttributeKind::AsPtr(..)
|
||||
AttributeKind::RustcAllowIncoherentImpl(..)
|
||||
| AttributeKind::AutomaticallyDerived(..)
|
||||
| AttributeKind::BodyStability { .. }
|
||||
| AttributeKind::CfgAttrTrace
|
||||
| AttributeKind::CfgTrace(..)
|
||||
| AttributeKind::CfiEncoding { .. }
|
||||
| AttributeKind::Coinductive(..)
|
||||
| AttributeKind::Cold(..)
|
||||
| AttributeKind::CollapseDebugInfo(..)
|
||||
| AttributeKind::CompilerBuiltins
|
||||
| AttributeKind::Confusables { .. }
|
||||
| AttributeKind::ConstStabilityIndirect
|
||||
| AttributeKind::Coroutine(..)
|
||||
| AttributeKind::Coverage (..)
|
||||
| AttributeKind::CrateName { .. }
|
||||
| AttributeKind::CrateType(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
| AttributeKind::DenyExplicitImpl(..)
|
||||
// `#[doc]` is actually a lot more than just doc comments, so is checked below
|
||||
| AttributeKind::DocComment {..}
|
||||
| AttributeKind::Dummy
|
||||
| AttributeKind::DynIncompatibleTrait(..)
|
||||
| AttributeKind::EiiDeclaration { .. }
|
||||
| AttributeKind::EiiForeignItem
|
||||
| AttributeKind::ExportName { .. }
|
||||
|
|
@ -262,7 +254,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::LinkSection { .. }
|
||||
| AttributeKind::Linkage(..)
|
||||
| AttributeKind::MacroEscape( .. )
|
||||
| AttributeKind::MacroTransparency(_)
|
||||
| AttributeKind::MacroUse { .. }
|
||||
| AttributeKind::Marker(..)
|
||||
| AttributeKind::MoveSizeLimit { .. }
|
||||
|
|
@ -277,12 +268,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::NoMain
|
||||
| AttributeKind::NoMangle(..)
|
||||
| AttributeKind::NoStd { .. }
|
||||
| AttributeKind::ObjcClass { .. }
|
||||
| AttributeKind::ObjcSelector { .. }
|
||||
| AttributeKind::Optimize(..)
|
||||
| AttributeKind::PanicRuntime
|
||||
| AttributeKind::ParenSugar(..)
|
||||
| AttributeKind::PassByValue (..)
|
||||
| AttributeKind::PatchableFunctionEntry { .. }
|
||||
| AttributeKind::Path(..)
|
||||
| AttributeKind::PatternComplexityLimit { .. }
|
||||
|
|
@ -295,14 +282,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcAllocator
|
||||
| AttributeKind::RustcAllocatorZeroed
|
||||
| AttributeKind::RustcAllocatorZeroedVariant { .. }
|
||||
| AttributeKind::RustcAsPtr(..)
|
||||
| AttributeKind::RustcBodyStability { .. }
|
||||
| AttributeKind::RustcBuiltinMacro { .. }
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::RustcCoinductive(..)
|
||||
| AttributeKind::RustcConfusables { .. }
|
||||
| AttributeKind::RustcConstStabilityIndirect
|
||||
| AttributeKind::RustcDeallocator
|
||||
| AttributeKind::RustcDenyExplicitImpl(..)
|
||||
| AttributeKind::RustcDummy
|
||||
| AttributeKind::RustcDumpDefParents
|
||||
| AttributeKind::RustcDumpItemBounds
|
||||
| AttributeKind::RustcDumpPredicates
|
||||
| AttributeKind::RustcDumpUserArgs
|
||||
| AttributeKind::RustcDumpVtable(..)
|
||||
| AttributeKind::RustcDynIncompatibleTrait(..)
|
||||
| AttributeKind::RustcHasIncoherentInherentImpls
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
|
|
@ -310,26 +305,31 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcLintOptTy
|
||||
| AttributeKind::RustcLintQueryInstability
|
||||
| AttributeKind::RustcLintUntrackedQueryInformation
|
||||
| AttributeKind::RustcMacroTransparency(_)
|
||||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcNounwind
|
||||
| AttributeKind::RustcObjcClass { .. }
|
||||
| AttributeKind::RustcObjcSelector { .. }
|
||||
| AttributeKind::RustcOffloadKernel
|
||||
| AttributeKind::RustcParenSugar(..)
|
||||
| AttributeKind::RustcPassByValue (..)
|
||||
| AttributeKind::RustcPassIndirectlyInNonRusticAbis(..)
|
||||
| AttributeKind::RustcReallocator
|
||||
| AttributeKind::RustcScalableVector { .. }
|
||||
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::RustcSkipDuringMethodDispatch { .. }
|
||||
| AttributeKind::RustcSpecializationTrait(..)
|
||||
| AttributeKind::RustcStdInternalSymbol (..)
|
||||
| AttributeKind::RustcUnsafeSpecializationMarker(..)
|
||||
| AttributeKind::RustcVariance
|
||||
| AttributeKind::RustcVarianceOfOpaques
|
||||
| AttributeKind::ShouldPanic { .. }
|
||||
| AttributeKind::SkipDuringMethodDispatch { .. }
|
||||
| AttributeKind::SpecializationTrait(..)
|
||||
| AttributeKind::StdInternalSymbol (..)
|
||||
| AttributeKind::ThreadLocal
|
||||
| AttributeKind::TypeConst{..}
|
||||
| AttributeKind::TypeLengthLimit { .. }
|
||||
| AttributeKind::UnsafeSpecializationMarker(..)
|
||||
| AttributeKind::UnstableFeatureBound(..)
|
||||
| AttributeKind::Used { .. }
|
||||
| AttributeKind::WindowsSubsystem(..)
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::Stability { stability, span }) => {
|
||||
(stability.feature, stability.level, *span)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => {
|
||||
Attribute::Parsed(AttributeKind::RustcConstStability { stability, span }) => {
|
||||
(stability.feature, stability.level, *span)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => {
|
||||
Attribute::Parsed(AttributeKind::RustcBodyStability { stability, span }) => {
|
||||
(stability.feature, stability.level, *span)
|
||||
}
|
||||
_ => return None,
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ fn lookup_default_body_stability(
|
|||
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
|
||||
// FIXME: check that this item can have body stability
|
||||
find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability)
|
||||
find_attr!(attrs, AttributeKind::RustcBodyStability { stability, .. } => *stability)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
|
|
@ -214,7 +214,7 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstSt
|
|||
{
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
|
||||
let const_stability_indirect =
|
||||
find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
|
||||
find_attr!(attrs, AttributeKind::RustcConstStabilityIndirect);
|
||||
return Some(ConstStability::unmarked(const_stability_indirect, parent_stab));
|
||||
}
|
||||
}
|
||||
|
|
@ -223,9 +223,9 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstSt
|
|||
}
|
||||
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
|
||||
let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
|
||||
let const_stability_indirect = find_attr!(attrs, AttributeKind::RustcConstStabilityIndirect);
|
||||
let const_stab =
|
||||
find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability);
|
||||
find_attr!(attrs, AttributeKind::RustcConstStability { stability, span: _ } => *stability);
|
||||
|
||||
// After checking the immediate attributes, get rid of the span and compute implied
|
||||
// const stability: inherit feature gate from regular stability.
|
||||
|
|
@ -393,7 +393,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
|||
if let Some(fn_sig) = fn_sig
|
||||
&& !fn_sig.header.is_const()
|
||||
&& const_stab.is_some()
|
||||
&& find_attr_span!(ConstStability).is_some()
|
||||
&& find_attr_span!(RustcConstStability).is_some()
|
||||
{
|
||||
self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
|
||||
}
|
||||
|
|
@ -403,7 +403,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
|||
&& let Some(fn_sig) = fn_sig
|
||||
&& const_stab.is_const_stable()
|
||||
&& !stab.is_some_and(|s| s.is_stable())
|
||||
&& let Some(const_span) = find_attr_span!(ConstStability)
|
||||
&& let Some(const_span) = find_attr_span!(RustcConstStability)
|
||||
{
|
||||
self.tcx
|
||||
.dcx()
|
||||
|
|
@ -413,7 +413,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
|
|||
if let Some(stab) = &const_stab
|
||||
&& stab.is_const_stable()
|
||||
&& stab.const_stable_indirect
|
||||
&& let Some(span) = find_attr_span!(ConstStability)
|
||||
&& let Some(span) = find_attr_span!(RustcConstStability)
|
||||
{
|
||||
self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span });
|
||||
}
|
||||
|
|
@ -602,7 +602,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
let stab = find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
|
||||
|
||||
// FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
|
||||
let const_stab = find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
|
||||
let const_stab = find_attr!(attrs, AttributeKind::RustcConstStability{stability, ..} => *stability);
|
||||
|
||||
let unstable_feature_stab =
|
||||
find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
|||
let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
|
||||
let attrs = self.tcx.hir_attrs(hir_id);
|
||||
|
||||
if find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
|
||||
if find_attr!(attrs, AttributeKind::RustcMacroTransparency(x) => *x)
|
||||
.unwrap_or(Transparency::fallback(md.macro_rules))
|
||||
!= Transparency::Opaque
|
||||
{
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ where
|
|||
}
|
||||
|
||||
impl RustcInternal for BoundVariableKind {
|
||||
type T<'tcx> = rustc_ty::BoundVariableKind;
|
||||
type T<'tcx> = rustc_ty::BoundVariableKind<'tcx>;
|
||||
|
||||
fn internal<'tcx>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundTyKind<'tcx> {
|
||||
type T = crate::ty::BoundTyKind;
|
||||
|
||||
fn stable<'cx>(
|
||||
|
|
@ -290,7 +290,7 @@ impl<'tcx> Stable<'tcx> for ty::BoundTyKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundRegionKind<'tcx> {
|
||||
type T = crate::ty::BoundRegionKind;
|
||||
|
||||
fn stable<'cx>(
|
||||
|
|
@ -307,12 +307,12 @@ impl<'tcx> Stable<'tcx> for ty::BoundRegionKind {
|
|||
cx.tcx.item_name(*def_id).to_string(),
|
||||
),
|
||||
ty::BoundRegionKind::ClosureEnv => BoundRegionKind::BrEnv,
|
||||
ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => bug!("only used for pretty printing"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundVariableKind {
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundVariableKind<'tcx> {
|
||||
type T = crate::ty::BoundVariableKind;
|
||||
|
||||
fn stable<'cx>(
|
||||
|
|
@ -546,7 +546,7 @@ impl<'tcx> Stable<'tcx> for ty::ParamTy {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundTy {
|
||||
impl<'tcx> Stable<'tcx> for ty::BoundTy<'tcx> {
|
||||
type T = crate::ty::BoundTy;
|
||||
fn stable<'cx>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,10 @@ impl<'tcx> InternalCx<'tcx> for TyCtxt<'tcx> {
|
|||
fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>,
|
||||
T: ty::CollectAndApply<
|
||||
ty::BoundVariableKind<'tcx>,
|
||||
&'tcx List<ty::BoundVariableKind<'tcx>>,
|
||||
>,
|
||||
{
|
||||
TyCtxt::mk_bound_variable_kinds_from_iter(self, iter)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ pub trait InternalCx<'tcx>: Copy + Clone {
|
|||
fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: ty::CollectAndApply<ty::BoundVariableKind, &'tcx List<ty::BoundVariableKind>>;
|
||||
T: ty::CollectAndApply<
|
||||
ty::BoundVariableKind<'tcx>,
|
||||
&'tcx List<ty::BoundVariableKind<'tcx>>,
|
||||
>;
|
||||
|
||||
fn mk_place_elems(self, v: &[mir::PlaceElem<'tcx>]) -> &'tcx List<mir::PlaceElem<'tcx>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,17 @@ use rustc_data_structures::stable_hasher::HashStable;
|
|||
use rustc_data_structures::sync::AtomicU64;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::{self, DepKind, DepKindVTable, DepNodeIndex};
|
||||
use rustc_middle::query::erase::{Erase, erase, restore};
|
||||
use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
|
||||
use rustc_middle::query::plumbing::{DynamicQuery, QuerySystem, QuerySystemFns};
|
||||
use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable};
|
||||
use rustc_middle::query::{
|
||||
AsLocalKey, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
|
||||
queries,
|
||||
AsLocalKey, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, queries,
|
||||
};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_query_system::Value;
|
||||
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode,
|
||||
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryDispatcher, QueryMap, QueryMode,
|
||||
QueryStackDeferred, QueryState, get_query_incr, get_query_non_incr,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
|
@ -37,45 +35,54 @@ pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all};
|
|||
mod profiling_support;
|
||||
pub use self::profiling_support::alloc_self_profile_query_strings;
|
||||
|
||||
struct DynamicConfig<
|
||||
/// Combines a [`QueryVTable`] with some additional compile-time booleans
|
||||
/// to implement [`QueryDispatcher`], for use by code in [`rustc_query_system`].
|
||||
///
|
||||
/// Baking these boolean flags into the type gives a modest but measurable
|
||||
/// improvement to compiler perf and compiler code size; see
|
||||
/// <https://github.com/rust-lang/rust/pull/151633>.
|
||||
struct SemiDynamicQueryDispatcher<
|
||||
'tcx,
|
||||
C: QueryCache,
|
||||
const ANON: bool,
|
||||
const DEPTH_LIMIT: bool,
|
||||
const FEEDABLE: bool,
|
||||
> {
|
||||
dynamic: &'tcx DynamicQuery<'tcx, C>,
|
||||
vtable: &'tcx QueryVTable<'tcx, C>,
|
||||
}
|
||||
|
||||
// Manually implement Copy/Clone, because deriving would put trait bounds on the cache type.
|
||||
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy
|
||||
for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
{
|
||||
}
|
||||
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone
|
||||
for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
// This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`.
|
||||
impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool>
|
||||
QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
QueryDispatcher for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
|
||||
where
|
||||
for<'a> C::Key: HashStable<StableHashingContext<'a>>,
|
||||
{
|
||||
type Qcx = QueryCtxt<'tcx>;
|
||||
type Key = C::Key;
|
||||
type Value = C::Value;
|
||||
type Cache = C;
|
||||
|
||||
#[inline(always)]
|
||||
fn name(self) -> &'static str {
|
||||
self.dynamic.name
|
||||
self.vtable.name
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
|
||||
(self.dynamic.cache_on_disk)(tcx, key)
|
||||
(self.vtable.cache_on_disk)(tcx, key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -90,33 +97,30 @@ where
|
|||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
|
||||
.byte_add(self.dynamic.query_state)
|
||||
.byte_add(self.vtable.query_state)
|
||||
.cast::<QueryState<Self::Key, QueryStackDeferred<'tcx>>>()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache {
|
||||
// Safety:
|
||||
// This is just manually doing the subfield referencing through pointer math.
|
||||
unsafe {
|
||||
&*(&qcx.tcx.query_system.caches as *const QueryCaches<'tcx>)
|
||||
.byte_add(self.dynamic.query_cache)
|
||||
.byte_add(self.vtable.query_cache)
|
||||
.cast::<Self::Cache>()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
|
||||
(self.dynamic.execute_query)(tcx, key)
|
||||
(self.vtable.execute_query)(tcx, key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
|
||||
(self.dynamic.compute)(qcx.tcx, key)
|
||||
(self.vtable.compute)(qcx.tcx, key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -127,8 +131,8 @@ where
|
|||
prev_index: SerializedDepNodeIndex,
|
||||
index: DepNodeIndex,
|
||||
) -> Option<Self::Value> {
|
||||
if self.dynamic.can_load_from_disk {
|
||||
(self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index)
|
||||
if self.vtable.can_load_from_disk {
|
||||
(self.vtable.try_load_from_disk)(qcx.tcx, key, prev_index, index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -141,7 +145,7 @@ where
|
|||
key: &Self::Key,
|
||||
index: SerializedDepNodeIndex,
|
||||
) -> bool {
|
||||
(self.dynamic.loadable_from_disk)(qcx.tcx, key, index)
|
||||
(self.vtable.loadable_from_disk)(qcx.tcx, key, index)
|
||||
}
|
||||
|
||||
fn value_from_cycle_error(
|
||||
|
|
@ -150,12 +154,12 @@ where
|
|||
cycle_error: &CycleError,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self::Value {
|
||||
(self.dynamic.value_from_cycle_error)(tcx, cycle_error, guar)
|
||||
(self.vtable.value_from_cycle_error)(tcx, cycle_error, guar)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn format_value(self) -> fn(&Self::Value) -> String {
|
||||
self.dynamic.format_value
|
||||
self.vtable.format_value
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -165,7 +169,7 @@ where
|
|||
|
||||
#[inline(always)]
|
||||
fn eval_always(self) -> bool {
|
||||
self.dynamic.eval_always
|
||||
self.vtable.eval_always
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -180,31 +184,40 @@ where
|
|||
|
||||
#[inline(always)]
|
||||
fn dep_kind(self) -> DepKind {
|
||||
self.dynamic.dep_kind
|
||||
self.vtable.dep_kind
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cycle_error_handling(self) -> CycleErrorHandling {
|
||||
self.dynamic.cycle_error_handling
|
||||
self.vtable.cycle_error_handling
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hash_result(self) -> HashResult<Self::Value> {
|
||||
self.dynamic.hash_result
|
||||
self.vtable.hash_result
|
||||
}
|
||||
}
|
||||
|
||||
/// This is implemented per query. It allows restoring query values from their erased state
|
||||
/// and constructing a QueryConfig.
|
||||
trait QueryConfigRestored<'tcx> {
|
||||
type RestoredValue;
|
||||
type Config: QueryConfig<QueryCtxt<'tcx>>;
|
||||
/// Provides access to vtable-like operations for a query
|
||||
/// (by creating a [`QueryDispatcher`]),
|
||||
/// but also keeps track of the "unerased" value type of the query
|
||||
/// (i.e. the actual result type in the query declaration).
|
||||
///
|
||||
/// This trait allows some per-query code to be defined in generic functions
|
||||
/// with a trait bound, instead of having to be defined inline within a macro
|
||||
/// expansion.
|
||||
///
|
||||
/// There is one macro-generated implementation of this trait for each query,
|
||||
/// on the type `rustc_query_impl::query_impl::$name::QueryType`.
|
||||
trait QueryDispatcherUnerased<'tcx> {
|
||||
type UnerasedValue;
|
||||
type Dispatcher: QueryDispatcher<Qcx = QueryCtxt<'tcx>>;
|
||||
|
||||
const NAME: &'static &'static str;
|
||||
|
||||
fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
|
||||
fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
|
||||
-> Self::RestoredValue;
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher;
|
||||
|
||||
fn restore_val(value: <Self::Dispatcher as QueryDispatcher>::Value) -> Self::UnerasedValue;
|
||||
}
|
||||
|
||||
pub fn query_system<'a>(
|
||||
|
|
@ -217,7 +230,7 @@ pub fn query_system<'a>(
|
|||
states: Default::default(),
|
||||
arenas: Default::default(),
|
||||
caches: Default::default(),
|
||||
dynamic_queries: dynamic_queries(),
|
||||
query_vtables: make_query_vtables(),
|
||||
on_disk_cache,
|
||||
fns: QuerySystemFns {
|
||||
engine: engine(incremental),
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ use rustc_middle::ty::{self, TyCtxt};
|
|||
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect,
|
||||
QueryCache, QueryContext, QueryDispatcher, QueryJobId, QueryMap, QuerySideEffect,
|
||||
QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query,
|
||||
};
|
||||
use rustc_query_system::{QueryOverflow, QueryOverflowNote};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
|
||||
use crate::QueryConfigRestored;
|
||||
use crate::QueryDispatcherUnerased;
|
||||
|
||||
/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
|
||||
/// crate does not have direct access to [`TyCtxt`].
|
||||
|
|
@ -281,7 +281,10 @@ macro_rules! feedable {
|
|||
|
||||
macro_rules! hash_result {
|
||||
([][$V:ty]) => {{
|
||||
Some(|hcx, result| dep_graph::hash_result(hcx, &restore::<$V>(*result)))
|
||||
Some(|hcx, result| {
|
||||
let result = ::rustc_middle::query::erase::restore_val::<$V>(*result);
|
||||
::rustc_query_system::dep_graph::hash_result(hcx, &result)
|
||||
})
|
||||
}};
|
||||
([(no_hash) $($rest:tt)*][$V:ty]) => {{
|
||||
None
|
||||
|
|
@ -387,13 +390,13 @@ pub(crate) fn create_query_frame<
|
|||
}
|
||||
|
||||
pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
||||
query: Q::Config,
|
||||
query: Q::Dispatcher,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
encoder: &mut CacheEncoder<'a, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex,
|
||||
) where
|
||||
Q: super::QueryConfigRestored<'tcx>,
|
||||
Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
|
||||
Q: QueryDispatcherUnerased<'tcx>,
|
||||
Q::UnerasedValue: Encodable<CacheEncoder<'a, 'tcx>>,
|
||||
{
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());
|
||||
|
||||
|
|
@ -408,13 +411,13 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
|||
|
||||
// Encode the type check tables with the `SerializedDepNodeIndex`
|
||||
// as tag.
|
||||
encoder.encode_tagged(dep_node, &Q::restore(*value));
|
||||
encoder.encode_tagged(dep_node, &Q::restore_val(*value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn query_key_hash_verify<'tcx>(
|
||||
query: impl QueryConfig<QueryCtxt<'tcx>>,
|
||||
query: impl QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
) {
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());
|
||||
|
|
@ -442,7 +445,7 @@ pub(crate) fn query_key_hash_verify<'tcx>(
|
|||
|
||||
fn try_load_from_on_disk_cache<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode)
|
||||
where
|
||||
Q: QueryConfig<QueryCtxt<'tcx>>,
|
||||
Q: QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
debug_assert!(tcx.dep_graph.is_green(&dep_node));
|
||||
|
||||
|
|
@ -488,7 +491,7 @@ where
|
|||
|
||||
fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
|
||||
where
|
||||
Q: QueryConfig<QueryCtxt<'tcx>>,
|
||||
Q: QueryDispatcher<Qcx = QueryCtxt<'tcx>>,
|
||||
{
|
||||
// We must avoid ever having to call `force_from_dep_node()` for a
|
||||
// `DepNode::codegen_unit`:
|
||||
|
|
@ -521,9 +524,9 @@ pub(crate) fn make_dep_kind_vtable_for_query<'tcx, Q>(
|
|||
is_eval_always: bool,
|
||||
) -> DepKindVTable<'tcx>
|
||||
where
|
||||
Q: QueryConfigRestored<'tcx>,
|
||||
Q: QueryDispatcherUnerased<'tcx>,
|
||||
{
|
||||
let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style();
|
||||
let fingerprint_style = <Q::Dispatcher as QueryDispatcher>::Key::fingerprint_style();
|
||||
|
||||
if is_anon || !fingerprint_style.reconstructible() {
|
||||
return DepKindVTable {
|
||||
|
|
@ -541,10 +544,10 @@ where
|
|||
is_eval_always,
|
||||
fingerprint_style,
|
||||
force_from_dep_node: Some(|tcx, dep_node, _| {
|
||||
force_from_dep_node(Q::config(tcx), tcx, dep_node)
|
||||
force_from_dep_node(Q::query_dispatcher(tcx), tcx, dep_node)
|
||||
}),
|
||||
try_load_from_on_disk_cache: Some(|tcx, dep_node| {
|
||||
try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node)
|
||||
try_load_from_on_disk_cache(Q::query_dispatcher(tcx), tcx, dep_node)
|
||||
}),
|
||||
name: Q::NAME,
|
||||
}
|
||||
|
|
@ -597,6 +600,7 @@ macro_rules! define_queries {
|
|||
pub(crate) mod query_impl { $(pub(crate) mod $name {
|
||||
use super::super::*;
|
||||
use std::marker::PhantomData;
|
||||
use ::rustc_middle::query::erase::{self, Erased};
|
||||
|
||||
pub(crate) mod get_query_incr {
|
||||
use super::*;
|
||||
|
|
@ -609,11 +613,11 @@ macro_rules! define_queries {
|
|||
span: Span,
|
||||
key: queries::$name::Key<'tcx>,
|
||||
mode: QueryMode,
|
||||
) -> Option<Erase<queries::$name::Value<'tcx>>> {
|
||||
) -> Option<Erased<queries::$name::Value<'tcx>>> {
|
||||
#[cfg(debug_assertions)]
|
||||
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
|
||||
get_query_incr(
|
||||
QueryType::config(tcx),
|
||||
QueryType::query_dispatcher(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
span,
|
||||
key,
|
||||
|
|
@ -631,9 +635,9 @@ macro_rules! define_queries {
|
|||
span: Span,
|
||||
key: queries::$name::Key<'tcx>,
|
||||
__mode: QueryMode,
|
||||
) -> Option<Erase<queries::$name::Value<'tcx>>> {
|
||||
) -> Option<Erased<queries::$name::Value<'tcx>>> {
|
||||
Some(get_query_non_incr(
|
||||
QueryType::config(tcx),
|
||||
QueryType::query_dispatcher(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
span,
|
||||
key,
|
||||
|
|
@ -641,10 +645,10 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dynamic_query<'tcx>()
|
||||
-> DynamicQuery<'tcx, queries::$name::Storage<'tcx>>
|
||||
pub(crate) fn make_query_vtable<'tcx>()
|
||||
-> QueryVTable<'tcx, queries::$name::Storage<'tcx>>
|
||||
{
|
||||
DynamicQuery {
|
||||
QueryVTable {
|
||||
name: stringify!($name),
|
||||
eval_always: is_eval_always!([$($modifiers)*]),
|
||||
dep_kind: dep_graph::dep_kinds::$name,
|
||||
|
|
@ -652,7 +656,7 @@ macro_rules! define_queries {
|
|||
query_state: std::mem::offset_of!(QueryStates<'tcx>, $name),
|
||||
query_cache: std::mem::offset_of!(QueryCaches<'tcx>, $name),
|
||||
cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key),
|
||||
execute_query: |tcx, key| erase(tcx.$name(key)),
|
||||
execute_query: |tcx, key| erase::erase_val(tcx.$name(key)),
|
||||
compute: |tcx, key| {
|
||||
#[cfg(debug_assertions)]
|
||||
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
|
||||
|
|
@ -690,7 +694,7 @@ macro_rules! define_queries {
|
|||
}),
|
||||
value_from_cycle_error: |tcx, cycle, guar| {
|
||||
let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar);
|
||||
erase(result)
|
||||
erase::erase_val(result)
|
||||
},
|
||||
loadable_from_disk: |_tcx, _key, _index| {
|
||||
should_ever_cache_on_disk!([$($modifiers)*] {
|
||||
|
|
@ -701,7 +705,7 @@ macro_rules! define_queries {
|
|||
})
|
||||
},
|
||||
hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]),
|
||||
format_value: |value| format!("{:?}", restore::<queries::$name::Value<'tcx>>(*value)),
|
||||
format_value: |value| format!("{:?}", erase::restore_val::<queries::$name::Value<'tcx>>(*value)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -710,9 +714,9 @@ macro_rules! define_queries {
|
|||
data: PhantomData<&'tcx ()>
|
||||
}
|
||||
|
||||
impl<'tcx> QueryConfigRestored<'tcx> for QueryType<'tcx> {
|
||||
type RestoredValue = queries::$name::Value<'tcx>;
|
||||
type Config = DynamicConfig<
|
||||
impl<'tcx> QueryDispatcherUnerased<'tcx> for QueryType<'tcx> {
|
||||
type UnerasedValue = queries::$name::Value<'tcx>;
|
||||
type Dispatcher = SemiDynamicQueryDispatcher<
|
||||
'tcx,
|
||||
queries::$name::Storage<'tcx>,
|
||||
{ is_anon!([$($modifiers)*]) },
|
||||
|
|
@ -723,15 +727,15 @@ macro_rules! define_queries {
|
|||
const NAME: &'static &'static str = &stringify!($name);
|
||||
|
||||
#[inline(always)]
|
||||
fn config(tcx: TyCtxt<'tcx>) -> Self::Config {
|
||||
DynamicConfig {
|
||||
dynamic: &tcx.query_system.dynamic_queries.$name,
|
||||
fn query_dispatcher(tcx: TyCtxt<'tcx>) -> Self::Dispatcher {
|
||||
SemiDynamicQueryDispatcher {
|
||||
vtable: &tcx.query_system.query_vtables.$name,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue {
|
||||
restore::<queries::$name::Value<'tcx>>(value)
|
||||
fn restore_val(value: <Self::Dispatcher as QueryDispatcher>::Value) -> Self::UnerasedValue {
|
||||
erase::restore_val::<queries::$name::Value<'tcx>>(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -782,7 +786,7 @@ macro_rules! define_queries {
|
|||
query_result_index: &mut EncodedDepNodeIndex
|
||||
) {
|
||||
$crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>(
|
||||
query_impl::$name::QueryType::config(tcx),
|
||||
query_impl::$name::QueryType::query_dispatcher(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
encoder,
|
||||
query_result_index,
|
||||
|
|
@ -792,7 +796,7 @@ macro_rules! define_queries {
|
|||
|
||||
pub(crate) fn query_key_hash_verify<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
$crate::plumbing::query_key_hash_verify(
|
||||
query_impl::$name::QueryType::config(tcx),
|
||||
query_impl::$name::QueryType::query_dispatcher(tcx),
|
||||
QueryCtxt::new(tcx),
|
||||
)
|
||||
}
|
||||
|
|
@ -810,10 +814,10 @@ macro_rules! define_queries {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> {
|
||||
DynamicQueries {
|
||||
pub fn make_query_vtables<'tcx>() -> ::rustc_middle::query::PerQueryVTables<'tcx> {
|
||||
::rustc_middle::query::PerQueryVTables {
|
||||
$(
|
||||
$name: query_impl::$name::dynamic_query(),
|
||||
$name: query_impl::$name::make_query_vtable(),
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
//! Query configuration and description traits.
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
|
|
@ -7,19 +5,35 @@ use rustc_data_structures::fingerprint::Fingerprint;
|
|||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use super::QueryStackFrameExtra;
|
||||
use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
|
||||
use crate::dep_graph::{DepKind, DepNode, DepNodeParams, HasDepContext, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::query::caches::QueryCache;
|
||||
use crate::query::{CycleError, CycleErrorHandling, DepNodeIndex, QueryContext, QueryState};
|
||||
|
||||
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
|
||||
|
||||
pub trait QueryConfig<Qcx: QueryContext>: Copy {
|
||||
/// Unambiguous shorthand for `<This::Qcx as HasDepContext>::DepContext`.
|
||||
#[expect(type_alias_bounds)]
|
||||
type DepContextOf<This: QueryDispatcher> =
|
||||
<<This as QueryDispatcher>::Qcx as HasDepContext>::DepContext;
|
||||
|
||||
/// Trait that can be used as a vtable for a single query, providing operations
|
||||
/// and metadata for that query.
|
||||
///
|
||||
/// Implemented by `rustc_query_impl::SemiDynamicQueryDispatcher`, which
|
||||
/// mostly delegates to `rustc_middle::query::plumbing::QueryVTable`.
|
||||
/// Those types are not visible from this `rustc_query_system` crate.
|
||||
///
|
||||
/// "Dispatcher" should be understood as a near-synonym of "vtable".
|
||||
pub trait QueryDispatcher: Copy {
|
||||
fn name(self) -> &'static str;
|
||||
|
||||
/// Query context used by this dispatcher, i.e. `rustc_query_impl::QueryCtxt`.
|
||||
type Qcx: QueryContext;
|
||||
|
||||
// `Key` and `Value` are `Copy` instead of `Clone` to ensure copying them stays cheap,
|
||||
// but it isn't necessary.
|
||||
type Key: DepNodeParams<Qcx::DepContext> + Eq + Hash + Copy + Debug;
|
||||
type Key: DepNodeParams<DepContextOf<Self>> + Eq + Hash + Copy + Debug;
|
||||
type Value: Copy;
|
||||
|
||||
type Cache: QueryCache<Key = Self::Key, Value = Self::Value>;
|
||||
|
|
@ -27,36 +41,40 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
|
|||
fn format_value(self) -> fn(&Self::Value) -> String;
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt
|
||||
fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key, Qcx::QueryInfo>
|
||||
where
|
||||
Qcx: 'a;
|
||||
fn query_state<'a>(
|
||||
self,
|
||||
tcx: Self::Qcx,
|
||||
) -> &'a QueryState<Self::Key, <Self::Qcx as QueryContext>::QueryInfo>;
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt
|
||||
fn query_cache<'a>(self, tcx: Qcx) -> &'a Self::Cache
|
||||
where
|
||||
Qcx: 'a;
|
||||
fn query_cache<'a>(self, tcx: Self::Qcx) -> &'a Self::Cache;
|
||||
|
||||
fn cache_on_disk(self, tcx: Qcx::DepContext, key: &Self::Key) -> bool;
|
||||
fn cache_on_disk(self, tcx: DepContextOf<Self>, key: &Self::Key) -> bool;
|
||||
|
||||
// Don't use this method to compute query results, instead use the methods on TyCtxt
|
||||
fn execute_query(self, tcx: Qcx::DepContext, k: Self::Key) -> Self::Value;
|
||||
fn execute_query(self, tcx: DepContextOf<Self>, k: Self::Key) -> Self::Value;
|
||||
|
||||
fn compute(self, tcx: Qcx, key: Self::Key) -> Self::Value;
|
||||
fn compute(self, tcx: Self::Qcx, key: Self::Key) -> Self::Value;
|
||||
|
||||
fn try_load_from_disk(
|
||||
self,
|
||||
tcx: Qcx,
|
||||
tcx: Self::Qcx,
|
||||
key: &Self::Key,
|
||||
prev_index: SerializedDepNodeIndex,
|
||||
index: DepNodeIndex,
|
||||
) -> Option<Self::Value>;
|
||||
|
||||
fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool;
|
||||
fn loadable_from_disk(
|
||||
self,
|
||||
qcx: Self::Qcx,
|
||||
key: &Self::Key,
|
||||
idx: SerializedDepNodeIndex,
|
||||
) -> bool;
|
||||
|
||||
/// Synthesize an error value to let compilation continue after a cycle.
|
||||
fn value_from_cycle_error(
|
||||
self,
|
||||
tcx: Qcx::DepContext,
|
||||
tcx: DepContextOf<Self>,
|
||||
cycle_error: &CycleError<QueryStackFrameExtra>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self::Value;
|
||||
|
|
@ -71,7 +89,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
|
|||
fn hash_result(self) -> HashResult<Self::Value>;
|
||||
|
||||
// Just here for convenience and checking that the key matches the kind, don't override this.
|
||||
fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode {
|
||||
fn construct_dep_node(self, tcx: DepContextOf<Self>, key: &Self::Key) -> DepNode {
|
||||
DepNode::construct(tcx, self.dep_kind(), key)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ use rustc_span::Span;
|
|||
use rustc_span::def_id::DefId;
|
||||
|
||||
pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache};
|
||||
pub use self::config::{HashResult, QueryConfig};
|
||||
pub use self::dispatcher::{HashResult, QueryDispatcher};
|
||||
pub use self::job::{
|
||||
QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack,
|
||||
report_cycle,
|
||||
|
|
@ -22,7 +22,7 @@ pub use self::plumbing::*;
|
|||
use crate::dep_graph::{DepKind, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
|
||||
|
||||
mod caches;
|
||||
mod config;
|
||||
mod dispatcher;
|
||||
mod job;
|
||||
mod plumbing;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ use rustc_errors::{Diag, FatalError, StashKey};
|
|||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{QueryConfig, QueryStackFrameExtra};
|
||||
use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
|
||||
use super::{QueryDispatcher, QueryStackFrameExtra};
|
||||
use crate::dep_graph::{
|
||||
DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams, HasDepContext,
|
||||
};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::query::caches::QueryCache;
|
||||
use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle};
|
||||
|
|
@ -124,24 +126,22 @@ where
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn mk_cycle<Q, Qcx>(query: Q, qcx: Qcx, cycle_error: CycleError) -> Q::Value
|
||||
fn mk_cycle<Q>(query: Q, qcx: Q::Qcx, cycle_error: CycleError) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
|
||||
handle_cycle_error(query, qcx, &cycle_error, error)
|
||||
}
|
||||
|
||||
fn handle_cycle_error<Q, Qcx>(
|
||||
fn handle_cycle_error<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
cycle_error: &CycleError,
|
||||
error: Diag<'_>,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
match query.cycle_error_handling() {
|
||||
CycleErrorHandling::Error => {
|
||||
|
|
@ -272,15 +272,14 @@ where
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn cycle_error<Q, Qcx>(
|
||||
fn cycle_error<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
try_execute: QueryJobId,
|
||||
span: Span,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
// Ensure there was no errors collecting all active jobs.
|
||||
// We need the complete map to ensure we find a cycle to break.
|
||||
|
|
@ -291,17 +290,16 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn wait_for_query<Q, Qcx>(
|
||||
fn wait_for_query<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
latch: QueryLatch<Qcx::QueryInfo>,
|
||||
latch: QueryLatch<<Q::Qcx as QueryContext>::QueryInfo>,
|
||||
current: Option<QueryJobId>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
// For parallel queries, we'll block and wait until the query running
|
||||
// in another thread has completed. Record how long we wait in the
|
||||
|
|
@ -341,16 +339,15 @@ where
|
|||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn try_execute_query<Q, Qcx, const INCR: bool>(
|
||||
fn try_execute_query<Q, const INCR: bool>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
dep_node: Option<DepNode>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
let state = query.query_state(qcx);
|
||||
let key_hash = sharded::make_hash(&key);
|
||||
|
|
@ -382,7 +379,7 @@ where
|
|||
// Drop the lock before we start executing the query
|
||||
drop(state_lock);
|
||||
|
||||
execute_job::<_, _, INCR>(query, qcx, state, key, key_hash, id, dep_node)
|
||||
execute_job::<Q, INCR>(query, qcx, state, key, key_hash, id, dep_node)
|
||||
}
|
||||
Entry::Occupied(mut entry) => {
|
||||
match &mut entry.get_mut().1 {
|
||||
|
|
@ -411,18 +408,17 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job<Q, Qcx, const INCR: bool>(
|
||||
fn execute_job<Q, const INCR: bool>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
state: &QueryState<Q::Key, Qcx::QueryInfo>,
|
||||
qcx: Q::Qcx,
|
||||
state: &QueryState<Q::Key, <Q::Qcx as QueryContext>::QueryInfo>,
|
||||
key: Q::Key,
|
||||
key_hash: u64,
|
||||
id: QueryJobId,
|
||||
dep_node: Option<DepNode>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
// Use `JobOwner` so the query will be poisoned if executing it panics.
|
||||
let job_owner = JobOwner { state, key };
|
||||
|
|
@ -484,15 +480,14 @@ where
|
|||
|
||||
// Fast path for when incr. comp. is off.
|
||||
#[inline(always)]
|
||||
fn execute_job_non_incr<Q, Qcx>(
|
||||
fn execute_job_non_incr<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
key: Q::Key,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
|
|
@ -521,17 +516,16 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job_incr<Q, Qcx>(
|
||||
fn execute_job_incr<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
dep_graph_data: &DepGraphData<Qcx::Deps>,
|
||||
qcx: Q::Qcx,
|
||||
dep_graph_data: &DepGraphData<<Q::Qcx as HasDepContext>::Deps>,
|
||||
key: Q::Key,
|
||||
mut dep_node_opt: Option<DepNode>,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
if !query.anon() && !query.eval_always() {
|
||||
// `to_dep_node` is expensive for some `DepKind`s.
|
||||
|
|
@ -577,16 +571,15 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn try_load_from_disk_and_cache_in_memory<Q, Qcx>(
|
||||
fn try_load_from_disk_and_cache_in_memory<Q>(
|
||||
query: Q,
|
||||
dep_graph_data: &DepGraphData<Qcx::Deps>,
|
||||
qcx: Qcx,
|
||||
dep_graph_data: &DepGraphData<<Q::Qcx as HasDepContext>::Deps>,
|
||||
qcx: Q::Qcx,
|
||||
key: &Q::Key,
|
||||
dep_node: &DepNode,
|
||||
) -> Option<(Q::Value, DepNodeIndex)>
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
// Note this function can be called concurrently from the same query
|
||||
// We must ensure that this is handled correctly.
|
||||
|
|
@ -764,15 +757,14 @@ fn incremental_verify_ich_failed<Tcx>(
|
|||
///
|
||||
/// Note: The optimization is only available during incr. comp.
|
||||
#[inline(never)]
|
||||
fn ensure_must_run<Q, Qcx>(
|
||||
fn ensure_must_run<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
key: &Q::Key,
|
||||
check_cache: bool,
|
||||
) -> (bool, Option<DepNode>)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
if query.eval_always() {
|
||||
return (true, None);
|
||||
|
|
@ -817,27 +809,25 @@ pub enum QueryMode {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value
|
||||
pub fn get_query_non_incr<Q>(query: Q, qcx: Q::Qcx, span: Span, key: Q::Key) -> Q::Value
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0)
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, false>(query, qcx, span, key, None).0)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_query_incr<Q, Qcx>(
|
||||
pub fn get_query_incr<Q>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
qcx: Q::Qcx,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
mode: QueryMode,
|
||||
) -> Option<Q::Value>
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
|
|
@ -851,19 +841,17 @@ where
|
|||
None
|
||||
};
|
||||
|
||||
let (result, dep_node_index) = ensure_sufficient_stack(|| {
|
||||
try_execute_query::<_, _, true>(query, qcx, span, key, dep_node)
|
||||
});
|
||||
let (result, dep_node_index) =
|
||||
ensure_sufficient_stack(|| try_execute_query::<Q, true>(query, qcx, span, key, dep_node));
|
||||
if let Some(dep_node_index) = dep_node_index {
|
||||
qcx.dep_context().dep_graph().read_index(dep_node_index)
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
|
||||
pub fn force_query<Q, Qcx>(query: Q, qcx: Qcx, key: Q::Key, dep_node: DepNode)
|
||||
pub fn force_query<Q>(query: Q, qcx: Q::Qcx, key: Q::Key, dep_node: DepNode)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
Q: QueryDispatcher,
|
||||
{
|
||||
// We may be concurrently trying both execute and force a query.
|
||||
// Ensure that only one of them runs the query.
|
||||
|
|
@ -875,6 +863,6 @@ where
|
|||
debug_assert!(!query.anon());
|
||||
|
||||
ensure_sufficient_stack(|| {
|
||||
try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
|
||||
try_execute_query::<Q, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_middle::metadata::{ModChild, Reexport};
|
|||
use rustc_middle::ty::{Feed, Visibility};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
|
||||
use rustc_span::{Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, kw, sym};
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -36,9 +36,9 @@ use crate::imports::{ImportData, ImportKind};
|
|||
use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
|
||||
use crate::ref_mut::CmCell;
|
||||
use crate::{
|
||||
BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, MacroData, Module,
|
||||
ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver, Segment,
|
||||
Used, VisResolutionError, errors,
|
||||
BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, IdentKey, MacroData,
|
||||
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver,
|
||||
Segment, Used, VisResolutionError, errors,
|
||||
};
|
||||
|
||||
type Res = def::Res<NodeId>;
|
||||
|
|
@ -48,20 +48,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
/// and report an error in case of a collision.
|
||||
pub(crate) fn plant_decl_into_local_module(
|
||||
&mut self,
|
||||
ident: Macros20NormalizedIdent,
|
||||
ident: IdentKey,
|
||||
orig_ident_span: Span,
|
||||
ns: Namespace,
|
||||
decl: Decl<'ra>,
|
||||
) {
|
||||
if let Err(old_decl) = self.try_plant_decl_into_local_module(ident, ns, decl, false) {
|
||||
self.report_conflict(ident.0, ns, old_decl, decl);
|
||||
if let Err(old_decl) =
|
||||
self.try_plant_decl_into_local_module(ident, orig_ident_span, ns, decl, false)
|
||||
{
|
||||
self.report_conflict(ident, ns, old_decl, decl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a name definitinon from the given components, and put it into the local module.
|
||||
/// Create a name definition from the given components, and put it into the local module.
|
||||
fn define_local(
|
||||
&mut self,
|
||||
parent: Module<'ra>,
|
||||
ident: Ident,
|
||||
orig_ident: Ident,
|
||||
ns: Namespace,
|
||||
res: Res,
|
||||
vis: Visibility,
|
||||
|
|
@ -69,15 +72,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
expn_id: LocalExpnId,
|
||||
) {
|
||||
let decl = self.arenas.new_def_decl(res, vis.to_def_id(), span, expn_id, Some(parent));
|
||||
let ident = Macros20NormalizedIdent::new(ident);
|
||||
self.plant_decl_into_local_module(ident, ns, decl);
|
||||
let ident = IdentKey::new(orig_ident);
|
||||
self.plant_decl_into_local_module(ident, orig_ident.span, ns, decl);
|
||||
}
|
||||
|
||||
/// Create a name definitinon from the given components, and put it into the extern module.
|
||||
/// Create a name definition from the given components, and put it into the extern module.
|
||||
fn define_extern(
|
||||
&self,
|
||||
parent: Module<'ra>,
|
||||
ident: Macros20NormalizedIdent,
|
||||
ident: IdentKey,
|
||||
orig_ident_span: Span,
|
||||
ns: Namespace,
|
||||
child_index: usize,
|
||||
res: Res,
|
||||
|
|
@ -102,7 +106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let key =
|
||||
BindingKey::new_disambiguated(ident, ns, || (child_index + 1).try_into().unwrap()); // 0 indicates no underscore
|
||||
if self
|
||||
.resolution_or_default(parent, key)
|
||||
.resolution_or_default(parent, key, orig_ident_span)
|
||||
.borrow_mut_unchecked()
|
||||
.non_glob_decl
|
||||
.replace(decl)
|
||||
|
|
@ -279,8 +283,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
.unwrap_or_else(|| res.def_id()),
|
||||
)
|
||||
};
|
||||
let ModChild { ident, res, vis, ref reexport_chain } = *child;
|
||||
let ident = Macros20NormalizedIdent::new(ident);
|
||||
let ModChild { ident: orig_ident, res, vis, ref reexport_chain } = *child;
|
||||
let ident = IdentKey::new(orig_ident);
|
||||
let span = child_span(self, reexport_chain, res);
|
||||
let res = res.expect_non_local();
|
||||
let expansion = parent_scope.expansion;
|
||||
|
|
@ -293,7 +297,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
// Record primary definitions.
|
||||
let define_extern = |ns| {
|
||||
self.define_extern(parent, ident, ns, child_index, res, vis, span, expansion, ambig)
|
||||
self.define_extern(
|
||||
parent,
|
||||
ident,
|
||||
orig_ident.span,
|
||||
ns,
|
||||
child_index,
|
||||
res,
|
||||
vis,
|
||||
span,
|
||||
expansion,
|
||||
ambig,
|
||||
)
|
||||
};
|
||||
match res {
|
||||
Res::Def(
|
||||
|
|
@ -533,8 +548,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
if target.name != kw::Underscore {
|
||||
self.r.per_ns(|this, ns| {
|
||||
if !type_ns_only || ns == TypeNS {
|
||||
let key = BindingKey::new(Macros20NormalizedIdent::new(target), ns);
|
||||
this.resolution_or_default(current_module, key)
|
||||
let key = BindingKey::new(IdentKey::new(target), ns);
|
||||
this.resolution_or_default(current_module, key, target.span)
|
||||
.borrow_mut(this)
|
||||
.single_imports
|
||||
.insert(import);
|
||||
|
|
@ -974,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
orig_name: Option<Symbol>,
|
||||
item: &Item,
|
||||
ident: Ident,
|
||||
orig_ident: Ident,
|
||||
local_def_id: LocalDefId,
|
||||
vis: Visibility,
|
||||
) {
|
||||
|
|
@ -983,7 +998,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
let parent = parent_scope.module;
|
||||
let expansion = parent_scope.expansion;
|
||||
|
||||
let (used, module, decl) = if orig_name.is_none() && ident.name == kw::SelfLower {
|
||||
let (used, module, decl) = if orig_name.is_none() && orig_ident.name == kw::SelfLower {
|
||||
self.r.dcx().emit_err(errors::ExternCrateSelfRequiresRenaming { span: sp });
|
||||
return;
|
||||
} else if orig_name == Some(kw::SelfLower) {
|
||||
|
|
@ -1008,7 +1023,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
})
|
||||
.unwrap_or((true, None, self.r.dummy_decl));
|
||||
let import = self.r.arenas.alloc_import(ImportData {
|
||||
kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
|
||||
kind: ImportKind::ExternCrate { source: orig_name, target: orig_ident, id: item.id },
|
||||
root_id: item.id,
|
||||
parent_scope,
|
||||
imported_module: CmCell::new(module),
|
||||
|
|
@ -1026,7 +1041,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
}
|
||||
self.r.potentially_unused_imports.push(import);
|
||||
let import_decl = self.r.new_import_decl(decl, import);
|
||||
let ident = Macros20NormalizedIdent::new(ident);
|
||||
let ident = IdentKey::new(orig_ident);
|
||||
if ident.name != kw::Underscore && parent == self.r.graph_root {
|
||||
// FIXME: this error is technically unnecessary now when extern prelude is split into
|
||||
// two scopes, remove it with lang team approval.
|
||||
|
|
@ -1045,20 +1060,20 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
Entry::Occupied(mut occupied) => {
|
||||
let entry = occupied.get_mut();
|
||||
if entry.item_decl.is_some() {
|
||||
let msg = format!("extern crate `{ident}` already in extern prelude");
|
||||
let msg = format!("extern crate `{orig_ident}` already in extern prelude");
|
||||
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
|
||||
} else {
|
||||
entry.item_decl = Some((import_decl, orig_name.is_some()));
|
||||
entry.item_decl = Some((import_decl, orig_ident.span, orig_name.is_some()));
|
||||
}
|
||||
entry
|
||||
}
|
||||
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
|
||||
item_decl: Some((import_decl, true)),
|
||||
item_decl: Some((import_decl, orig_ident.span, true)),
|
||||
flag_decl: None,
|
||||
}),
|
||||
};
|
||||
}
|
||||
self.r.plant_decl_into_local_module(ident, TypeNS, import_decl);
|
||||
self.r.plant_decl_into_local_module(ident, orig_ident.span, TypeNS, import_decl);
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one foreign item.
|
||||
|
|
@ -1159,7 +1174,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
if let Some(span) = import_all {
|
||||
let import = macro_use_import(self, span, false);
|
||||
self.r.potentially_unused_imports.push(import);
|
||||
module.for_each_child_mut(self, |this, ident, ns, binding| {
|
||||
module.for_each_child_mut(self, |this, ident, _, ns, binding| {
|
||||
if ns == MacroNS {
|
||||
let import =
|
||||
if this.r.is_accessible_from(binding.vis(), this.parent_scope.module) {
|
||||
|
|
@ -1270,7 +1285,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
let expansion = parent_scope.expansion;
|
||||
let feed = self.r.feed(item.id);
|
||||
let def_id = feed.key();
|
||||
let (res, ident, span, macro_rules) = match &item.kind {
|
||||
let (res, orig_ident, span, macro_rules) = match &item.kind {
|
||||
ItemKind::MacroDef(ident, def) => {
|
||||
(self.res(def_id), *ident, item.span, def.macro_rules)
|
||||
}
|
||||
|
|
@ -1293,8 +1308,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
self.r.local_macro_def_scopes.insert(def_id, parent_scope.module);
|
||||
|
||||
if macro_rules {
|
||||
let ident = Macros20NormalizedIdent::new(ident);
|
||||
self.r.macro_names.insert(ident.0);
|
||||
let ident = IdentKey::new(orig_ident);
|
||||
self.r.macro_names.insert(ident);
|
||||
let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export);
|
||||
let vis = if is_macro_export {
|
||||
Visibility::Public
|
||||
|
|
@ -1326,10 +1341,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
});
|
||||
self.r.import_use_map.insert(import, Used::Other);
|
||||
let import_decl = self.r.new_import_decl(decl, import);
|
||||
self.r.plant_decl_into_local_module(ident, MacroNS, import_decl);
|
||||
self.r.plant_decl_into_local_module(ident, orig_ident.span, MacroNS, import_decl);
|
||||
} else {
|
||||
self.r.check_reserved_macro_name(ident.0, res);
|
||||
self.insert_unused_macro(ident.0, def_id, item.id);
|
||||
self.r.check_reserved_macro_name(ident.name, orig_ident.span, res);
|
||||
self.insert_unused_macro(orig_ident, def_id, item.id);
|
||||
}
|
||||
self.r.feed_visibility(feed, vis);
|
||||
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Def(
|
||||
|
|
@ -1337,6 +1352,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
parent_macro_rules_scope: parent_scope.macro_rules,
|
||||
decl,
|
||||
ident,
|
||||
orig_ident_span: orig_ident.span,
|
||||
}),
|
||||
));
|
||||
self.r.macro_rules_scopes.insert(def_id, scope);
|
||||
|
|
@ -1352,9 +1368,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
_ => self.resolve_visibility(&item.vis),
|
||||
};
|
||||
if !vis.is_public() {
|
||||
self.insert_unused_macro(ident, def_id, item.id);
|
||||
self.insert_unused_macro(orig_ident, def_id, item.id);
|
||||
}
|
||||
self.r.define_local(module, ident, MacroNS, res, vis, span, expansion);
|
||||
self.r.define_local(module, orig_ident, MacroNS, res, vis, span, expansion);
|
||||
self.r.feed_visibility(feed, vis);
|
||||
self.parent_scope.macro_rules
|
||||
}
|
||||
|
|
@ -1496,7 +1512,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
{
|
||||
// Don't add underscore names, they cannot be looked up anyway.
|
||||
let impl_def_id = self.r.tcx.local_parent(local_def_id);
|
||||
let key = BindingKey::new(Macros20NormalizedIdent::new(ident), ns);
|
||||
let key = BindingKey::new(IdentKey::new(ident), ns);
|
||||
self.r.impl_binding_keys.entry(impl_def_id).or_default().insert(key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ use rustc_session::lint::BuiltinLintDiag;
|
|||
use rustc_session::lint::builtin::{
|
||||
MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS,
|
||||
};
|
||||
use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, kw};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, kw};
|
||||
|
||||
use crate::imports::{Import, ImportKind};
|
||||
use crate::{DeclKind, LateDecl, Resolver, module_to_string};
|
||||
use crate::{DeclKind, IdentKey, LateDecl, Resolver, module_to_string};
|
||||
|
||||
struct UnusedImport {
|
||||
use_tree: ast::UseTree,
|
||||
|
|
@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
|
|||
if self
|
||||
.r
|
||||
.extern_prelude
|
||||
.get(&Macros20NormalizedIdent::new(extern_crate.ident))
|
||||
.get(&IdentKey::new(extern_crate.ident))
|
||||
.is_none_or(|entry| entry.introduced_by_item())
|
||||
{
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
|||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::{
|
||||
BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym,
|
||||
};
|
||||
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -47,10 +45,10 @@ use crate::imports::{Import, ImportKind};
|
|||
use crate::late::{DiagMetadata, PatternSource, Rib};
|
||||
use crate::{
|
||||
AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind,
|
||||
Finalize, ForwardGenericParamBanReason, HasGenericParams, LateDecl, MacroRulesScope, Module,
|
||||
ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, ResolutionError,
|
||||
Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, errors as errs,
|
||||
path_names_to_string,
|
||||
Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, LateDecl, MacroRulesScope,
|
||||
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError,
|
||||
ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError,
|
||||
errors as errs, path_names_to_string,
|
||||
};
|
||||
|
||||
type Res = def::Res<ast::NodeId>;
|
||||
|
|
@ -81,24 +79,14 @@ pub(crate) struct TypoSuggestion {
|
|||
}
|
||||
|
||||
impl TypoSuggestion {
|
||||
pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
|
||||
Self {
|
||||
candidate: ident.name,
|
||||
span: Some(ident.span),
|
||||
res,
|
||||
target: SuggestionTarget::SimilarlyNamed,
|
||||
}
|
||||
pub(crate) fn new(candidate: Symbol, span: Span, res: Res) -> TypoSuggestion {
|
||||
Self { candidate, span: Some(span), res, target: SuggestionTarget::SimilarlyNamed }
|
||||
}
|
||||
pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
|
||||
Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
|
||||
}
|
||||
pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
|
||||
Self {
|
||||
candidate: ident.name,
|
||||
span: Some(ident.span),
|
||||
res,
|
||||
target: SuggestionTarget::SingleItem,
|
||||
}
|
||||
pub(crate) fn single_item(candidate: Symbol, span: Span, res: Res) -> TypoSuggestion {
|
||||
Self { candidate, span: Some(span), res, target: SuggestionTarget::SingleItem }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +200,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
pub(crate) fn report_conflict(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
ident: IdentKey,
|
||||
ns: Namespace,
|
||||
old_binding: Decl<'ra>,
|
||||
new_binding: Decl<'ra>,
|
||||
|
|
@ -324,10 +312,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// Check if the target of the use for both bindings is the same.
|
||||
let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
|
||||
let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
|
||||
let from_item = self
|
||||
.extern_prelude
|
||||
.get(&Macros20NormalizedIdent::new(ident))
|
||||
.is_none_or(|entry| entry.introduced_by_item());
|
||||
let from_item =
|
||||
self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item());
|
||||
// Only suggest removing an import if both bindings are to the same def, if both spans
|
||||
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
|
||||
// been introduced by an item.
|
||||
|
|
@ -531,10 +517,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
filter_fn: &impl Fn(Res) -> bool,
|
||||
ctxt: Option<SyntaxContext>,
|
||||
) {
|
||||
module.for_each_child(self, |_this, ident, _ns, binding| {
|
||||
module.for_each_child(self, |_this, ident, orig_ident_span, _ns, binding| {
|
||||
let res = binding.res();
|
||||
if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) {
|
||||
names.push(TypoSuggestion::typo_from_ident(ident.0, res));
|
||||
if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == *ident.ctxt) {
|
||||
names.push(TypoSuggestion::new(ident.name, orig_ident_span, res));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1187,11 +1173,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
||||
if filter_fn(res) {
|
||||
suggestions.extend(
|
||||
this.helper_attrs
|
||||
.get(&expn_id)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|(ident, _)| TypoSuggestion::typo_from_ident(ident.0, res)),
|
||||
this.helper_attrs.get(&expn_id).into_iter().flatten().map(
|
||||
|&(ident, orig_ident_span, _)| {
|
||||
TypoSuggestion::new(ident.name, orig_ident_span, res)
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1202,8 +1188,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if let MacroRulesScope::Def(macro_rules_def) = macro_rules_scope.get() {
|
||||
let res = macro_rules_def.decl.res();
|
||||
if filter_fn(res) {
|
||||
suggestions
|
||||
.push(TypoSuggestion::typo_from_ident(macro_rules_def.ident.0, res))
|
||||
suggestions.push(TypoSuggestion::new(
|
||||
macro_rules_def.ident.name,
|
||||
macro_rules_def.orig_ident_span,
|
||||
res,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1233,9 +1222,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
Scope::ExternPreludeItems => {
|
||||
// Add idents from both item and flag scopes.
|
||||
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
|
||||
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, entry)| {
|
||||
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
|
||||
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res))
|
||||
filter_fn(res).then_some(TypoSuggestion::new(ident.name, entry.span(), res))
|
||||
}));
|
||||
}
|
||||
Scope::ExternPreludeFlags => {}
|
||||
|
|
@ -1244,7 +1233,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
suggestions.extend(
|
||||
this.registered_tools
|
||||
.iter()
|
||||
.map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
|
||||
.map(|ident| TypoSuggestion::new(ident.name, ident.span, res)),
|
||||
);
|
||||
}
|
||||
Scope::StdLibPrelude => {
|
||||
|
|
@ -1329,7 +1318,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
{
|
||||
let in_module_is_extern = !in_module.def_id().is_local();
|
||||
in_module.for_each_child(self, |this, ident, ns, name_binding| {
|
||||
in_module.for_each_child(self, |this, ident, orig_ident_span, ns, name_binding| {
|
||||
// Avoid non-importable candidates.
|
||||
if name_binding.is_assoc_item()
|
||||
&& !this.tcx.features().import_trait_associated_functions()
|
||||
|
|
@ -1382,7 +1371,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if ident.name == lookup_ident.name
|
||||
&& ns == namespace
|
||||
&& in_module != parent_scope.module
|
||||
&& !ident.span.normalize_to_macros_2_0().from_expansion()
|
||||
&& ident.ctxt.is_root()
|
||||
&& filter_fn(res)
|
||||
{
|
||||
// create the path
|
||||
|
|
@ -1395,7 +1384,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
};
|
||||
segms.append(&mut path_segments.clone());
|
||||
|
||||
segms.push(ast::PathSegment::from_ident(ident.0));
|
||||
segms.push(ast::PathSegment::from_ident(ident.orig(orig_ident_span)));
|
||||
let path = Path { span: name_binding.span, segments: segms, tokens: None };
|
||||
|
||||
if child_accessible
|
||||
|
|
@ -1468,7 +1457,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if let Some(def_id) = name_binding.res().module_like_def_id() {
|
||||
// form the path
|
||||
let mut path_segments = path_segments.clone();
|
||||
path_segments.push(ast::PathSegment::from_ident(ident.0));
|
||||
path_segments.push(ast::PathSegment::from_ident(ident.orig(orig_ident_span)));
|
||||
|
||||
let alias_import = if let DeclKind::Import { import, .. } = name_binding.kind
|
||||
&& let ImportKind::ExternCrate { source: Some(_), .. } = import.kind
|
||||
|
|
@ -1557,8 +1546,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
);
|
||||
|
||||
if lookup_ident.span.at_least_rust_2018() {
|
||||
for &ident in self.extern_prelude.keys() {
|
||||
if ident.span.from_expansion() {
|
||||
for (ident, entry) in &self.extern_prelude {
|
||||
if entry.span().from_expansion() {
|
||||
// Idents are adjusted to the root context before being
|
||||
// resolved in the extern prelude, so reporting this to the
|
||||
// user is no help. This skips the injected
|
||||
|
|
@ -1582,7 +1571,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
self.resolutions(parent_scope.module).borrow().iter().any(
|
||||
|(key, name_resolution)| {
|
||||
if key.ns == TypeNS
|
||||
&& key.ident == ident
|
||||
&& key.ident == *ident
|
||||
&& let Some(decl) = name_resolution.borrow().best_decl()
|
||||
{
|
||||
match decl.res() {
|
||||
|
|
@ -1601,7 +1590,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if needs_disambiguation {
|
||||
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
|
||||
}
|
||||
crate_path.push(ast::PathSegment::from_ident(ident.0));
|
||||
crate_path.push(ast::PathSegment::from_ident(ident.orig(entry.span())));
|
||||
|
||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
|
|
@ -1777,7 +1766,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
|
||||
if self.macro_names.contains(&IdentKey::new(ident)) {
|
||||
err.subdiagnostic(AddedMacroUse);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2007,8 +1996,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
matches!(scope2, Scope::ExternPreludeFlags)
|
||||
&& self
|
||||
.extern_prelude
|
||||
.get(&Macros20NormalizedIdent::new(ident))
|
||||
.is_some_and(|entry| entry.item_decl.map(|(b, _)| b) == Some(b1))
|
||||
.get(&IdentKey::new(ident))
|
||||
.is_some_and(|entry| entry.item_decl.map(|(b, ..)| b) == Some(b1))
|
||||
};
|
||||
let (b1, b2, scope1, scope2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
|
||||
// We have to print the span-less alternative first, otherwise formatting looks bad.
|
||||
|
|
@ -2914,7 +2903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let binding_key = BindingKey::new(Macros20NormalizedIdent::new(ident), MacroNS);
|
||||
let binding_key = BindingKey::new(IdentKey::new(ident), MacroNS);
|
||||
let binding = self.resolution(crate_module, binding_key)?.binding()?;
|
||||
let Res::Def(DefKind::Macro(kinds), _) = binding.res() else {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -96,13 +96,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
|
|||
// is the maximum value among visibilities of declarations corresponding to that def id.
|
||||
for (decl, eff_vis) in visitor.import_effective_visibilities.iter() {
|
||||
let DeclKind::Import { import, .. } = decl.kind else { unreachable!() };
|
||||
if !decl.is_ambiguity_recursive() {
|
||||
if let Some(node_id) = import.id() {
|
||||
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
|
||||
}
|
||||
} else if decl.ambiguity.get().is_some()
|
||||
&& eff_vis.is_public_at_level(Level::Reexported)
|
||||
{
|
||||
if let Some(node_id) = import.id() {
|
||||
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
|
||||
}
|
||||
if decl.ambiguity.get().is_some() && eff_vis.is_public_at_level(Level::Reexported) {
|
||||
exported_ambiguities.insert(*decl);
|
||||
}
|
||||
}
|
||||
|
|
@ -123,31 +120,13 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
|
|||
// Set the given effective visibility level to `Level::Direct` and
|
||||
// sets the rest of the `use` chain to `Level::Reexported` until
|
||||
// we hit the actual exported item.
|
||||
//
|
||||
// If the binding is ambiguous, put the root ambiguity binding and all reexports
|
||||
// leading to it into the table. They are used by the `ambiguous_glob_reexports`
|
||||
// lint. For all bindings added to the table this way `is_ambiguity` returns true.
|
||||
let is_ambiguity =
|
||||
|decl: Decl<'ra>, warn: bool| decl.ambiguity.get().is_some() && !warn;
|
||||
let mut parent_id = ParentId::Def(module_id);
|
||||
let mut warn_ambiguity = decl.warn_ambiguity.get();
|
||||
while let DeclKind::Import { source_decl, .. } = decl.kind {
|
||||
self.update_import(decl, parent_id);
|
||||
|
||||
if is_ambiguity(decl, warn_ambiguity) {
|
||||
// Stop at the root ambiguity, further bindings in the chain should not
|
||||
// be reexported because the root ambiguity blocks any access to them.
|
||||
// (Those further bindings are most likely not ambiguities themselves.)
|
||||
break;
|
||||
}
|
||||
|
||||
parent_id = ParentId::Import(decl);
|
||||
decl = source_decl;
|
||||
warn_ambiguity |= source_decl.warn_ambiguity.get();
|
||||
}
|
||||
if !is_ambiguity(decl, warn_ambiguity)
|
||||
&& let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local())
|
||||
{
|
||||
if let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) {
|
||||
self.update_def(def_id, decl.vis().expect_local(), parent_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue