mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
+2
-2
@@ -1140,9 +1140,9 @@ version = "0.1.96"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
|
||||
checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -1013,9 +1013,10 @@
|
||||
# its historical default, but when compiling the compiler itself, we skip it by
|
||||
# default since we know it's safe to do so in that case.
|
||||
#
|
||||
# On Windows platforms, packed debuginfo is the only supported option,
|
||||
# producing a `.pdb` file.
|
||||
#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
|
||||
# On Windows MSVC platforms, packed debuginfo is the only supported option,
|
||||
# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo,
|
||||
# and enabling it causes issues.
|
||||
#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked }
|
||||
|
||||
# Path to the `llvm-config` binary of the installation of a custom LLVM to link
|
||||
# against. Note that if this is specified we don't compile LLVM at all for this
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_inline_asm(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
use rustc_span::sym;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_block(
|
||||
&mut self,
|
||||
b: &Block,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::LoweringContext;
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
/// Lowered contracts are guarded with the `contract_checks` compiler flag,
|
||||
/// i.e. the flag turns into a boolean guard in the lowered HIR. The reason
|
||||
/// for not eliminating the contract code entirely when the `contract_checks`
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
//! also be emitted during HIR ty lowering.
|
||||
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
@@ -44,16 +45,15 @@
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::*;
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
|
||||
use rustc_middle::ty::Asyncness;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
|
||||
@@ -79,7 +79,7 @@ struct AttrAdditionInfo {
|
||||
|
||||
enum AttrAdditionKind {
|
||||
Default { factory: fn(Span) -> hir::Attribute },
|
||||
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
||||
Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
||||
}
|
||||
|
||||
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
|
||||
@@ -96,7 +96,6 @@ enum AttrAdditionKind {
|
||||
|
||||
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
|
||||
},
|
||||
flag: DelegationFnSigAttrs::MUST_USE,
|
||||
},
|
||||
},
|
||||
AttrAdditionInfo {
|
||||
@@ -107,45 +106,11 @@ enum AttrAdditionKind {
|
||||
},
|
||||
];
|
||||
|
||||
type DelegationIdsVec = SmallVec<[DefId; 1]>;
|
||||
|
||||
// As delegations can now refer to another delegation, we have a delegation path
|
||||
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
|
||||
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
|
||||
struct DelegationIds {
|
||||
path: DelegationIdsVec,
|
||||
}
|
||||
|
||||
impl DelegationIds {
|
||||
fn new(path: DelegationIdsVec) -> Self {
|
||||
assert!(!path.is_empty());
|
||||
Self { path }
|
||||
}
|
||||
|
||||
// Id of the first function in (non)local crate that is being reused
|
||||
fn root_function_id(&self) -> DefId {
|
||||
*self.path.last().expect("Ids vector can't be empty")
|
||||
}
|
||||
|
||||
// Id of the first definition which is being reused,
|
||||
// can be either function, in this case `root_id == delegee_id`, or other delegation
|
||||
fn delegee_id(&self) -> DefId {
|
||||
*self.path.first().expect("Ids vector can't be empty")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
DefKind::Fn => false,
|
||||
DefKind::AssocFn => match def_id.as_local() {
|
||||
Some(local_def_id) => self
|
||||
.resolver
|
||||
.delegation_fn_sigs
|
||||
.get(&local_def_id)
|
||||
.is_some_and(|sig| sig.has_self),
|
||||
None => self.tcx.associated_item(def_id).is_method(),
|
||||
},
|
||||
DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
}
|
||||
@@ -158,10 +123,10 @@ pub(crate) fn lower_delegation(
|
||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||
|
||||
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
|
||||
let ids = if let Some(delegation_info) =
|
||||
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
|
||||
let sig_id = if let Some(delegation_info) =
|
||||
self.resolver.delegation_info(self.local_def_id(item_id))
|
||||
{
|
||||
self.get_delegation_ids(delegation_info.resolution_node, span)
|
||||
self.get_sig_id(delegation_info.resolution_node, span)
|
||||
} else {
|
||||
return self.generate_delegation_error(
|
||||
self.dcx().span_delayed_bug(
|
||||
@@ -173,28 +138,16 @@ pub(crate) fn lower_delegation(
|
||||
);
|
||||
};
|
||||
|
||||
match ids {
|
||||
Ok(ids) => {
|
||||
self.add_attrs_if_needed(span, &ids);
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
self.add_attrs_if_needed(span, sig_id);
|
||||
|
||||
let delegee_id = ids.delegee_id();
|
||||
let root_function_id = ids.root_function_id();
|
||||
let is_method = self.is_method(sig_id, span);
|
||||
|
||||
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
|
||||
// if the original function is not a method (without `self`), then it can not be added
|
||||
// during chain of reuses, so we use `root_function_id` here
|
||||
let is_method = self.is_method(root_function_id, span);
|
||||
let (param_count, c_variadic) = self.param_count(sig_id);
|
||||
|
||||
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
|
||||
// we need a function to extract this information
|
||||
let (param_count, c_variadic) = self.param_count(root_function_id);
|
||||
|
||||
let mut generics = self.lower_delegation_generics(
|
||||
delegation,
|
||||
ids.root_function_id(),
|
||||
item_id,
|
||||
span,
|
||||
);
|
||||
let mut generics =
|
||||
self.lower_delegation_generics(delegation, sig_id, item_id, span);
|
||||
|
||||
let body_id = self.lower_delegation_body(
|
||||
delegation,
|
||||
@@ -205,20 +158,10 @@ pub(crate) fn lower_delegation(
|
||||
span,
|
||||
);
|
||||
|
||||
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
|
||||
// inheritance, and we want this id to point on a delegee, not on the original
|
||||
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
|
||||
let decl = self.lower_delegation_decl(
|
||||
delegee_id,
|
||||
param_count,
|
||||
c_variadic,
|
||||
span,
|
||||
&generics,
|
||||
);
|
||||
let decl =
|
||||
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
|
||||
|
||||
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
|
||||
// from the root function that started delegation
|
||||
let sig = self.lower_delegation_sig(root_function_id, decl, span);
|
||||
let sig = self.lower_delegation_sig(sig_id, decl, span);
|
||||
let ident = self.lower_ident(delegation.ident);
|
||||
|
||||
let generics = self.arena.alloc(hir::Generics {
|
||||
@@ -237,9 +180,9 @@ pub(crate) fn lower_delegation(
|
||||
}
|
||||
}
|
||||
|
||||
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
|
||||
fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
|
||||
let new_attrs =
|
||||
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
|
||||
self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
|
||||
|
||||
if new_attrs.is_empty() {
|
||||
return;
|
||||
@@ -259,15 +202,9 @@ fn create_new_attrs(
|
||||
&self,
|
||||
candidate_additions: &[AttrAdditionInfo],
|
||||
span: Span,
|
||||
ids: &DelegationIds,
|
||||
sig_id: DefId,
|
||||
existing_attrs: Option<&&[hir::Attribute]>,
|
||||
) -> Vec<hir::Attribute> {
|
||||
let defs_orig_attrs = ids
|
||||
.path
|
||||
.iter()
|
||||
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
candidate_additions
|
||||
.iter()
|
||||
.filter_map(|addition_info| {
|
||||
@@ -281,83 +218,22 @@ fn create_new_attrs(
|
||||
|
||||
match addition_info.kind {
|
||||
AttrAdditionKind::Default { factory } => Some(factory(span)),
|
||||
AttrAdditionKind::Inherit { flag, factory } => {
|
||||
for (def_id, orig_attrs) in &defs_orig_attrs {
|
||||
let original_attr = match def_id.as_local() {
|
||||
Some(local_id) => self
|
||||
.get_attrs(local_id)
|
||||
.flags
|
||||
.contains(flag)
|
||||
.then(|| {
|
||||
orig_attrs
|
||||
.as_ref()
|
||||
.map(|attrs| {
|
||||
attrs.iter().find(|base_attr| {
|
||||
(addition_info.equals)(base_attr)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
.flatten(),
|
||||
None =>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
self.tcx
|
||||
.get_all_attrs(*def_id)
|
||||
.iter()
|
||||
.find(|base_attr| (addition_info.equals)(base_attr))
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(original_attr) = original_attr {
|
||||
return Some(factory(span, original_attr));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
AttrAdditionKind::Inherit { factory, .. } =>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
self.tcx
|
||||
.get_all_attrs(sig_id)
|
||||
.iter()
|
||||
.find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
|
||||
if let Some(local_id) = def_id.as_local() {
|
||||
let attrs = &self.get_attrs(local_id).to_inherit;
|
||||
|
||||
if !attrs.is_empty() {
|
||||
return Some(AttributeParser::parse_limited_all(
|
||||
self.tcx.sess,
|
||||
attrs,
|
||||
None,
|
||||
hir::Target::Fn,
|
||||
DUMMY_SP,
|
||||
DUMMY_NODE_ID,
|
||||
Some(self.tcx.features()),
|
||||
ShouldEmit::Nothing,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
|
||||
// local_id can correspond either to a function or other delegation
|
||||
if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
|
||||
&fn_sig.attrs
|
||||
} else {
|
||||
&self.resolver.delegation_infos[&local_id].attrs
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delegation_ids(
|
||||
&self,
|
||||
mut node_id: NodeId,
|
||||
span: Span,
|
||||
) -> Result<DelegationIds, ErrorGuaranteed> {
|
||||
fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
|
||||
let mut visited: FxHashSet<NodeId> = Default::default();
|
||||
let mut path: DelegationIdsVec = Default::default();
|
||||
let mut path: SmallVec<[DefId; 1]> = Default::default();
|
||||
|
||||
loop {
|
||||
visited.insert(node_id);
|
||||
@@ -378,7 +254,7 @@ fn get_delegation_ids(
|
||||
// it means that we refer to another delegation as a callee, so in order to obtain
|
||||
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
|
||||
if let Some(local_id) = def_id.as_local()
|
||||
&& let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
|
||||
&& let Some(delegation_info) = self.resolver.delegation_info(local_id)
|
||||
{
|
||||
node_id = delegation_info.resolution_node;
|
||||
if visited.contains(&node_id) {
|
||||
@@ -390,7 +266,7 @@ fn get_delegation_ids(
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Ok(DelegationIds::new(path));
|
||||
return Ok(path[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,15 +277,8 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
|
||||
|
||||
// Function parameter count, including C variadic `...` if present.
|
||||
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = def_id.as_local() {
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||
None => (0, false),
|
||||
}
|
||||
} else {
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
|
||||
fn lower_delegation_decl(
|
||||
@@ -456,41 +325,21 @@ fn lower_delegation_sig(
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
span: Span,
|
||||
) -> hir::FnSig<'hir> {
|
||||
let header = if let Some(local_sig_id) = sig_id.as_local() {
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => {
|
||||
let parent = self.tcx.parent(sig_id);
|
||||
// HACK: we override the default safety instead of generating attributes from the ether.
|
||||
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
||||
// and here we need the hir attributes.
|
||||
let default_safety =
|
||||
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|
||||
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
|
||||
{
|
||||
hir::Safety::Unsafe
|
||||
} else {
|
||||
hir::Safety::Safe
|
||||
};
|
||||
self.lower_fn_header(sig.header, default_safety, &[])
|
||||
}
|
||||
None => self.generate_header_error(),
|
||||
}
|
||||
} else {
|
||||
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||
let asyncness = match self.tcx.asyncness(sig_id) {
|
||||
Asyncness::Yes => hir::IsAsync::Async(span),
|
||||
Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
hir::FnHeader {
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi,
|
||||
}
|
||||
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||
let asyncness = match self.tcx.asyncness(sig_id) {
|
||||
Asyncness::Yes => hir::IsAsync::Async(span),
|
||||
Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
|
||||
let header = hir::FnHeader {
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi,
|
||||
};
|
||||
|
||||
hir::FnSig { decl, header, span }
|
||||
@@ -573,6 +422,7 @@ fn lower_delegation_body(
|
||||
resolver: this.resolver,
|
||||
path_id: delegation.id,
|
||||
self_param_id: pat_node_id,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
self_resolver.visit_block(block);
|
||||
// Target expr needs to lower `self` path.
|
||||
@@ -818,25 +668,26 @@ fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir>
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfResolver<'a, 'tcx> {
|
||||
resolver: &'a mut ResolverAstLowering<'tcx>,
|
||||
struct SelfResolver<'a, 'tcx, R> {
|
||||
resolver: &'a mut R,
|
||||
path_id: NodeId,
|
||||
self_param_id: NodeId,
|
||||
phantom: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
impl SelfResolver<'_, '_> {
|
||||
impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, 'tcx, R> {
|
||||
fn try_replace_id(&mut self, id: NodeId) {
|
||||
if let Some(res) = self.resolver.partial_res_map.get(&id)
|
||||
if let Some(res) = self.resolver.get_partial_res(id)
|
||||
&& let Some(Res::Local(sig_id)) = res.full_res()
|
||||
&& sig_id == self.path_id
|
||||
{
|
||||
let new_res = PartialRes::new(Res::Local(self.self_param_id));
|
||||
self.resolver.partial_res_map.insert(id, new_res);
|
||||
self.resolver.insert_partial_res(id, new_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a, '_> {
|
||||
impl<'ast, 'a, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'a, 'tcx, R> {
|
||||
fn visit_id(&mut self, id: NodeId) {
|
||||
self.try_replace_id(id);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::sym::{self};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span};
|
||||
use rustc_span::{Ident, Span};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::{AstOwner, LoweringContext};
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
pub(super) enum DelegationGenerics<T> {
|
||||
/// User-specified args are present: `reuse foo::<String>;`.
|
||||
@@ -81,7 +81,7 @@ fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
impl<'hir> HirOrAstGenerics<'hir> {
|
||||
pub(super) fn into_hir_generics(
|
||||
&mut self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
) -> &mut HirOrAstGenerics<'hir> {
|
||||
@@ -128,7 +128,7 @@ fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
|
||||
|
||||
pub(super) fn into_generic_args(
|
||||
&self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
add_lifetimes: bool,
|
||||
span: Span,
|
||||
) -> Option<&'hir hir::GenericArgs<'hir>> {
|
||||
@@ -169,7 +169,7 @@ pub(super) fn all_params(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::GenericParam<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
@@ -211,7 +211,7 @@ pub(super) fn all_predicates(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
@@ -236,11 +236,11 @@ pub(super) fn all_predicates(
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_delegation_generics(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
root_fn_id: DefId,
|
||||
sig_id: DefId,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
) -> GenericsGenerationResults<'hir> {
|
||||
@@ -258,7 +258,7 @@ pub(super) fn lower_delegation_generics(
|
||||
// we will take those args that are in trait impl header trait ref.
|
||||
let parent = GenericsGenerationResult::new(DelegationGenerics::Default(None));
|
||||
|
||||
let generics = self.get_fn_like_generics(root_fn_id, span);
|
||||
let generics = self.get_external_generics(sig_id, false, span);
|
||||
let child = DelegationGenerics::TraitImpl(generics, child_user_specified);
|
||||
let child = GenericsGenerationResult::new(child);
|
||||
|
||||
@@ -269,17 +269,12 @@ pub(super) fn lower_delegation_generics(
|
||||
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
|
||||
|
||||
let root_function_in_trait =
|
||||
matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
|
||||
matches!(self.tcx.def_kind(self.tcx.parent(sig_id)), DefKind::Trait);
|
||||
|
||||
let generate_self = delegation_in_free_ctx && root_function_in_trait;
|
||||
|
||||
let parent_generics_factory = |this: &mut Self, user_specified: bool| {
|
||||
this.get_parent_generics(
|
||||
this.tcx.parent(root_fn_id),
|
||||
generate_self,
|
||||
user_specified,
|
||||
span,
|
||||
)
|
||||
this.get_parent_generics(this.tcx.parent(sig_id), generate_self, user_specified, span)
|
||||
};
|
||||
|
||||
let can_add_generics_to_parent = len >= 2
|
||||
@@ -304,7 +299,7 @@ pub(super) fn lower_delegation_generics(
|
||||
let child_generics = if child_user_specified {
|
||||
DelegationGenerics::UserSpecified
|
||||
} else {
|
||||
DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span))
|
||||
DelegationGenerics::Default(self.get_external_generics(sig_id, false, span))
|
||||
};
|
||||
|
||||
GenericsGenerationResults {
|
||||
@@ -334,11 +329,11 @@ fn lower_delegation_generic_params(
|
||||
|
||||
// Note that we use self.disambiguator here, if we will create new every time
|
||||
// we will get ICE if params have the same name.
|
||||
self.resolver.node_id_to_def_id.insert(
|
||||
self.resolver.insert_new_def_id(
|
||||
p.id,
|
||||
self.tcx
|
||||
.create_def(
|
||||
self.resolver.node_id_to_def_id[&item_id],
|
||||
self.local_def_id(item_id),
|
||||
Some(p.ident.name),
|
||||
match p.kind {
|
||||
GenericParamKind::Lifetime => DefKind::LifetimeParam,
|
||||
@@ -363,11 +358,9 @@ fn lower_delegation_generic_params(
|
||||
// FIXME(fn_delegation): proper support for late bound lifetimes.
|
||||
self.arena.alloc(hir::Generics {
|
||||
params,
|
||||
predicates: self.arena.alloc_from_iter(
|
||||
params
|
||||
.iter()
|
||||
.filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))),
|
||||
),
|
||||
predicates: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
|
||||
p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
|
||||
})),
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: span,
|
||||
span,
|
||||
@@ -377,6 +370,7 @@ fn lower_delegation_generic_params(
|
||||
fn generate_lifetime_predicate(
|
||||
&mut self,
|
||||
p: &hir::GenericParam<'hir>,
|
||||
span: Span,
|
||||
) -> hir::WherePredicate<'hir> {
|
||||
let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
|
||||
this.arena.alloc(hir::Lifetime {
|
||||
@@ -392,7 +386,7 @@ fn generate_lifetime_predicate(
|
||||
|
||||
hir::WherePredicate {
|
||||
hir_id: self.next_id(),
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
|
||||
hir::WhereRegionPredicate {
|
||||
in_where_clause: true,
|
||||
@@ -479,22 +473,6 @@ fn create_generics_args_from_params(
|
||||
})
|
||||
}
|
||||
|
||||
fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option<Generics> {
|
||||
if let Some(local_id) = id.as_local() {
|
||||
match self.ast_index.get(local_id) {
|
||||
Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => {
|
||||
Some(f.generics.clone())
|
||||
}
|
||||
Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => {
|
||||
Some(f.generics.clone())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.get_external_generics(id, false, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_external_generics(
|
||||
&mut self,
|
||||
id: DefId,
|
||||
@@ -519,7 +497,7 @@ fn get_external_generics(
|
||||
bounds: Default::default(),
|
||||
colon_span: None,
|
||||
id: self.next_node_id(),
|
||||
ident: Ident::with_dummy_span(p.name),
|
||||
ident: Ident::new(p.name, span),
|
||||
is_placeholder: false,
|
||||
kind: match p.kind {
|
||||
GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
|
||||
@@ -531,7 +509,7 @@ fn get_external_generics(
|
||||
})
|
||||
.collect(),
|
||||
where_clause: Default::default(),
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -554,7 +532,7 @@ fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericPara
|
||||
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
self.resolver.partial_res_map.insert(node_id, hir::def::PartialRes::new(res));
|
||||
self.resolver.insert_partial_res(node_id, hir::def::PartialRes::new(res));
|
||||
|
||||
GenericParamKind::Const {
|
||||
ty: Box::new(Ty {
|
||||
@@ -563,18 +541,18 @@ fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericPara
|
||||
None,
|
||||
Path {
|
||||
segments: thin_vec![PathSegment {
|
||||
ident: Ident::with_dummy_span(type_symbol),
|
||||
ident: Ident::new(type_symbol, span),
|
||||
id: self.next_node_id(),
|
||||
args: None
|
||||
}],
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
tokens: None,
|
||||
},
|
||||
),
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
tokens: None,
|
||||
}),
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
default: None,
|
||||
}
|
||||
}
|
||||
@@ -587,28 +565,15 @@ fn get_parent_generics(
|
||||
span: Span,
|
||||
) -> Option<Generics> {
|
||||
// If args are user-specified we still maybe need to add self.
|
||||
let mut generics = if user_specified {
|
||||
None
|
||||
} else {
|
||||
if let Some(local_id) = id.as_local() {
|
||||
if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id)
|
||||
&& matches!(item.kind, ItemKind::Trait(..))
|
||||
{
|
||||
item.opt_generics().cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
self.get_external_generics(id, true, span)
|
||||
}
|
||||
};
|
||||
let mut generics =
|
||||
if user_specified { None } else { self.get_external_generics(id, true, span) };
|
||||
|
||||
if add_self {
|
||||
generics.get_or_insert_default().params.insert(
|
||||
0,
|
||||
GenericParam {
|
||||
id: self.next_node_id(),
|
||||
ident: Ident::new(kw::SelfUpper, DUMMY_SP),
|
||||
ident: Ident::new(kw::SelfUpper, span),
|
||||
attrs: Default::default(),
|
||||
bounds: vec![],
|
||||
is_placeholder: false,
|
||||
|
||||
@@ -52,7 +52,7 @@ fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||
}
|
||||
@@ -1244,7 +1244,10 @@ fn lower_expr_assign(
|
||||
whole_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
// Return early in case of an ordinary assignment.
|
||||
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
||||
fn is_ordinary<'hir>(
|
||||
lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
lhs: &Expr,
|
||||
) -> bool {
|
||||
match &lhs.kind {
|
||||
ExprKind::Array(..)
|
||||
| ExprKind::Struct(..)
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
|
||||
use super::LoweringContext;
|
||||
use crate::ResolverAstLoweringExt;
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
||||
// Never call the const constructor of `fmt::Arguments` if the
|
||||
// format_args!() had any arguments _before_ flattening/inlining.
|
||||
@@ -230,7 +231,7 @@ enum ArgumentType {
|
||||
/// <core::fmt::Argument>::new_…(arg)
|
||||
/// ```
|
||||
fn make_argument<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
sp: Span,
|
||||
arg: &'hir hir::Expr<'hir>,
|
||||
ty: ArgumentType,
|
||||
@@ -277,7 +278,7 @@ fn make_count(
|
||||
}
|
||||
|
||||
fn expand_format_args<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
macsp: Span,
|
||||
fmt: &FormatArgs,
|
||||
allow_const: bool,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
@@ -12,7 +13,7 @@
|
||||
};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
@@ -27,11 +28,31 @@
|
||||
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
|
||||
/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR
|
||||
/// lowering of delegations (`lower_delayed_owner`),
|
||||
/// in this case we can not modify already created IndexVec, so we use other map.
|
||||
pub(super) enum Owners<'a, 'hir> {
|
||||
IndexVec(&'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>),
|
||||
Map(&'a mut FxIndexMap<LocalDefId, hir::MaybeOwner<'hir>>),
|
||||
}
|
||||
|
||||
impl<'hir> Owners<'_, 'hir> {
|
||||
fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
|
||||
match self {
|
||||
Owners::IndexVec(index_vec) => {
|
||||
index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
|
||||
}
|
||||
Owners::Map(map) => map.entry(def_id).or_insert(hir::MaybeOwner::Phantom),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'hir, R> {
|
||||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
pub(super) resolver: &'a mut R,
|
||||
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
|
||||
pub(super) owners: Owners<'a, 'hir>,
|
||||
}
|
||||
|
||||
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
|
||||
@@ -53,17 +74,17 @@ fn add_ty_alias_where_clause(
|
||||
if before.0 || !after.0 { before } else { after };
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> {
|
||||
fn with_lctx(
|
||||
&mut self,
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.ast_index, self.resolver);
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
for (def_id, info) in lctx.children {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
let owner = self.owners.get_or_insert_mut(def_id);
|
||||
assert!(
|
||||
matches!(owner, hir::MaybeOwner::Phantom),
|
||||
"duplicate copy of {def_id:?} in lctx.children"
|
||||
@@ -73,13 +94,13 @@ fn with_lctx(
|
||||
}
|
||||
|
||||
pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
let owner = self.owners.get_or_insert_mut(def_id);
|
||||
if let hir::MaybeOwner::Phantom = owner {
|
||||
let node = self.ast_index[def_id];
|
||||
match node {
|
||||
AstOwner::NonOwner => {}
|
||||
AstOwner::Crate(c) => {
|
||||
assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
|
||||
assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, &c.spans);
|
||||
// FIXME(jdonszelman): is dummy span ever a problem here?
|
||||
@@ -101,7 +122,7 @@ pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_mod(
|
||||
&mut self,
|
||||
items: &[Box<Item>],
|
||||
@@ -1491,7 +1512,7 @@ fn lower_maybe_coroutine_body(
|
||||
pub(crate) fn lower_coroutine_body_with_moved_arguments(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>,
|
||||
fn_decl_span: Span,
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
@@ -1628,7 +1649,7 @@ pub(crate) fn lower_coroutine_body_with_moved_arguments(
|
||||
parameters.push(new_parameter);
|
||||
}
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = lower_body(this);
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::spawn;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
@@ -57,8 +58,9 @@
|
||||
};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::{self as mid_hir};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::parse::add_feature_diagnostics;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||
@@ -67,6 +69,7 @@
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
|
||||
use crate::item::Owners;
|
||||
|
||||
macro_rules! arena_vec {
|
||||
($this:expr; $($x:expr),*) => (
|
||||
@@ -87,18 +90,9 @@ macro_rules! arena_vec {
|
||||
mod path;
|
||||
pub mod stability;
|
||||
|
||||
struct LoweringContext<'a, 'hir> {
|
||||
struct LoweringContext<'a, 'hir, R> {
|
||||
tcx: TyCtxt<'hir>,
|
||||
|
||||
// During lowering of delegation we need to access AST of other functions
|
||||
// in order to properly propagate generics, we could have done it at resolve
|
||||
// stage, however it will require either to firstly identify functions that
|
||||
// are being reused and store their generics, or to store generics of all functions
|
||||
// in resolver. This approach helps with those problems, as functions that are reused
|
||||
// will be in AST index.
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
|
||||
resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
resolver: &'a mut R,
|
||||
disambiguator: DisambiguatorState,
|
||||
|
||||
/// Used to allocate HIR nodes.
|
||||
@@ -158,17 +152,11 @@ struct LoweringContext<'a, 'hir> {
|
||||
attribute_parser: AttributeParser<'hir>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'hir>,
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
) -> Self {
|
||||
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
|
||||
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
|
||||
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
|
||||
Self {
|
||||
// Pseudo-globals.
|
||||
tcx,
|
||||
ast_index,
|
||||
resolver,
|
||||
disambiguator: DisambiguatorState::new(),
|
||||
arena: tcx.hir_arena,
|
||||
@@ -248,9 +236,84 @@ fn lower(&self, span: Span) -> Span {
|
||||
}
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering<'_> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<usize>> {
|
||||
struct ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
node_id_to_def_id: NodeMap<LocalDefId>,
|
||||
partial_res_map: NodeMap<PartialRes>,
|
||||
next_node_id: NodeId,
|
||||
base: &'a ResolverAstLowering<'tcx>,
|
||||
}
|
||||
|
||||
// FIXME(fn_delegation): delegate this trait impl to `self.base`
|
||||
impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
self.base.legacy_const_generic_args(expr, tcx)
|
||||
}
|
||||
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||
self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
|
||||
}
|
||||
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
|
||||
self.base.get_import_res(id)
|
||||
}
|
||||
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.base.get_label_res(id)
|
||||
}
|
||||
|
||||
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
|
||||
self.base.get_lifetime_res(id)
|
||||
}
|
||||
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.base.extra_lifetime_params(id)
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
self.base.delegation_info(id)
|
||||
}
|
||||
|
||||
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id))
|
||||
}
|
||||
|
||||
fn local_def_id(&self, id: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(id).expect("must have def_id")
|
||||
}
|
||||
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.base.lifetime_elision_allowed(id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.base.trait_candidates(node_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_node_id(current_id: &mut NodeId) -> NodeId {
|
||||
let start = *current_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
*current_id = ast::NodeId::from_u32(next);
|
||||
|
||||
start
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt<'tcx>)]
|
||||
impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
let ExprKind::Path(None, path) = &expr.kind else {
|
||||
return None;
|
||||
};
|
||||
@@ -261,7 +324,7 @@ fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<
|
||||
return None;
|
||||
}
|
||||
|
||||
let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
|
||||
let def_id = self.get_partial_res(expr.id)?.full_res()?.opt_def_id()?;
|
||||
|
||||
// We only support cross-crate argument rewriting. Uses
|
||||
// within the same crate should be updated to use the new
|
||||
@@ -304,9 +367,42 @@ fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
|
||||
///
|
||||
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
|
||||
/// should appear at the enclosing `PolyTraitRef`.
|
||||
fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
self.delegation_infos.get(&id)
|
||||
}
|
||||
|
||||
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&id).copied()
|
||||
}
|
||||
|
||||
fn local_def_id(&self, id: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(id).expect("must have def_id")
|
||||
}
|
||||
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.lifetime_elision_allowed.contains(&id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.trait_map.get(&node_id).copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// How relaxed bounds `?Trait` should be treated.
|
||||
@@ -446,42 +542,43 @@ enum TryBlockScope {
|
||||
Heterogeneous(HirId),
|
||||
}
|
||||
|
||||
fn index_crate<'a>(
|
||||
node_id_to_def_id: &NodeMap<LocalDefId>,
|
||||
fn index_crate<'a, 'b>(
|
||||
resolver: &'b impl ResolverAstLoweringExt<'a>,
|
||||
krate: &'a Crate,
|
||||
) -> IndexVec<LocalDefId, AstOwner<'a>> {
|
||||
let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
|
||||
let mut indexer = Indexer { resolver, index: IndexVec::new() };
|
||||
*indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) =
|
||||
AstOwner::Crate(krate);
|
||||
visit::walk_crate(&mut indexer, krate);
|
||||
|
||||
return indexer.index;
|
||||
|
||||
struct Indexer<'s, 'a> {
|
||||
node_id_to_def_id: &'s NodeMap<LocalDefId>,
|
||||
struct Indexer<'a, 'b, R> {
|
||||
resolver: &'b R,
|
||||
index: IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
|
||||
impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'a ast::Item) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item);
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
|
||||
AstOwner::AssocItem(item, ctxt);
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
|
||||
AstOwner::ForeignItem(item);
|
||||
visit::walk_item(self, item);
|
||||
@@ -512,8 +609,7 @@ fn compute_hir_hash(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
let sess = tcx.sess;
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
|
||||
// Queries that borrow `resolver_for_lowering`.
|
||||
tcx.ensure_done().output_filenames(());
|
||||
tcx.ensure_done().early_lint_checks(());
|
||||
@@ -521,7 +617,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
tcx.ensure_done().get_lang_items(());
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
let ast_index = index_crate(&resolver, &krate);
|
||||
let mut owners = IndexVec::from_fn_n(
|
||||
|_| hir::MaybeOwner::Phantom,
|
||||
tcx.definitions_untracked().def_index_count(),
|
||||
@@ -531,25 +627,60 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
tcx,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: &mut owners,
|
||||
owners: Owners::IndexVec(&mut owners),
|
||||
};
|
||||
|
||||
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
|
||||
|
||||
for def_id in ast_index.indices() {
|
||||
lowerer.lower_node(def_id);
|
||||
match &ast_index[def_id] {
|
||||
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
|
||||
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
|
||||
delayed_ids.insert(def_id);
|
||||
}
|
||||
_ => lowerer.lower_node(def_id),
|
||||
};
|
||||
}
|
||||
|
||||
drop(ast_index);
|
||||
|
||||
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
|
||||
let prof = sess.prof.clone();
|
||||
spawn(move || {
|
||||
let _timer = prof.verbose_generic_activity("drop_ast");
|
||||
drop(krate);
|
||||
});
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let opt_hir_hash =
|
||||
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
|
||||
hir::Crate { owners, opt_hir_hash }
|
||||
|
||||
let delayed_resolver = Steal::new((resolver, krate));
|
||||
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
|
||||
}
|
||||
|
||||
/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way.
|
||||
pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let krate = tcx.hir_crate(());
|
||||
|
||||
let (resolver, krate) = &*krate.delayed_resolver.borrow();
|
||||
|
||||
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
|
||||
// as it is too bad to reindex whole crate on each delegation lowering.
|
||||
let ast_index = index_crate(resolver, krate);
|
||||
|
||||
let mut resolver = ResolverDelayedAstLowering {
|
||||
next_node_id: resolver.next_node_id,
|
||||
partial_res_map: Default::default(),
|
||||
node_id_to_def_id: Default::default(),
|
||||
base: resolver,
|
||||
};
|
||||
|
||||
let mut map = Default::default();
|
||||
|
||||
let mut lowerer = item::ItemLowerer {
|
||||
tcx,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: Owners::Map(&mut map),
|
||||
};
|
||||
|
||||
lowerer.lower_node(def_id);
|
||||
|
||||
for (&child_def_id, &owner) in &map {
|
||||
tcx.feed_delayed_owner(child_def_id, owner);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
@@ -579,7 +710,7 @@ enum GenericArgsMode {
|
||||
Silence,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn create_def(
|
||||
&mut self,
|
||||
node_id: ast::NodeId,
|
||||
@@ -605,22 +736,19 @@ fn create_def(
|
||||
.def_id();
|
||||
|
||||
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
|
||||
self.resolver.node_id_to_def_id.insert(node_id, def_id);
|
||||
self.resolver.insert_new_def_id(node_id, def_id);
|
||||
|
||||
def_id
|
||||
}
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
let start = self.resolver.next_node_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
self.resolver.next_node_id = ast::NodeId::from_u32(next);
|
||||
start
|
||||
self.resolver.next_node_id()
|
||||
}
|
||||
|
||||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
/// resolver (if any).
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||||
self.resolver.node_id_to_def_id.get(&node).copied()
|
||||
self.resolver.opt_local_def_id(node)
|
||||
}
|
||||
|
||||
fn local_def_id(&self, node: NodeId) -> LocalDefId {
|
||||
@@ -749,7 +877,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
}
|
||||
|
||||
if let Some(&traits) = self.resolver.trait_map.get(&ast_node_id) {
|
||||
if let Some(traits) = self.resolver.trait_candidates(ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits);
|
||||
}
|
||||
|
||||
@@ -1269,9 +1397,13 @@ fn lower_generic_arg(
|
||||
}
|
||||
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
|
||||
}
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(
|
||||
self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
|
||||
),
|
||||
ast::GenericArg::Const(ct) => {
|
||||
let ct = self.lower_anon_const_to_const_arg_and_alloc(ct);
|
||||
match ct.try_as_ambig_ct() {
|
||||
Some(ct) => GenericArg::Const(ct),
|
||||
None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1766,7 +1898,7 @@ fn lower_fn_decl(
|
||||
inputs,
|
||||
output,
|
||||
c_variadic,
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id),
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id),
|
||||
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
|
||||
let is_mutable_pat = matches!(
|
||||
arg.pat.kind,
|
||||
@@ -2953,7 +3085,10 @@ fn is_empty(&self) -> bool {
|
||||
&& self.parenthesized == hir::GenericArgsParentheses::No
|
||||
}
|
||||
|
||||
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
|
||||
fn into_generic_args(
|
||||
self,
|
||||
this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
let ga = hir::GenericArgs {
|
||||
args: this.arena.alloc_from_iter(self.args),
|
||||
constraints: self.constraints,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
|
||||
use crate::{AllowReturnTypeNotation, ImplTraitPosition};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(self.lower_pat_mut(pattern))
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(crate) fn lower_qpath(
|
||||
&mut self,
|
||||
|
||||
@@ -329,6 +329,19 @@ fn print_crate_inner<'a>(
|
||||
/// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,`
|
||||
/// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]`
|
||||
///
|
||||
/// Returns `true` if both token trees are identifier-like tokens that would
|
||||
/// merge into a single token if printed without a space between them.
|
||||
/// E.g. `ident` + `where` would merge into `identwhere`.
|
||||
fn idents_would_merge(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
fn is_ident_like(tt: &TokenTree) -> bool {
|
||||
matches!(
|
||||
tt,
|
||||
TokenTree::Token(Token { kind: token::Ident(..) | token::NtIdent(..), .. }, _,)
|
||||
)
|
||||
}
|
||||
is_ident_like(tt1) && is_ident_like(tt2)
|
||||
}
|
||||
|
||||
fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
use Delimiter::*;
|
||||
use TokenTree::{Delimited as Del, Token as Tok};
|
||||
@@ -737,6 +750,23 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing {
|
||||
TokenTree::Token(token, spacing) => {
|
||||
let token_str = self.token_to_string_ext(token, convert_dollar_crate);
|
||||
self.word(token_str);
|
||||
// Emit hygiene annotations for identity-bearing tokens,
|
||||
// matching how print_ident() and print_lifetime() call ann_post().
|
||||
match token.kind {
|
||||
token::Ident(name, _) => {
|
||||
self.ann_post(Ident::new(name, token.span));
|
||||
}
|
||||
token::NtIdent(ident, _) => {
|
||||
self.ann_post(ident);
|
||||
}
|
||||
token::Lifetime(name, _) => {
|
||||
self.ann_post(Ident::new(name, token.span));
|
||||
}
|
||||
token::NtLifetime(ident, _) => {
|
||||
self.ann_post(ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let token::DocComment(..) = token.kind {
|
||||
self.hardbreak()
|
||||
}
|
||||
@@ -794,6 +824,13 @@ fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||
if let Some(next) = iter.peek() {
|
||||
if spacing == Spacing::Alone && space_between(tt, next) {
|
||||
self.space();
|
||||
} else if spacing != Spacing::Alone && idents_would_merge(tt, next) {
|
||||
// When tokens from macro `tt` captures preserve their
|
||||
// original `Joint`/`JointHidden` spacing, adjacent
|
||||
// identifier-like tokens can be concatenated without a
|
||||
// space (e.g. `$x:identwhere`). Insert a space to
|
||||
// prevent this.
|
||||
self.space();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +260,15 @@ fn print_expr_method_call(
|
||||
//
|
||||
// loop { break x; }.method();
|
||||
//
|
||||
self.print_expr_cond_paren(
|
||||
receiver,
|
||||
receiver.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression_with_dot(),
|
||||
);
|
||||
let needs_paren = receiver.precedence() < ExprPrecedence::Unambiguous;
|
||||
self.print_expr_cond_paren(receiver, needs_paren, fixup.leftmost_subexpression_with_dot());
|
||||
|
||||
// If the receiver is an unsuffixed float literal like `0.`, insert
|
||||
// a space so the `.` of the method call doesn't merge with the
|
||||
// trailing dot: `0. .method()` instead of `0..method()`.
|
||||
if !needs_paren && expr_ends_with_dot(receiver) {
|
||||
self.word(" ");
|
||||
}
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(args) = &segment.args {
|
||||
@@ -658,11 +661,15 @@ pub(super) fn print_expr_outer_attr_style(
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
let needs_paren = expr.precedence() < ExprPrecedence::Unambiguous;
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
needs_paren,
|
||||
fixup.leftmost_subexpression_with_dot(),
|
||||
);
|
||||
if !needs_paren && expr_ends_with_dot(expr) {
|
||||
self.word(" ");
|
||||
}
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
@@ -685,11 +692,15 @@ pub(super) fn print_expr_outer_attr_style(
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
start_fixup.precedence(e) < fake_prec,
|
||||
start_fixup,
|
||||
);
|
||||
let needs_paren = start_fixup.precedence(e) < fake_prec;
|
||||
self.print_expr_cond_paren(e, needs_paren, start_fixup);
|
||||
// If the start expression is a float literal ending with
|
||||
// `.`, we need a space before `..` or `..=` so that the
|
||||
// dots don't merge. E.g. `0. ..45.` must not become
|
||||
// `0...45.`.
|
||||
if !needs_paren && expr_ends_with_dot(e) {
|
||||
self.word(" ");
|
||||
}
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
@@ -1025,3 +1036,18 @@ fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String
|
||||
template.push('"');
|
||||
template
|
||||
}
|
||||
|
||||
/// Returns `true` if the printed representation of this expression ends with
|
||||
/// a `.` character — specifically, an unsuffixed float literal like `0.` or
|
||||
/// `45.`. This is used to insert whitespace before range operators (`..`,
|
||||
/// `..=`) so that the dots don't merge (e.g. `0. ..45.` instead of `0...45.`).
|
||||
fn expr_ends_with_dot(expr: &ast::Expr) -> bool {
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Lit(token_lit) => {
|
||||
token_lit.kind == token::Float
|
||||
&& token_lit.suffix.is_none()
|
||||
&& token_lit.symbol.as_str().ends_with('.')
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -881,7 +881,13 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
|
||||
}
|
||||
if items.is_empty() {
|
||||
self.word("{}");
|
||||
} else if let [(item, _)] = items.as_slice() {
|
||||
} else if let [(item, _)] = items.as_slice()
|
||||
&& !item
|
||||
.prefix
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|seg| seg.ident.name == rustc_span::symbol::kw::SelfLower)
|
||||
{
|
||||
self.print_use_tree(item);
|
||||
} else {
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::context::{AcceptContext, ShouldEmit, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
|
||||
use crate::parser::{
|
||||
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
|
||||
};
|
||||
use crate::session_diagnostics::{
|
||||
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
||||
ParsedDescription,
|
||||
@@ -363,6 +365,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -94,6 +94,7 @@ pub fn parse_cfg_select(
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
p,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
|
||||
@@ -169,7 +169,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
return None;
|
||||
};
|
||||
let Some(classname) = nv.value_as_str() else {
|
||||
// `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
|
||||
// `#[rustc_objc_class = ...]` is expected to be used as an implementation detail
|
||||
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
||||
// Use a custom error message instead.
|
||||
cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
|
||||
@@ -201,7 +201,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
return None;
|
||||
};
|
||||
let Some(methname) = nv.value_as_str() else {
|
||||
// `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
|
||||
// `#[rustc_objc_selector = ...]` is expected to be used as an implementation detail
|
||||
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
|
||||
// Use a custom error message instead.
|
||||
cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
pub(crate) mod do_not_recommend;
|
||||
pub(crate) mod on_const;
|
||||
pub(crate) mod on_move;
|
||||
pub(crate) mod on_unimplemented;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -32,6 +33,8 @@ pub(crate) enum Mode {
|
||||
DiagnosticOnUnimplemented,
|
||||
/// `#[diagnostic::on_const]`
|
||||
DiagnosticOnConst,
|
||||
/// `#[diagnostic::on_move]`
|
||||
DiagnosticOnMove,
|
||||
}
|
||||
|
||||
fn merge_directives<S: Stage>(
|
||||
@@ -113,6 +116,13 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
span,
|
||||
);
|
||||
}
|
||||
Mode::DiagnosticOnMove => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnMoveAttr { span },
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}}
|
||||
@@ -132,7 +142,7 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
Mode::RustcOnUnimplemented => {
|
||||
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
|
||||
}
|
||||
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst => {
|
||||
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::IgnoredDiagnosticOption {
|
||||
@@ -460,11 +470,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString {
|
||||
// if the integer type has been resolved, to allow targeting all integers.
|
||||
// `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet,
|
||||
// from the `Display` impl of `InferTy` to be precise.
|
||||
// `"{union|enum|struct}"` is used as a special selector for ADTs.
|
||||
//
|
||||
// Don't try to format these later!
|
||||
Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => {
|
||||
LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}")))
|
||||
}
|
||||
Position::ArgumentNamed(
|
||||
arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
|
||||
) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))),
|
||||
|
||||
Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
|
||||
Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnMoveParser {
|
||||
span: Option<Span>,
|
||||
directive: Option<(Span, Directive)>,
|
||||
}
|
||||
|
||||
impl OnMoveParser {
|
||||
fn parse<'sess, S: Stage>(
|
||||
&mut self,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
args: &ArgParser,
|
||||
mode: Mode,
|
||||
) {
|
||||
if !cx.features().diagnostic_on_move() {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.attr_span;
|
||||
self.span = Some(span);
|
||||
let Some(list) = args.list() else {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnMove,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
|
||||
list.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
|
||||
merge_directives(cx, &mut self.directive, (span, directive));
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<S: Stage> AttributeParser<S> for OnMoveParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::diagnostic, sym::on_move],
|
||||
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|
||||
|this, cx, args| {
|
||||
this.parse(cx, args, Mode::DiagnosticOnMove);
|
||||
},
|
||||
)];
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(span) = self.span {
|
||||
Some(AttributeKind::OnMove { span, directive: self.directive.map(|d| Box::new(d.1)) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
use crate::target_checking::AllowedTargets;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
|
||||
@@ -57,6 +58,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
let dialect = parse_dialect(cx, dialect, &mut failed);
|
||||
let phase = parse_phase(cx, phase, &mut failed);
|
||||
check_custom_mir(cx, dialect, phase, &mut failed);
|
||||
|
||||
if failed {
|
||||
return None;
|
||||
@@ -138,3 +140,51 @@ fn parse_phase<S: Stage>(
|
||||
|
||||
Some((phase, span))
|
||||
}
|
||||
|
||||
fn check_custom_mir<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
dialect: Option<(MirDialect, Span)>,
|
||||
phase: Option<(MirPhase, Span)>,
|
||||
failed: &mut bool,
|
||||
) {
|
||||
let attr_span = cx.attr_span;
|
||||
let Some((dialect, dialect_span)) = dialect else {
|
||||
if let Some((_, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirPhaseRequiresDialect {
|
||||
attr_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
match dialect {
|
||||
MirDialect::Analysis => {
|
||||
if let Some((MirPhase::Optimized, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||
dialect,
|
||||
phase: MirPhase::Optimized,
|
||||
attr_span,
|
||||
dialect_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MirDialect::Built => {
|
||||
if let Some((phase, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||
dialect,
|
||||
phase,
|
||||
attr_span,
|
||||
dialect_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
MirDialect::Runtime => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::num::NonZero;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_feature::ACCEPTED_LANG_FEATURES;
|
||||
use rustc_hir::target::GenericParamKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||
@@ -366,7 +367,7 @@ pub(crate) fn parse_stability<S: Stage>(
|
||||
}
|
||||
}
|
||||
|
||||
// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// attribute, and return the feature name and its stability information.
|
||||
pub(crate) fn parse_unstability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
@@ -451,6 +452,16 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
|
||||
match (feature, issue) {
|
||||
(Ok(feature), Ok(_)) => {
|
||||
// Stable *language* features shouldn't be used as unstable library features.
|
||||
// (Not doing this for stable library features is checked by tidy.)
|
||||
if ACCEPTED_LANG_FEATURES.iter().any(|f| f.name == feature) {
|
||||
cx.emit_err(session_diagnostics::UnstableAttrForAlreadyStableFeature {
|
||||
attr_span: cx.attr_span,
|
||||
item_span: cx.target_span,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
let level = StabilityLevel::Unstable {
|
||||
reason: UnstableReason::from_opt_reason(reason),
|
||||
issue: issue_num,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
use crate::attributes::deprecation::*;
|
||||
use crate::attributes::diagnostic::do_not_recommend::*;
|
||||
use crate::attributes::diagnostic::on_const::*;
|
||||
use crate::attributes::diagnostic::on_move::*;
|
||||
use crate::attributes::diagnostic::on_unimplemented::*;
|
||||
use crate::attributes::doc::*;
|
||||
use crate::attributes::dummy::*;
|
||||
@@ -149,6 +150,7 @@ mod late {
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
OnConstParser,
|
||||
OnMoveParser,
|
||||
OnUnimplementedParser,
|
||||
RustcAlignParser,
|
||||
RustcAlignStaticParser,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
||||
@@ -139,6 +139,7 @@ pub fn parse_single<T>(
|
||||
emit_errors: ShouldEmit,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
|
||||
template: &AttributeTemplate,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Option<T> {
|
||||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
@@ -152,6 +153,7 @@ pub fn parse_single<T>(
|
||||
&parts,
|
||||
&sess.psess,
|
||||
emit_errors,
|
||||
allow_expr_metavar,
|
||||
)?;
|
||||
Self::parse_single_args(
|
||||
sess,
|
||||
@@ -333,6 +335,7 @@ pub fn parse_attribute_list(
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
AllowExprMetavar::No,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -109,6 +109,7 @@ pub fn from_attr_args<'sess>(
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Option<Self> {
|
||||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
@@ -122,6 +123,7 @@ pub fn from_attr_args<'sess>(
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
|
||||
allow_expr_metavar,
|
||||
) {
|
||||
Ok(p) => return Some(ArgParser::List(p)),
|
||||
Err(e) => {
|
||||
@@ -147,9 +149,15 @@ pub fn from_attr_args<'sess>(
|
||||
}
|
||||
|
||||
Self::List(
|
||||
MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()?,
|
||||
MetaItemListParser::new(
|
||||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
should_emit,
|
||||
allow_expr_metavar,
|
||||
)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()?,
|
||||
)
|
||||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
@@ -217,8 +225,9 @@ impl MetaItemOrLitParser {
|
||||
pub fn parse_single<'sess>(
|
||||
parser: &mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> PResult<'sess, MetaItemOrLitParser> {
|
||||
let mut this = MetaItemListParserContext { parser, should_emit };
|
||||
let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
|
||||
this.parse_meta_item_inner()
|
||||
}
|
||||
|
||||
@@ -404,9 +413,19 @@ fn expr_to_lit<'sess>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether expansions of `expr` metavariables from decrarative macros
|
||||
/// are permitted. Used when parsing meta items; currently, only `cfg` predicates
|
||||
/// enable this option
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AllowExprMetavar {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
parser: &'a mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
}
|
||||
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
@@ -447,20 +466,44 @@ fn unsuffixed_meta_item_from_lit(
|
||||
Ok(lit)
|
||||
}
|
||||
|
||||
fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext { parser: this, should_emit: self.should_emit }
|
||||
.parse_attr_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
if let Some(metavar) = self.parser.token.is_metavar_seq() {
|
||||
match (metavar, self.allow_expr_metavar) {
|
||||
(kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
|
||||
return self
|
||||
.parser
|
||||
.eat_metavar_seq(kind, |this| {
|
||||
MetaItemListParserContext {
|
||||
parser: this,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: AllowExprMetavar::Yes,
|
||||
}
|
||||
.parse_meta_item()
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
|
||||
});
|
||||
}
|
||||
(MetaVarKind::Meta { has_meta_form }, _) => {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext {
|
||||
parser: this,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: self.allow_expr_metavar,
|
||||
}
|
||||
.parse_meta_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let path = self.parser.parse_path(PathStyle::Mod)?;
|
||||
@@ -469,8 +512,12 @@ fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
let args = if self.parser.check(exp!(OpenParen)) {
|
||||
let start = self.parser.token.span;
|
||||
let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
|
||||
MetaItemListParserContext { parser, should_emit: self.should_emit }
|
||||
.parse_meta_item_inner()
|
||||
MetaItemListParserContext {
|
||||
parser,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: self.allow_expr_metavar,
|
||||
}
|
||||
.parse_meta_item_inner()
|
||||
})?;
|
||||
let end = self.parser.prev_token.span;
|
||||
ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
|
||||
@@ -492,7 +539,7 @@ fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
|
||||
Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
|
||||
} else {
|
||||
let prev_pros = self.parser.approx_token_stream_pos();
|
||||
match self.parse_attr_item() {
|
||||
match self.parse_meta_item() {
|
||||
Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
|
||||
Err(err) => {
|
||||
// If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
|
||||
@@ -580,13 +627,15 @@ fn parse(
|
||||
psess: &'sess ParseSess,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> PResult<'sess, MetaItemListParser> {
|
||||
let mut parser = Parser::new(psess, tokens, None);
|
||||
if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
|
||||
parser = parser.recovery(recovery);
|
||||
}
|
||||
|
||||
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
||||
let mut this =
|
||||
MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
|
||||
|
||||
// Presumably, the majority of the time there will only be one attr.
|
||||
let mut sub_parsers = ThinVec::with_capacity(1);
|
||||
@@ -618,8 +667,15 @@ pub(crate) fn new<'sess>(
|
||||
span: Span,
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Result<Self, Diag<'sess>> {
|
||||
MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit)
|
||||
MetaItemListParserContext::parse(
|
||||
tokens.clone(),
|
||||
psess,
|
||||
span,
|
||||
should_emit,
|
||||
allow_expr_metavar,
|
||||
)
|
||||
}
|
||||
|
||||
/// Lets you pick and choose as what you want to parse each element in the list
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::{MirDialect, MirPhase};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
@@ -1023,3 +1024,36 @@ pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||
pub instruction_set: Symbol,
|
||||
pub current_target: &'a TargetTuple,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`dialect` key required")]
|
||||
pub(crate) struct CustomMirPhaseRequiresDialect {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label("`phase` argument requires a `dialect` argument")]
|
||||
pub phase_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
|
||||
pub(crate) struct CustomMirIncompatibleDialectAndPhase {
|
||||
pub dialect: MirDialect,
|
||||
pub phase: MirPhase,
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label("this dialect...")]
|
||||
pub dialect_span: Span,
|
||||
#[label("... is not compatible with this phase")]
|
||||
pub phase_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("can't mark as unstable using an already stable feature")]
|
||||
pub(crate) struct UnstableAttrForAlreadyStableFeature {
|
||||
#[primary_span]
|
||||
#[label("this feature is already stable")]
|
||||
#[help("consider removing the attribute")]
|
||||
pub attr_span: Span,
|
||||
#[label("the stability attribute annotates this item")]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
@@ -324,18 +324,23 @@ pub(crate) fn cannot_act_on_moved_value(
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: Option<String>,
|
||||
primary_message: Option<String>,
|
||||
) -> Diag<'infcx> {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
if let Some(primary_message) = primary_message {
|
||||
struct_span_code_err!(self.dcx(), use_span, E0382, "{}", primary_message)
|
||||
} else {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
use_span,
|
||||
E0382,
|
||||
"{} of {}moved value{}",
|
||||
verb,
|
||||
optional_adverb_for_moved,
|
||||
moved_path,
|
||||
)
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
use_span,
|
||||
E0382,
|
||||
"{} of {}moved value{}",
|
||||
verb,
|
||||
optional_adverb_for_moved,
|
||||
moved_path,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_borrow_path_as_mutable_because(
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
use either::Either;
|
||||
use hir::{ClosureKind, Path};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::diagnostic::FormatArgs;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
|
||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
|
||||
use rustc_hir::{
|
||||
CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::{
|
||||
@@ -138,6 +142,36 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
let partial_str = if is_partial_move { "partial " } else { "" };
|
||||
let partially_str = if is_partial_move { "partially " } else { "" };
|
||||
|
||||
let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) =
|
||||
self.body.local_decls[moved_place.local].ty.kind()
|
||||
&& let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. } => directive)
|
||||
{
|
||||
let item_name = self.infcx.tcx.item_name(item_def.did()).to_string();
|
||||
let mut generic_args: Vec<_> = self
|
||||
.infcx
|
||||
.tcx
|
||||
.generics_of(item_def.did())
|
||||
.own_params
|
||||
.iter()
|
||||
.filter_map(|param| Some((param.name, args[param.index as usize].to_string())))
|
||||
.collect();
|
||||
generic_args.push((kw::SelfUpper, item_name));
|
||||
|
||||
let args = FormatArgs {
|
||||
this: String::new(),
|
||||
trait_sugared: String::new(),
|
||||
item_context: "",
|
||||
generic_args,
|
||||
};
|
||||
(
|
||||
directive.message.as_ref().map(|e| e.1.format(&args)),
|
||||
directive.label.as_ref().map(|e| e.1.format(&args)),
|
||||
directive.notes.iter().map(|e| e.format(&args)).collect(),
|
||||
)
|
||||
} else {
|
||||
(None, None, ThinVec::new())
|
||||
};
|
||||
|
||||
let mut err = self.cannot_act_on_moved_value(
|
||||
span,
|
||||
desired_action.as_noun(),
|
||||
@@ -146,8 +180,13 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
moved_place,
|
||||
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
|
||||
),
|
||||
on_move_message,
|
||||
);
|
||||
|
||||
for note in on_move_notes {
|
||||
err.note(note);
|
||||
}
|
||||
|
||||
let reinit_spans = maybe_reinitialized_locations
|
||||
.iter()
|
||||
.take(3)
|
||||
@@ -275,12 +314,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
if needs_note {
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
if let Some(on_move_label) = on_move_label {
|
||||
err.span_label(span, on_move_label);
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
|
||||
@@ -374,10 +374,6 @@ fn body(&self) -> &Body<'tcx> {
|
||||
self.body
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
self.tcx().features().unsized_fn_params()
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
@@ -660,7 +656,7 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
|
||||
);
|
||||
}
|
||||
|
||||
if !self.unsized_feature_enabled() {
|
||||
if !self.tcx().features().unsized_fn_params() {
|
||||
let trait_ref = ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Sized, self.last_span),
|
||||
@@ -936,9 +932,10 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is enabled, only function calls
|
||||
// and nullary ops are checked in `check_call_dest`.
|
||||
if !self.unsized_feature_enabled() {
|
||||
// When `unsized_fn_params` is enabled, this is checked in `check_call_dest`,
|
||||
// and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't
|
||||
// fully re-check what was already checked on HIR).
|
||||
if !self.tcx().features().unsized_fn_params() {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
@@ -1953,8 +1950,8 @@ fn check_call_dest(
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
// this check is done at `visit_local_decl`.
|
||||
if self.tcx().features().unsized_fn_params() {
|
||||
let span = term.source_info.span;
|
||||
self.ensure_place_sized(dest_ty, span);
|
||||
}
|
||||
|
||||
@@ -616,4 +616,9 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
}
|
||||
})]);
|
||||
}
|
||||
|
||||
fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
|
||||
// Past hir typeck, so we don't have to worry about type inference anymore.
|
||||
self.type_checker.infcx.next_ty_var(self.span())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, token};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::parser::MetaItemOrLitParser;
|
||||
use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser};
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
|
||||
self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
@@ -44,6 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
&mut parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
|
||||
@@ -4,13 +4,13 @@ Date: Sun, 15 Feb 2026 14:06:49 +0000
|
||||
Subject: [PATCH] Disable f16 math tests for cranelift
|
||||
|
||||
---
|
||||
coretests/tests/floats/mod.rs | 26 +++++++++++++-------------
|
||||
coretests/tests/num/floats.rs | 26 +++++++++++++-------------
|
||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs
|
||||
index c61961f8584..d7b4fa20322 100644
|
||||
--- a/coretests/tests/floats/mod.rs
|
||||
+++ b/coretests/tests/floats/mod.rs
|
||||
--- a/coretests/tests/num/floats.rs
|
||||
+++ b/coretests/tests/num/floats.rs
|
||||
@@ -1534,7 +1534,7 @@ fn s_nan() -> Float {
|
||||
name: powf,
|
||||
attrs: {
|
||||
@@ -128,6 +128,5 @@ index c61961f8584..d7b4fa20322 100644
|
||||
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
|
||||
},
|
||||
test {
|
||||
--
|
||||
--
|
||||
2.50.1
|
||||
|
||||
|
||||
@@ -23,9 +23,7 @@
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
|
||||
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
|
||||
use rustc_target::spec::{
|
||||
Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel,
|
||||
};
|
||||
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::back::lto::{Buffer, ModuleBuffer};
|
||||
@@ -206,13 +204,7 @@ pub(crate) fn target_machine_factory(
|
||||
let reloc_model = to_llvm_relocation_model(sess.relocation_model());
|
||||
|
||||
let (opt_level, _) = to_llvm_opt_settings(optlvl);
|
||||
let float_abi = if sess.target.arch == Arch::Arm && sess.opts.cg.soft_float {
|
||||
llvm::FloatAbi::Soft
|
||||
} else {
|
||||
// `validate_commandline_args_with_session_available` has already warned about this being
|
||||
// ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets.
|
||||
to_llvm_float_abi(sess.target.llvm_floatabi)
|
||||
};
|
||||
let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi);
|
||||
|
||||
let ffunction_sections =
|
||||
sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections);
|
||||
|
||||
@@ -394,8 +394,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
// ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
|
||||
// list at <https://github.com/rust-lang/rust/issues/116909>)
|
||||
(Arch::PowerPC | Arch::PowerPC64, _) => false,
|
||||
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838>
|
||||
(Arch::Sparc, _) => false,
|
||||
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> (fixed in llvm22)
|
||||
(Arch::Sparc, _) if major < 22 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// There are no known problems on other platforms, so the only requirement is that symbols
|
||||
|
||||
@@ -437,7 +437,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
assert_eq!(
|
||||
None,
|
||||
num_untupled.replace(tupled_arg_tys.len()),
|
||||
"Replaced existing num_tupled"
|
||||
"Replaced existing num_untupled"
|
||||
);
|
||||
|
||||
return LocalRef::Place(place);
|
||||
|
||||
@@ -188,53 +188,6 @@ pub fn assert_dyn_send<T: ?Sized + PointeeSized + DynSend>() {}
|
||||
pub fn assert_dyn_send_val<T: ?Sized + PointeeSized + DynSend>(_t: &T) {}
|
||||
pub fn assert_dyn_send_sync_val<T: ?Sized + PointeeSized + DynSync + DynSend>(_t: &T) {}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FromDyn<T>(T);
|
||||
|
||||
impl<T> FromDyn<T> {
|
||||
#[inline(always)]
|
||||
pub fn from(val: T) -> Self {
|
||||
// Check that `sync::is_dyn_thread_safe()` is true on creation so we can
|
||||
// implement `Send` and `Sync` for this structure when `T`
|
||||
// implements `DynSend` and `DynSync` respectively.
|
||||
assert!(crate::sync::is_dyn_thread_safe());
|
||||
FromDyn(val)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn derive<O>(&self, val: O) -> FromDyn<O> {
|
||||
// We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
|
||||
FromDyn(val)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||
unsafe impl<T: DynSend> Send for FromDyn<T> {}
|
||||
|
||||
// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||
unsafe impl<T: DynSync> Sync for FromDyn<T> {}
|
||||
|
||||
impl<T> std::ops::Deref for FromDyn<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::DerefMut for FromDyn<T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
// A wrapper to convert a struct that is already a `Send` or `Sync` into
|
||||
// an instance of `DynSend` and `DynSync`, since the compiler cannot infer
|
||||
// it automatically in some cases. (e.g. Box<dyn Send / Sync>)
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
|
||||
#[doc(no_inline)]
|
||||
pub use self::lock::{Lock, LockGuard, Mode};
|
||||
pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
|
||||
pub use self::mode::{
|
||||
FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode,
|
||||
};
|
||||
pub use self::parallel::{
|
||||
broadcast, par_fns, par_for_each_in, par_join, par_map, parallel_guard, spawn,
|
||||
try_par_for_each_in,
|
||||
@@ -64,12 +66,20 @@ mod atomic {
|
||||
mod mode {
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
|
||||
use crate::sync::{DynSend, DynSync};
|
||||
|
||||
const UNINITIALIZED: u8 = 0;
|
||||
const DYN_NOT_THREAD_SAFE: u8 = 1;
|
||||
const DYN_THREAD_SAFE: u8 = 2;
|
||||
|
||||
static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED);
|
||||
|
||||
// Whether thread safety is enabled (due to running under multiple threads).
|
||||
#[inline]
|
||||
pub fn check_dyn_thread_safe() -> Option<FromDyn<()>> {
|
||||
is_dyn_thread_safe().then_some(FromDyn(()))
|
||||
}
|
||||
|
||||
// Whether thread safety is enabled (due to running under multiple threads).
|
||||
#[inline]
|
||||
pub fn is_dyn_thread_safe() -> bool {
|
||||
@@ -99,6 +109,44 @@ pub fn set_dyn_thread_safe_mode(mode: bool) {
|
||||
// Check that the mode was either uninitialized or was already set to the requested mode.
|
||||
assert!(previous.is_ok() || previous == Err(set));
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FromDyn<T>(T);
|
||||
|
||||
impl<T> FromDyn<T> {
|
||||
#[inline(always)]
|
||||
pub fn derive<O>(&self, val: O) -> FromDyn<O> {
|
||||
// We already did the check for `sync::is_dyn_thread_safe()` when creating `Self`
|
||||
FromDyn(val)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||
unsafe impl<T: DynSend> Send for FromDyn<T> {}
|
||||
|
||||
// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
|
||||
unsafe impl<T: DynSync> Sync for FromDyn<T> {}
|
||||
|
||||
impl<T> std::ops::Deref for FromDyn<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::DerefMut for FromDyn<T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This makes locks panic if they are already held.
|
||||
|
||||
@@ -57,8 +57,8 @@ fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
|
||||
}
|
||||
|
||||
pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let func = FromDyn::from(func);
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let func = proof.derive(func);
|
||||
rustc_thread_pool::spawn(|| {
|
||||
(func.into_inner())();
|
||||
});
|
||||
@@ -73,8 +73,8 @@ pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
||||
/// Use that for the longest running function for better scheduling.
|
||||
pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
|
||||
parallel_guard(|guard: &ParallelGuard| {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let funcs = FromDyn::from(funcs);
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let funcs = proof.derive(funcs);
|
||||
rustc_thread_pool::scope(|s| {
|
||||
let Some((first, rest)) = funcs.into_inner().split_at_mut_checked(1) else {
|
||||
return;
|
||||
@@ -84,7 +84,7 @@ pub fn par_fns(funcs: &mut [&mut (dyn FnMut() + DynSend)]) {
|
||||
// order when using a single thread. This ensures the execution order matches
|
||||
// that of a single threaded rustc.
|
||||
for f in rest.iter_mut().rev() {
|
||||
let f = FromDyn::from(f);
|
||||
let f = proof.derive(f);
|
||||
s.spawn(|_| {
|
||||
guard.run(|| (f.into_inner())());
|
||||
});
|
||||
@@ -108,13 +108,13 @@ pub fn par_join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB
|
||||
A: FnOnce() -> RA + DynSend,
|
||||
B: FnOnce() -> RB + DynSend,
|
||||
{
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let oper_a = FromDyn::from(oper_a);
|
||||
let oper_b = FromDyn::from(oper_b);
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let oper_a = proof.derive(oper_a);
|
||||
let oper_b = proof.derive(oper_b);
|
||||
let (a, b) = parallel_guard(|guard| {
|
||||
rustc_thread_pool::join(
|
||||
move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
|
||||
move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
|
||||
move || guard.run(move || proof.derive(oper_a.into_inner()())),
|
||||
move || guard.run(move || proof.derive(oper_b.into_inner()())),
|
||||
)
|
||||
});
|
||||
(a.unwrap().into_inner(), b.unwrap().into_inner())
|
||||
@@ -127,13 +127,30 @@ fn par_slice<I: DynSend>(
|
||||
items: &mut [I],
|
||||
guard: &ParallelGuard,
|
||||
for_each: impl Fn(&mut I) + DynSync + DynSend,
|
||||
proof: FromDyn<()>,
|
||||
) {
|
||||
let for_each = FromDyn::from(for_each);
|
||||
match items {
|
||||
[] => return,
|
||||
[item] => {
|
||||
guard.run(|| for_each(item));
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let for_each = proof.derive(for_each);
|
||||
let mut items = for_each.derive(items);
|
||||
rustc_thread_pool::scope(|s| {
|
||||
let proof = items.derive(());
|
||||
let group_size = std::cmp::max(items.len() / 128, 1);
|
||||
for group in items.chunks_mut(group_size) {
|
||||
|
||||
const MAX_GROUP_COUNT: usize = 128;
|
||||
let group_size = items.len().div_ceil(MAX_GROUP_COUNT);
|
||||
let groups = items.chunks_mut(group_size);
|
||||
|
||||
// Reverse the order of the later functions since Rayon executes them in reverse
|
||||
// order when using a single thread. This ensures the execution order matches
|
||||
// that of a single threaded rustc.
|
||||
for group in groups.rev() {
|
||||
let group = proof.derive(group);
|
||||
s.spawn(|_| {
|
||||
let mut group = group;
|
||||
@@ -150,9 +167,9 @@ pub fn par_for_each_in<I: DynSend, T: IntoIterator<Item = I>>(
|
||||
for_each: impl Fn(&I) + DynSync + DynSend,
|
||||
) {
|
||||
parallel_guard(|guard| {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let mut items: Vec<_> = t.into_iter().collect();
|
||||
par_slice(&mut items, guard, |i| for_each(&*i))
|
||||
par_slice(&mut items, guard, |i| for_each(&*i), proof)
|
||||
} else {
|
||||
t.into_iter().for_each(|i| {
|
||||
guard.run(|| for_each(&i));
|
||||
@@ -173,16 +190,21 @@ pub fn try_par_for_each_in<T: IntoIterator, E: DynSend>(
|
||||
<T as IntoIterator>::Item: DynSend,
|
||||
{
|
||||
parallel_guard(|guard| {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let mut items: Vec<_> = t.into_iter().collect();
|
||||
|
||||
let error = Mutex::new(None);
|
||||
|
||||
par_slice(&mut items, guard, |i| {
|
||||
if let Err(err) = for_each(&*i) {
|
||||
*error.lock() = Some(err);
|
||||
}
|
||||
});
|
||||
par_slice(
|
||||
&mut items,
|
||||
guard,
|
||||
|i| {
|
||||
if let Err(err) = for_each(&*i) {
|
||||
*error.lock() = Some(err);
|
||||
}
|
||||
},
|
||||
proof,
|
||||
);
|
||||
|
||||
if let Some(err) = error.into_inner() { Err(err) } else { Ok(()) }
|
||||
} else {
|
||||
@@ -196,15 +218,20 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
|
||||
map: impl Fn(I) -> R + DynSync + DynSend,
|
||||
) -> C {
|
||||
parallel_guard(|guard| {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let map = FromDyn::from(map);
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let map = proof.derive(map);
|
||||
|
||||
let mut items: Vec<(Option<I>, Option<R>)> =
|
||||
t.into_iter().map(|i| (Some(i), None)).collect();
|
||||
|
||||
par_slice(&mut items, guard, |i| {
|
||||
i.1 = Some(map(i.0.take().unwrap()));
|
||||
});
|
||||
par_slice(
|
||||
&mut items,
|
||||
guard,
|
||||
|i| {
|
||||
i.1 = Some(map(i.0.take().unwrap()));
|
||||
},
|
||||
proof,
|
||||
);
|
||||
|
||||
items.into_iter().filter_map(|i| i.1).collect()
|
||||
} else {
|
||||
@@ -214,8 +241,8 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
|
||||
}
|
||||
|
||||
pub fn broadcast<R: DynSend>(op: impl Fn(usize) -> R + DynSync) -> Vec<R> {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let op = FromDyn::from(op);
|
||||
if let Some(proof) = mode::check_dyn_thread_safe() {
|
||||
let op = proof.derive(op);
|
||||
let results = rustc_thread_pool::broadcast(|context| op.derive(op(context.index())));
|
||||
results.into_iter().map(|r| r.into_inner()).collect()
|
||||
} else {
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute,
|
||||
HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
|
||||
};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::parser::AllowExprMetavar;
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
|
||||
self as attr, AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry,
|
||||
parse_cfg,
|
||||
};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_errors::msg;
|
||||
@@ -402,6 +403,7 @@ pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> Eval
|
||||
emit_errors,
|
||||
parse_cfg,
|
||||
&CFG_TEMPLATE,
|
||||
AllowExprMetavar::Yes,
|
||||
) else {
|
||||
// Cfg attribute was not parsable, give up
|
||||
return EvalConfigResult::True;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
TyKind, token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::parser::AllowExprMetavar;
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
|
||||
parse_cfg, validate_attr,
|
||||
@@ -2224,6 +2225,7 @@ fn expand_cfg_true(
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
parse_cfg,
|
||||
&CFG_TEMPLATE,
|
||||
AllowExprMetavar::Yes,
|
||||
) else {
|
||||
// Cfg attribute was not parsable, give up
|
||||
return EvalConfigResult::True;
|
||||
|
||||
@@ -1587,6 +1587,7 @@ pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool
|
||||
match sym {
|
||||
sym::on_unimplemented | sym::do_not_recommend => true,
|
||||
sym::on_const => features.diagnostic_on_const(),
|
||||
sym::on_move => features.diagnostic_on_move(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,6 +472,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, derive_from, "1.91.0", Some(144889)),
|
||||
/// Allows giving non-const impls custom diagnostic messages if attempted to be used as const
|
||||
(unstable, diagnostic_on_const, "1.93.0", Some(143874)),
|
||||
/// Allows giving on-move borrowck custom diagnostic messages for a type
|
||||
(unstable, diagnostic_on_move, "CURRENT_RUSTC_VERSION", Some(150935)),
|
||||
/// Allows `#[doc(cfg(...))]`.
|
||||
(unstable, doc_cfg, "1.21.0", Some(43781)),
|
||||
/// Allows `#[doc(masked)]`.
|
||||
|
||||
@@ -1180,13 +1180,18 @@ pub enum AttributeKind {
|
||||
directive: Option<Box<Directive>>,
|
||||
},
|
||||
|
||||
/// Represents `#[diagnostic::on_move]`
|
||||
OnMove {
|
||||
span: Span,
|
||||
directive: Option<Box<Directive>>,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_on_unimplemented]` and `#[diagnostic::on_unimplemented]`.
|
||||
OnUnimplemented {
|
||||
span: Span,
|
||||
/// None if the directive was malformed in some way.
|
||||
directive: Option<Box<Directive>>,
|
||||
},
|
||||
|
||||
/// Represents `#[optimize(size|speed)]`
|
||||
Optimize(OptimizeAttr, Span),
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
|
||||
NoStd(..) => No,
|
||||
NonExhaustive(..) => Yes, // Needed for rustdoc
|
||||
OnConst { .. } => Yes,
|
||||
OnMove { .. } => Yes,
|
||||
OnUnimplemented { .. } => Yes,
|
||||
Optimize(..) => No,
|
||||
PanicRuntime => No,
|
||||
|
||||
@@ -192,7 +192,7 @@ pub enum DefKind {
|
||||
/// These are all represented with the same `ExprKind::Closure` in the AST and HIR,
|
||||
/// which makes it difficult to distinguish these during def collection. Therefore,
|
||||
/// we treat them all the same, and code which needs to distinguish them can match
|
||||
/// or `hir::ClosureKind` or `type_of`.
|
||||
/// on `hir::ClosureKind` or `type_of`.
|
||||
Closure,
|
||||
/// The definition of a synthetic coroutine body created by the lowering of a
|
||||
/// coroutine-closure, such as an async closure.
|
||||
|
||||
@@ -1667,19 +1667,6 @@ pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level data structure that stores the entire contents of
|
||||
/// the crate currently being compiled.
|
||||
///
|
||||
/// For more details, see the [rustc dev guide].
|
||||
///
|
||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
|
||||
#[derive(Debug)]
|
||||
pub struct Crate<'hir> {
|
||||
pub owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
|
||||
// Only present when incr. comp. is enabled.
|
||||
pub opt_hir_hash: Option<Fingerprint>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Closure<'hir> {
|
||||
pub def_id: LocalDefId,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::HashIgnoredAttrId;
|
||||
use crate::hir::{
|
||||
AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
|
||||
AttributeMap, BodyId, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
|
||||
};
|
||||
use crate::hir_id::ItemLocalId;
|
||||
use crate::lints::DelayedLints;
|
||||
@@ -94,13 +94,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let Crate { owners: _, opt_hir_hash } = self;
|
||||
opt_hir_hash.unwrap().hash_stable(hcx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HashIgnoredAttrId {
|
||||
fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) {
|
||||
/* we don't hash HashIgnoredAttrId, we ignore them */
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
//! This module implements some validity checks for attributes.
|
||||
//! In particular it verifies that `#[inline]` and `#[repr]` attributes are
|
||||
//! attached to items that actually support them and if there are
|
||||
//! conflicts between multiple such attributes attached to the same
|
||||
//! item.
|
||||
//! This module lists attribute targets, with conversions from other types.
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
|
||||
@@ -998,7 +998,7 @@ fn check_type_defn<'tcx>(
|
||||
item: &hir::Item<'tcx>,
|
||||
all_sized: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let _ = tcx.check_representability(item.owner_id.def_id);
|
||||
tcx.ensure_ok().check_representability(item.owner_id.def_id);
|
||||
let adt_def = tcx.adt_def(item.owner_id);
|
||||
|
||||
enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
|
||||
|
||||
@@ -2874,6 +2874,9 @@ fn lower_const_arg_literal(
|
||||
span: Span,
|
||||
) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let ty = if !ty.has_infer() { Some(ty) } else { None };
|
||||
|
||||
if let LitKind::Err(guar) = *kind {
|
||||
return ty::Const::new_error(tcx, guar);
|
||||
}
|
||||
@@ -2905,16 +2908,20 @@ fn try_lower_anon_const_lit(
|
||||
};
|
||||
|
||||
let lit_input = match expr.kind {
|
||||
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: false }),
|
||||
hir::ExprKind::Lit(lit) => {
|
||||
Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: false })
|
||||
}
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
|
||||
hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: lit.node, ty, neg: true }),
|
||||
hir::ExprKind::Lit(lit) => {
|
||||
Some(LitToConstInput { lit: lit.node, ty: Some(ty), neg: true })
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
lit_input.and_then(|l| {
|
||||
if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) {
|
||||
if const_lit_matches_ty(tcx, &l.lit, ty, l.neg) {
|
||||
tcx.at(expr.span)
|
||||
.lit_to_const(l)
|
||||
.map(|value| ty::Const::new_value(tcx, value.valtree, value.ty))
|
||||
|
||||
@@ -1879,7 +1879,7 @@ fn check_expr_struct_fields(
|
||||
if !ocx.try_evaluate_obligations().is_empty() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
Ok(self.resolve_vars_if_possible(adt_ty))
|
||||
Ok(adt_ty)
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
|
||||
use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal};
|
||||
use rustc_hir_analysis::check::potentially_plural_count;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
|
||||
use rustc_index::IndexVec;
|
||||
@@ -276,12 +276,7 @@ pub(in super::super) fn check_argument_types(
|
||||
|
||||
// Record all the argument types, with the args
|
||||
// produced from the above subtyping unification.
|
||||
Ok(Some(
|
||||
formal_input_tys
|
||||
.iter()
|
||||
.map(|&ty| self.resolve_vars_if_possible(ty))
|
||||
.collect(),
|
||||
))
|
||||
Ok(Some(formal_input_tys.to_vec()))
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
@@ -1587,6 +1582,45 @@ struct MismatchedParam<'a> {
|
||||
}
|
||||
}
|
||||
err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
|
||||
if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id)
|
||||
&& let ty::Param(_) =
|
||||
self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind()
|
||||
&& let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id
|
||||
&& let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) {
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn { sig, body, .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)),
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(sig, body),
|
||||
..
|
||||
}) => Some((sig.decl.output, body)),
|
||||
_ => None,
|
||||
}
|
||||
&& let expr = self.tcx.hir_body(*body_id).value
|
||||
&& (expr.peel_blocks().span == call_expr.span
|
||||
|| matches!(
|
||||
self.tcx.parent_hir_node(call_expr.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
))
|
||||
{
|
||||
err.span_label(
|
||||
output.span(),
|
||||
match output {
|
||||
FnRetTy::DefaultReturn(_) => format!(
|
||||
"this implicit `()` return type influences the call expression's return type"
|
||||
),
|
||||
FnRetTy::Return(_) => {
|
||||
"this return type influences the call expression's return type"
|
||||
.to_string()
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
} else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id)
|
||||
&& let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
|
||||
{
|
||||
|
||||
@@ -3460,13 +3460,13 @@ fn consider_suggesting_derives_for_ty(
|
||||
let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id())?;
|
||||
|
||||
let can_derive = match diagnostic_name {
|
||||
sym::Copy | sym::Clone => true,
|
||||
_ if adt.is_union() => false,
|
||||
sym::Default
|
||||
| sym::Eq
|
||||
| sym::PartialEq
|
||||
| sym::Ord
|
||||
| sym::PartialOrd
|
||||
| sym::Clone
|
||||
| sym::Copy
|
||||
| sym::Hash
|
||||
| sym::Debug => true,
|
||||
_ => false,
|
||||
|
||||
@@ -140,6 +140,9 @@ pub fn sup<T>(
|
||||
ty::Contravariant,
|
||||
actual,
|
||||
self.cause.span,
|
||||
&mut |alias| {
|
||||
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
|
||||
},
|
||||
)
|
||||
.map(|goals| self.goals_to_obligations(goals))
|
||||
} else {
|
||||
@@ -173,6 +176,9 @@ pub fn sub<T>(
|
||||
ty::Covariant,
|
||||
actual,
|
||||
self.cause.span,
|
||||
&mut |alias| {
|
||||
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
|
||||
},
|
||||
)
|
||||
.map(|goals| self.goals_to_obligations(goals))
|
||||
} else {
|
||||
@@ -225,6 +231,9 @@ pub fn eq_trace<T>(
|
||||
ty::Invariant,
|
||||
actual,
|
||||
self.cause.span,
|
||||
&mut |alias| {
|
||||
self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias)
|
||||
},
|
||||
)
|
||||
.map(|goals| self.goals_to_obligations(goals))
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
use std::{fmt, mem};
|
||||
|
||||
pub use at::DefineOpaqueTypes;
|
||||
use free_regions::RegionRelations;
|
||||
@@ -21,6 +21,7 @@
|
||||
use rustc_macros::extension;
|
||||
pub use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hooks::TypeErasedInfcx;
|
||||
use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::select;
|
||||
@@ -1250,6 +1251,36 @@ pub fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
/// Normally, we shallow-resolve unresolved type variables to their root
|
||||
/// variables. This is mainly done for performance reasons, and in most
|
||||
/// cases resolving to the root variable (instead of the variable itself)
|
||||
/// does not affect type inference.
|
||||
///
|
||||
/// However, there is an exceptional case: *fudging*. Fudging is intended
|
||||
/// to guide inference rather than impose hard requirements. But our current
|
||||
/// handling here is somewhat janky.
|
||||
///
|
||||
/// In particular, inference variables that are considered equal within the
|
||||
/// fudging scope may not remain equal outside of it. This makes it observable
|
||||
/// which inference variable we resolve to. For backwards compatibility, we
|
||||
/// avoid resolving to the root variable by using this function inside the
|
||||
/// fudge instead of [`InferCtxt::resolve_vars_if_possible`].
|
||||
///
|
||||
/// See #153869 for more details.
|
||||
pub fn resolve_vars_if_possible_for_fudging<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
if let Err(guar) = value.error_reported() {
|
||||
self.set_tainted_by_errors(guar);
|
||||
}
|
||||
if !value.has_non_region_infer() {
|
||||
return value;
|
||||
}
|
||||
let mut r = resolve::OpportunisticVarResolver::new_for_fudging(self);
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
@@ -1498,6 +1529,17 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> boo
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_eagerly_normalize_alias<'a>(
|
||||
&'a self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
alias: ty::AliasTy<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let erased =
|
||||
unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) };
|
||||
self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias)
|
||||
}
|
||||
|
||||
/// Attach a callback to be invoked on each root obligation evaluated in the new trait solver.
|
||||
pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) {
|
||||
debug_assert!(
|
||||
|
||||
@@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
|
||||
/// other usecases (i.e. setting the value of a type var).
|
||||
#[instrument(level = "debug", skip(self, relation))]
|
||||
pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
|
||||
&self,
|
||||
relation: &mut R,
|
||||
target_is_expected: bool,
|
||||
@@ -61,29 +61,56 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
) -> RelateResult<'tcx, ()> {
|
||||
debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown());
|
||||
|
||||
// Generalize `source_ty` depending on the current variance. As an example, assume
|
||||
// `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
|
||||
// variable.
|
||||
//
|
||||
// Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
|
||||
// region/type inference variables.
|
||||
//
|
||||
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
|
||||
// `?1 <: ?3`.
|
||||
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
|
||||
relation.span(),
|
||||
relation.structurally_relate_aliases(),
|
||||
target_vid,
|
||||
instantiation_variance,
|
||||
source_ty,
|
||||
)?;
|
||||
let generalized_ty = if self.next_trait_solver()
|
||||
&& matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::No)
|
||||
&& let ty::Alias(_, alias) = source_ty.kind()
|
||||
{
|
||||
let normalized_alias = relation.try_eagerly_normalize_alias(*alias);
|
||||
|
||||
// Constrain `b_vid` to the generalized type `generalized_ty`.
|
||||
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
|
||||
self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
|
||||
if normalized_alias.is_ty_var() {
|
||||
normalized_alias
|
||||
} else {
|
||||
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
|
||||
relation.span(),
|
||||
GeneralizerState::ShallowStructurallyRelateAliases,
|
||||
target_vid,
|
||||
instantiation_variance,
|
||||
normalized_alias,
|
||||
&mut |alias| relation.try_eagerly_normalize_alias(alias),
|
||||
)?;
|
||||
|
||||
// The only way to get a tyvar back is if the outermost type is an alias.
|
||||
// However, here, though we know it *is* an alias, we initialize the generalizer
|
||||
// with `ShallowStructurallyRelateAliases` so we treat the outermost alias as rigid,
|
||||
// ensuring this is never a tyvar.
|
||||
assert!(!generalized_ty.is_ty_var());
|
||||
|
||||
generalized_ty
|
||||
}
|
||||
} else {
|
||||
self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
|
||||
}
|
||||
// Generalize `source_ty` depending on the current variance. As an example, assume
|
||||
// `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference
|
||||
// variable.
|
||||
//
|
||||
// Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh
|
||||
// region/type inference variables.
|
||||
//
|
||||
// We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and
|
||||
// `?1 <: ?3`.
|
||||
let Generalization { value_may_be_infer: generalized_ty } = self.generalize(
|
||||
relation.span(),
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::No => GeneralizerState::Default,
|
||||
StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
|
||||
},
|
||||
target_vid,
|
||||
instantiation_variance,
|
||||
source_ty,
|
||||
&mut |alias| relation.try_eagerly_normalize_alias(alias),
|
||||
)?;
|
||||
|
||||
generalized_ty
|
||||
};
|
||||
|
||||
// Finally, relate `generalized_ty` to `source_ty`, as described in previous comment.
|
||||
//
|
||||
@@ -91,7 +118,10 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
// relations wind up attributed to the same spans. We need
|
||||
// to associate causes/spans with each of the relations in
|
||||
// the stack to get this right.
|
||||
if generalized_ty.is_ty_var() {
|
||||
if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() {
|
||||
// Constrain `b_vid` to the generalized type variable.
|
||||
self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid);
|
||||
|
||||
// This happens for cases like `<?0 as Trait>::Assoc == ?0`.
|
||||
// We can't instantiate `?0` here as that would result in a
|
||||
// cyclic type. We instead delay the unification in case
|
||||
@@ -132,6 +162,9 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Constrain `b_vid` to the generalized type `generalized_ty`.
|
||||
self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty);
|
||||
|
||||
// NOTE: The `instantiation_variance` is not the same variance as
|
||||
// used by the relation. When instantiating `b`, `target_is_expected`
|
||||
// is flipped and the `instantiation_variance` is also flipped. To
|
||||
@@ -206,10 +239,14 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>
|
||||
// constants and generic expressions are not yet handled correctly.
|
||||
let Generalization { value_may_be_infer: generalized_ct } = self.generalize(
|
||||
relation.span(),
|
||||
relation.structurally_relate_aliases(),
|
||||
match relation.structurally_relate_aliases() {
|
||||
StructurallyRelateAliases::No => GeneralizerState::Default,
|
||||
StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases,
|
||||
},
|
||||
target_vid,
|
||||
ty::Invariant,
|
||||
source_ct,
|
||||
&mut |alias| relation.try_eagerly_normalize_alias(alias),
|
||||
)?;
|
||||
|
||||
debug_assert!(!generalized_ct.is_ct_infer());
|
||||
@@ -245,10 +282,11 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>
|
||||
fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
span: Span,
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
initial_state: GeneralizerState,
|
||||
target_vid: impl Into<TermVid>,
|
||||
ambient_variance: ty::Variance,
|
||||
source_term: T,
|
||||
normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
|
||||
) -> RelateResult<'tcx, Generalization<T>> {
|
||||
assert!(!source_term.has_escaping_bound_vars());
|
||||
let (for_universe, root_vid) = match target_vid.into() {
|
||||
@@ -264,13 +302,13 @@ fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
|
||||
let mut generalizer = Generalizer {
|
||||
infcx: self,
|
||||
span,
|
||||
structurally_relate_aliases,
|
||||
root_vid,
|
||||
for_universe,
|
||||
root_term: source_term.into(),
|
||||
ambient_variance,
|
||||
in_alias: false,
|
||||
state: initial_state,
|
||||
cache: Default::default(),
|
||||
normalize,
|
||||
};
|
||||
|
||||
let value_may_be_infer = generalizer.relate(source_term, source_term)?;
|
||||
@@ -317,6 +355,54 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
/// This state determines how generalization treats aliases.
|
||||
///
|
||||
/// Based on which state we're in, we treat them either as rigid or normalizable,
|
||||
/// which might change depending on what types the generalization visitor encounters.
|
||||
/// See `handle_alias_ty` for the logic of how we change states.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
enum GeneralizerState {
|
||||
/// Treat aliases as potentially normalizable.
|
||||
///
|
||||
/// This is the default state that generalization starts in, unless we're
|
||||
/// treating aliases as rigid. It also means we're not currently inside an
|
||||
/// alias, since then we change the state to `IncompletelyRelateAliasArgs`.
|
||||
Default,
|
||||
/// We enter this state when we're generalizing the arguments of a
|
||||
/// potentially normalizeable alias.
|
||||
///
|
||||
/// The behavior here is different between the old and the new solver:
|
||||
///
|
||||
/// In the old solver, the difference between this and `Default` is needed to
|
||||
/// correctly handle `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. That
|
||||
/// equality can hold by either normalizing the outer or the inner
|
||||
/// associated type. In the old solver, we always structurally relate
|
||||
/// aliases. If we we encounter an occurs check failure, we propagate the
|
||||
/// failure to the outermost alias, for which we then emit a `Projection`
|
||||
/// goal instead.
|
||||
///
|
||||
/// In the new solver, we rarely get into this state.
|
||||
/// When we encounter aliases we instead attempt to normalize them, and treat
|
||||
/// them as rigid using `ShallowStructurallyRelate`. Only when an alias has
|
||||
/// escaping bound variables do we continue with similar logic to the old
|
||||
/// solver, except now we also explicitly relate the type and consts in the
|
||||
/// arguments of aliases while in this mode.
|
||||
///
|
||||
/// FIXME: Because we relate the type and consts in the arguments of aliases
|
||||
/// while in this mode, this is incomplete.
|
||||
IncompletelyRelateAliasArgs,
|
||||
/// During generalization, when we encounter aliases, we will first attempt
|
||||
/// to normalize them when we're using the next trait solver. We can now
|
||||
/// treat the normalized alias as rigid, but only for "one layer", hence
|
||||
/// shallow. New aliases encountered inside the arguments of the outer alias
|
||||
/// should once again be related as normal.
|
||||
ShallowStructurallyRelateAliases,
|
||||
/// Treat aliases as rigid when relating them.
|
||||
///
|
||||
/// This corresponds to `relation.structurally_relate_aliases()`.
|
||||
StructurallyRelateAliases,
|
||||
}
|
||||
|
||||
/// The "generalizer" is used when handling inference variables.
|
||||
///
|
||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||
@@ -335,10 +421,6 @@ struct Generalizer<'me, 'tcx> {
|
||||
|
||||
span: Span,
|
||||
|
||||
/// Whether aliases should be related structurally. If not, we have to
|
||||
/// be careful when generalizing aliases.
|
||||
structurally_relate_aliases: StructurallyRelateAliases,
|
||||
|
||||
/// The vid of the type variable that is in the process of being
|
||||
/// instantiated. If we find this within the value we are folding,
|
||||
/// that means we would have created a cyclic value.
|
||||
@@ -356,14 +438,17 @@ struct Generalizer<'me, 'tcx> {
|
||||
/// some other type. What will be the variance at this point?
|
||||
ambient_variance: ty::Variance,
|
||||
|
||||
/// This is set once we're generalizing the arguments of an alias.
|
||||
/// This field keeps track of how we treat aliases during generalization.
|
||||
///
|
||||
/// This is necessary to correctly handle
|
||||
/// `<T as Bar<<?0 as Foo>::Assoc>::Assoc == ?0`. This equality can
|
||||
/// hold by either normalizing the outer or the inner associated type.
|
||||
in_alias: bool,
|
||||
/// Refer to [`GeneralizerState`]'s docs for more information about the
|
||||
/// all the possible values this can have, and when we use which.
|
||||
state: GeneralizerState,
|
||||
|
||||
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>,
|
||||
cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>,
|
||||
|
||||
/// Normalize an alias in the trait solver.
|
||||
/// If normalization fails, a fresh infer var is returned.
|
||||
normalize: &'me mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Generalizer<'_, 'tcx> {
|
||||
@@ -399,27 +484,51 @@ fn next_ty_var_for_alias(&self) -> Ty<'tcx> {
|
||||
/// continue generalizing the alias. This ends up pulling down the universe of the
|
||||
/// inference variable and is incomplete in case the alias would normalize to a type
|
||||
/// which does not mention that inference variable.
|
||||
fn generalize_alias_ty(
|
||||
fn handle_alias_ty(
|
||||
&mut self,
|
||||
alias_ty: Ty<'tcx>,
|
||||
alias: ty::AliasTy<'tcx>,
|
||||
) -> Result<Ty<'tcx>, TypeError<'tcx>> {
|
||||
// We do not eagerly replace aliases with inference variables if they have
|
||||
// escaping bound vars, see the method comment for details. However, when we
|
||||
// are inside of an alias with escaping bound vars replacing nested aliases
|
||||
// with inference variables can cause incorrect ambiguity.
|
||||
//
|
||||
// cc trait-system-refactor-initiative#110
|
||||
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
|
||||
return Ok(self.next_ty_var_for_alias());
|
||||
match self.state {
|
||||
GeneralizerState::ShallowStructurallyRelateAliases => {
|
||||
// We can switch back to default, we've treated one layer as rigid by doing this operation.
|
||||
self.state = GeneralizerState::Default;
|
||||
let res = relate::structurally_relate_tys(self, alias_ty, alias_ty);
|
||||
self.state = GeneralizerState::ShallowStructurallyRelateAliases;
|
||||
return res;
|
||||
}
|
||||
GeneralizerState::StructurallyRelateAliases => {
|
||||
return relate::structurally_relate_tys(self, alias_ty, alias_ty);
|
||||
}
|
||||
GeneralizerState::Default
|
||||
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() =>
|
||||
{
|
||||
// We do not eagerly replace aliases with inference variables if they have
|
||||
// escaping bound vars, see the method comment for details. However, when we
|
||||
// are inside of an alias with escaping bound vars replacing nested aliases
|
||||
// with inference variables can cause incorrect ambiguity.
|
||||
//
|
||||
// cc trait-system-refactor-initiative#110
|
||||
let normalized_alias = (self.normalize)(alias);
|
||||
|
||||
self.state = GeneralizerState::ShallowStructurallyRelateAliases;
|
||||
// recursively generalize, treat the outer alias as rigid to avoid infinite recursion
|
||||
let res = self.relate(normalized_alias, normalized_alias);
|
||||
|
||||
// only one way to get here
|
||||
self.state = GeneralizerState::Default;
|
||||
|
||||
return res;
|
||||
}
|
||||
GeneralizerState::Default | GeneralizerState::IncompletelyRelateAliasArgs => {}
|
||||
}
|
||||
|
||||
let is_nested_alias = mem::replace(&mut self.in_alias, true);
|
||||
let previous_state =
|
||||
mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateAliasArgs);
|
||||
let result = match self.relate(alias, alias) {
|
||||
Ok(alias) => Ok(alias.to_ty(self.cx())),
|
||||
Err(e) => {
|
||||
if is_nested_alias {
|
||||
return Err(e);
|
||||
} else {
|
||||
Err(e) => match previous_state {
|
||||
GeneralizerState::Default => {
|
||||
let mut visitor = MaxUniverse::new();
|
||||
alias.visit_with(&mut visitor);
|
||||
let infer_replacement_is_complete =
|
||||
@@ -432,9 +541,14 @@ fn generalize_alias_ty(
|
||||
debug!("generalization failure in alias");
|
||||
Ok(self.next_ty_var_for_alias())
|
||||
}
|
||||
}
|
||||
GeneralizerState::IncompletelyRelateAliasArgs => return Err(e),
|
||||
|
||||
// Early return.
|
||||
GeneralizerState::ShallowStructurallyRelateAliases
|
||||
| GeneralizerState::StructurallyRelateAliases => unreachable!(),
|
||||
},
|
||||
};
|
||||
self.in_alias = is_nested_alias;
|
||||
self.state = previous_state;
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -488,7 +602,7 @@ fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
|
||||
|
||||
if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) {
|
||||
if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.state)) {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
@@ -536,6 +650,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
// of each other. This is currently only used for diagnostics.
|
||||
// To see why, see the docs in the `type_variables` module.
|
||||
inner.type_variables().sub_unify(vid, new_var_id);
|
||||
|
||||
// If we're in the new solver and create a new inference
|
||||
// variable inside of an alias we eagerly constrain that
|
||||
// inference variable to prevent unexpected ambiguity errors.
|
||||
@@ -553,9 +668,15 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
// cc trait-system-refactor-initiative#108
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& self.in_alias
|
||||
{
|
||||
inner.type_variables().equate(vid, new_var_id);
|
||||
match self.state {
|
||||
GeneralizerState::IncompletelyRelateAliasArgs => {
|
||||
inner.type_variables().equate(vid, new_var_id);
|
||||
}
|
||||
GeneralizerState::Default
|
||||
| GeneralizerState::ShallowStructurallyRelateAliases
|
||||
| GeneralizerState::StructurallyRelateAliases => {}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("replacing original vid={:?} with new={:?}", vid, new_var_id);
|
||||
@@ -584,15 +705,12 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
ty::Alias(_, data) => match self.structurally_relate_aliases {
|
||||
StructurallyRelateAliases::No => self.generalize_alias_ty(data),
|
||||
StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t),
|
||||
},
|
||||
ty::Alias(_, data) => self.handle_alias_ty(t, data),
|
||||
|
||||
_ => relate::structurally_relate_tys(self, t, t),
|
||||
}?;
|
||||
|
||||
self.cache.insert((t, self.ambient_variance, self.in_alias), g);
|
||||
self.cache.insert((t, self.ambient_variance, self.state), g);
|
||||
Ok(g)
|
||||
}
|
||||
|
||||
@@ -683,9 +801,15 @@ fn consts(
|
||||
// for more details.
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& self.in_alias
|
||||
{
|
||||
variable_table.union(vid, new_var_id);
|
||||
match self.state {
|
||||
GeneralizerState::IncompletelyRelateAliasArgs => {
|
||||
variable_table.union(vid, new_var_id);
|
||||
}
|
||||
GeneralizerState::Default
|
||||
| GeneralizerState::ShallowStructurallyRelateAliases
|
||||
| GeneralizerState::StructurallyRelateAliases => {}
|
||||
}
|
||||
}
|
||||
Ok(ty::Const::new_var(self.cx(), new_var_id))
|
||||
}
|
||||
|
||||
@@ -299,4 +299,8 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
ty::AliasRelationDirection::Equate,
|
||||
))]);
|
||||
}
|
||||
|
||||
fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> {
|
||||
self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,4 +396,13 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
|
||||
}
|
||||
})]);
|
||||
}
|
||||
|
||||
fn try_eagerly_normalize_alias(
|
||||
&mut self,
|
||||
_alias: rustc_type_ir::AliasTy<<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner>,
|
||||
) -> <<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner as rustc_type_ir::Interner>::Ty
|
||||
{
|
||||
// We only try to eagerly normalize aliases if we're using the new solver.
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
/// points for correctness.
|
||||
pub struct OpportunisticVarResolver<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
/// If true, we don't resolve ty/const vars to their roots.
|
||||
/// See comments on [`InferCtxt::resolve_vars_if_possible_for_fudging`]
|
||||
for_fudging: bool,
|
||||
/// We're able to use a cache here as the folder does
|
||||
/// not have any mutable state.
|
||||
cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
@@ -25,7 +28,12 @@ pub struct OpportunisticVarResolver<'a, 'tcx> {
|
||||
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
|
||||
#[inline]
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
OpportunisticVarResolver { infcx, cache: Default::default() }
|
||||
OpportunisticVarResolver { infcx, for_fudging: false, cache: Default::default() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_for_fudging(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
OpportunisticVarResolver { infcx, for_fudging: true, cache: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +51,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
} else {
|
||||
let shallow = self.infcx.shallow_resolve(t);
|
||||
let res = shallow.super_fold_with(self);
|
||||
let res = if self.for_fudging && res.is_ty_var() { t } else { res };
|
||||
assert!(self.cache.insert(t, res));
|
||||
res
|
||||
}
|
||||
@@ -52,8 +61,11 @@ fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
|
||||
if !ct.has_non_region_infer() {
|
||||
ct // micro-optimize -- if there is nothing in this const that this fold affects...
|
||||
} else {
|
||||
let ct = self.infcx.shallow_resolve_const(ct);
|
||||
ct.super_fold_with(self)
|
||||
let res = self.infcx.shallow_resolve_const(ct);
|
||||
if self.for_fudging && res.is_ct_infer() {
|
||||
return ct;
|
||||
};
|
||||
res.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
|
||||
// going to be popped, so we will have to
|
||||
// eliminate any references to them.
|
||||
let snapshot_vars = SnapshotVarData::new(self, variable_lengths);
|
||||
Ok((snapshot_vars, self.resolve_vars_if_possible(value)))
|
||||
Ok((snapshot_vars, self.resolve_vars_if_possible_for_fudging(value)))
|
||||
})?;
|
||||
|
||||
// At this point, we need to replace any of the now-popped
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{Attribute, find_attr};
|
||||
use rustc_hir::{Attribute, MaybeOwner, find_attr};
|
||||
use rustc_incremental::setup_dep_graph;
|
||||
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
@@ -878,6 +878,10 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
let providers = &mut Providers::default();
|
||||
providers.queries.analysis = analysis;
|
||||
providers.queries.hir_crate = rustc_ast_lowering::lower_to_hir;
|
||||
providers.queries.lower_delayed_owner = rustc_ast_lowering::lower_delayed_owner;
|
||||
// `delayed_owner` is fed during `lower_delayed_owner`, by default it returns phantom,
|
||||
// as if this query was not fed it means that `MaybeOwner` does not exist for provided LocalDefId.
|
||||
providers.queries.delayed_owner = |_, _| MaybeOwner::Phantom;
|
||||
providers.queries.resolver_for_lowering_raw = resolver_for_lowering_raw;
|
||||
providers.queries.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
|
||||
providers.queries.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
|
||||
@@ -900,7 +904,7 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
|
||||
rustc_hir_typeck::provide(&mut providers.queries);
|
||||
ty::provide(&mut providers.queries);
|
||||
traits::provide(&mut providers.queries);
|
||||
solve::provide(&mut providers.queries);
|
||||
solve::provide(providers);
|
||||
rustc_passes::provide(&mut providers.queries);
|
||||
rustc_traits::provide(&mut providers.queries);
|
||||
rustc_ty_utils::provide(&mut providers.queries);
|
||||
|
||||
@@ -637,7 +637,6 @@ macro_rules! tracked {
|
||||
tracked!(profile_use, Some(PathBuf::from("abc")));
|
||||
tracked!(relocation_model, Some(RelocModel::Pic));
|
||||
tracked!(relro_level, Some(RelroLevel::Full));
|
||||
tracked!(soft_float, true);
|
||||
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
|
||||
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
|
||||
tracked!(target_cpu, Some(String::from("abc")));
|
||||
|
||||
@@ -183,7 +183,6 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
||||
use std::process;
|
||||
|
||||
use rustc_data_structures::defer;
|
||||
use rustc_data_structures::sync::FromDyn;
|
||||
use rustc_middle::ty::tls;
|
||||
use rustc_query_impl::break_query_cycles;
|
||||
|
||||
@@ -191,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
||||
|
||||
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||
|
||||
if !sync::is_dyn_thread_safe() {
|
||||
let Some(proof) = sync::check_dyn_thread_safe() else {
|
||||
return run_in_thread_with_globals(
|
||||
thread_stack_size,
|
||||
edition,
|
||||
@@ -204,9 +203,9 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
||||
f(current_gcx, jobserver_proxy)
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let current_gcx = FromDyn::from(CurrentGcx::new());
|
||||
let current_gcx = proof.derive(CurrentGcx::new());
|
||||
let current_gcx2 = current_gcx.clone();
|
||||
|
||||
let proxy = Proxy::new();
|
||||
@@ -278,7 +277,7 @@ pub(crate) fn run_in_thread_pool_with_globals<
|
||||
// `Send` in the parallel compiler.
|
||||
rustc_span::create_session_globals_then(edition, extra_symbols, Some(sm_inputs), || {
|
||||
rustc_span::with_session_globals(|session_globals| {
|
||||
let session_globals = FromDyn::from(session_globals);
|
||||
let session_globals = proof.derive(session_globals);
|
||||
builder
|
||||
.build_scoped(
|
||||
// Initialize each new worker thread when created.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
|
||||
elided_lifetime_in_path_suggestion,
|
||||
@@ -10,7 +9,6 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_span::BytePos;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::lints;
|
||||
@@ -28,32 +26,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> {
|
||||
impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
match self.diagnostic {
|
||||
BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
|
||||
let spans: Vec<_> = content
|
||||
.char_indices()
|
||||
.filter_map(|(i, c)| {
|
||||
TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
|
||||
let lo = comment_span.lo() + BytePos(2 + i as u32);
|
||||
(c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let characters = spans
|
||||
.iter()
|
||||
.map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
|
||||
.collect();
|
||||
let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
|
||||
spans: spans.iter().map(|(_c, span)| *span).collect(),
|
||||
});
|
||||
|
||||
lints::UnicodeTextFlow {
|
||||
comment_span,
|
||||
characters,
|
||||
suggestions,
|
||||
num_codepoints: spans.len(),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::AbsPathWithModule(mod_span) => {
|
||||
let (replacement, applicability) =
|
||||
match self.sess.source_map().span_to_snippet(mod_span) {
|
||||
@@ -153,30 +125,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix {
|
||||
label: label_span,
|
||||
suggestion: label_span.shrink_to_hi(),
|
||||
prefix,
|
||||
}
|
||||
.into_diag(dcx, level),
|
||||
BuiltinLintDiag::RawPrefix(label_span) => {
|
||||
lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::ReservedString { is_string, suggestion } => {
|
||||
if is_string {
|
||||
lints::ReservedString { suggestion }.into_diag(dcx, level)
|
||||
} else {
|
||||
lints::ReservedMultihash { suggestion }.into_diag(dcx, level)
|
||||
}
|
||||
}
|
||||
BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => lints::BreakWithLabelAndLoop {
|
||||
sub: lints::BreakWithLabelAndLoopSub {
|
||||
left: sugg_span.shrink_to_lo(),
|
||||
right: sugg_span.shrink_to_hi(),
|
||||
},
|
||||
}
|
||||
.into_diag(dcx, level),
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
|
||||
let suggestion = match sugg {
|
||||
Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
|
||||
@@ -498,6 +446,18 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
&AttributeLintKind::MissingOptionsForOnConst => {
|
||||
lints::MissingOptionsForOnConstAttr.into_diag(dcx, level)
|
||||
}
|
||||
&AttributeLintKind::MalformedOnMoveAttr { span } => {
|
||||
lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level)
|
||||
}
|
||||
&AttributeLintKind::OnMoveMalformedFormatLiterals { name } => {
|
||||
lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level)
|
||||
}
|
||||
&AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => {
|
||||
lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level)
|
||||
}
|
||||
&AttributeLintKind::MissingOptionsForOnMove => {
|
||||
lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some((pat, arg)) = extract_for_loop(expr) else { return };
|
||||
|
||||
// Do not put suggestions for external macros.
|
||||
if pat.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
let arg_span = arg.span.source_callsite();
|
||||
|
||||
let ty = cx.typeck_results().expr_ty(arg);
|
||||
@@ -77,6 +82,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
};
|
||||
|
||||
let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
|
||||
&& recv.span.can_be_used_for_suggestions()
|
||||
&& recv.span.between(arg_span.shrink_to_hi()).can_be_used_for_suggestions()
|
||||
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
||||
{
|
||||
ForLoopsOverFalliblesLoopSub::RemoveNext {
|
||||
|
||||
@@ -3019,46 +3019,6 @@ pub(crate) struct IllFormedAttributeInput {
|
||||
pub docs: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unicode codepoint changing visible direction of text present in comment")]
|
||||
#[note(
|
||||
"these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
|
||||
)]
|
||||
pub(crate) struct UnicodeTextFlow {
|
||||
#[label(
|
||||
"{$num_codepoints ->
|
||||
[1] this comment contains an invisible unicode text flow control codepoint
|
||||
*[other] this comment contains invisible unicode text flow control codepoints
|
||||
}"
|
||||
)]
|
||||
pub comment_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub characters: Vec<UnicodeCharNoteSub>,
|
||||
#[subdiagnostic]
|
||||
pub suggestions: Option<UnicodeTextFlowSuggestion>,
|
||||
|
||||
pub num_codepoints: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label("{$c_debug}")]
|
||||
pub(crate) struct UnicodeCharNoteSub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub c_debug: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"if their presence wasn't intentional, you can remove them",
|
||||
applicability = "machine-applicable",
|
||||
style = "hidden"
|
||||
)]
|
||||
pub(crate) struct UnicodeTextFlowSuggestion {
|
||||
#[suggestion_part(code = "")]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition"
|
||||
@@ -3192,52 +3152,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub {
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("prefix `{$prefix}` is unknown")]
|
||||
pub(crate) struct ReservedPrefix {
|
||||
#[label("unknown prefix")]
|
||||
pub label: Span,
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("prefix `'r` is reserved")]
|
||||
pub(crate) struct RawPrefix {
|
||||
#[label("reserved prefix")]
|
||||
pub label: Span,
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression"
|
||||
)]
|
||||
pub(crate) struct BreakWithLabelAndLoop {
|
||||
#[subdiagnostic]
|
||||
pub sub: BreakWithLabelAndLoopSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")]
|
||||
pub(crate) struct BreakWithLabelAndLoopSub {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("where clause not allowed here")]
|
||||
#[note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information")]
|
||||
@@ -3423,28 +3337,6 @@ pub(crate) enum MutRefSugg {
|
||||
#[diag("`use` of a local item without leading `self::`, `super::`, or `crate::`")]
|
||||
pub(crate) struct UnqualifiedLocalImportsDiag;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("will be parsed as a guarded string in Rust 2024")]
|
||||
pub(crate) struct ReservedString {
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("reserved token in Rust 2024")]
|
||||
pub(crate) struct ReservedMultihash {
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("direct cast of function item into an integer")]
|
||||
pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> {
|
||||
@@ -3953,6 +3845,11 @@ pub(crate) struct IgnoredDiagnosticOption {
|
||||
#[help("at least one of the `message`, `note` and `label` options are expected")]
|
||||
pub(crate) struct MissingOptionsForOnConstAttr;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing options for `on_move` attribute")]
|
||||
#[help("at least one of the `message`, `note` and `label` options are expected")]
|
||||
pub(crate) struct MissingOptionsForOnMoveAttr;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("malformed `on_unimplemented` attribute")]
|
||||
#[help("only `message`, `note` and `label` are allowed as options")]
|
||||
@@ -3973,3 +3870,27 @@ pub(crate) struct MalformedOnConstAttrLint {
|
||||
#[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")]
|
||||
#[note("this method was used to add checks to the `Eq` derive macro")]
|
||||
pub(crate) struct EqInternalMethodImplemented;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown or malformed `on_move` attribute")]
|
||||
#[help(
|
||||
"only `message`, `note` and `label` are allowed as options. Their values must be string literals"
|
||||
)]
|
||||
pub(crate) struct MalformedOnMoveAttrLint {
|
||||
#[label("invalid option found here")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown parameter `{$name}`")]
|
||||
#[help("expect `Self` as format argument")]
|
||||
pub(crate) struct OnMoveMalformedFormatLiterals {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected a literal or missing delimiter")]
|
||||
#[help(
|
||||
"only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma"
|
||||
)]
|
||||
pub(crate) struct OnMoveMalformedAttrExpectedLiteralOrDelimiter;
|
||||
|
||||
@@ -678,16 +678,7 @@ pub enum BuiltinLintDiag {
|
||||
ident: Ident,
|
||||
is_foreign: bool,
|
||||
},
|
||||
ReservedPrefix(Span, String),
|
||||
/// `'r#` in edition < 2021.
|
||||
RawPrefix(Span),
|
||||
/// `##` or `#"` in edition < 2024.
|
||||
ReservedString {
|
||||
is_string: bool,
|
||||
suggestion: Span,
|
||||
},
|
||||
BreakWithLabelAndLoop(Span),
|
||||
UnicodeTextFlow(Span, String),
|
||||
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
|
||||
SingleUseLifetime {
|
||||
/// Span of the parameter which declares this lifetime.
|
||||
@@ -840,6 +831,9 @@ pub enum AttributeLintKind {
|
||||
MalformedOnConstAttr {
|
||||
span: Span,
|
||||
},
|
||||
MalformedOnMoveAttr {
|
||||
span: Span,
|
||||
},
|
||||
MalformedDiagnosticFormat {
|
||||
warning: FormatWarning,
|
||||
},
|
||||
@@ -855,6 +849,11 @@ pub enum AttributeLintKind {
|
||||
},
|
||||
MissingOptionsForOnUnimplemented,
|
||||
MissingOptionsForOnConst,
|
||||
MissingOptionsForOnMove,
|
||||
OnMoveMalformedFormatLiterals {
|
||||
name: Symbol,
|
||||
},
|
||||
OnMoveMalformedAttrExpectedLiteralOrDelimiter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, HashStable_Generic)]
|
||||
|
||||
@@ -140,13 +140,13 @@ struct CacheOnDiskIf {
|
||||
/// See `rustc_middle::query::modifiers` for documentation of each query modifier.
|
||||
struct QueryModifiers {
|
||||
// tidy-alphabetical-start
|
||||
anon: Option<Ident>,
|
||||
arena_cache: Option<Ident>,
|
||||
cache_on_disk_if: Option<CacheOnDiskIf>,
|
||||
depth_limit: Option<Ident>,
|
||||
desc: Desc,
|
||||
eval_always: Option<Ident>,
|
||||
feedable: Option<Ident>,
|
||||
no_force: Option<Ident>,
|
||||
no_hash: Option<Ident>,
|
||||
separate_provide_extern: Option<Ident>,
|
||||
// tidy-alphabetical-end
|
||||
@@ -156,8 +156,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
let mut arena_cache = None;
|
||||
let mut cache_on_disk_if = None;
|
||||
let mut desc = None;
|
||||
let mut no_force = None;
|
||||
let mut no_hash = None;
|
||||
let mut anon = None;
|
||||
let mut eval_always = None;
|
||||
let mut depth_limit = None;
|
||||
let mut separate_provide_extern = None;
|
||||
@@ -189,10 +189,10 @@ macro_rules! try_insert {
|
||||
try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block });
|
||||
} else if modifier == "arena_cache" {
|
||||
try_insert!(arena_cache = modifier);
|
||||
} else if modifier == "no_force" {
|
||||
try_insert!(no_force = modifier);
|
||||
} else if modifier == "no_hash" {
|
||||
try_insert!(no_hash = modifier);
|
||||
} else if modifier == "anon" {
|
||||
try_insert!(anon = modifier);
|
||||
} else if modifier == "eval_always" {
|
||||
try_insert!(eval_always = modifier);
|
||||
} else if modifier == "depth_limit" {
|
||||
@@ -212,8 +212,8 @@ macro_rules! try_insert {
|
||||
arena_cache,
|
||||
cache_on_disk_if,
|
||||
desc,
|
||||
no_force,
|
||||
no_hash,
|
||||
anon,
|
||||
eval_always,
|
||||
depth_limit,
|
||||
separate_provide_extern,
|
||||
@@ -243,24 +243,24 @@ fn returns_error_guaranteed(ret_ty: &ReturnType) -> bool {
|
||||
fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
|
||||
let QueryModifiers {
|
||||
// tidy-alphabetical-start
|
||||
anon,
|
||||
arena_cache,
|
||||
cache_on_disk_if,
|
||||
depth_limit,
|
||||
desc: _,
|
||||
eval_always,
|
||||
feedable,
|
||||
no_force,
|
||||
no_hash,
|
||||
separate_provide_extern,
|
||||
// tidy-alphabetical-end
|
||||
} = &query.modifiers;
|
||||
|
||||
let anon = anon.is_some();
|
||||
let arena_cache = arena_cache.is_some();
|
||||
let cache_on_disk = cache_on_disk_if.is_some();
|
||||
let depth_limit = depth_limit.is_some();
|
||||
let eval_always = eval_always.is_some();
|
||||
let feedable = feedable.is_some();
|
||||
let no_force = no_force.is_some();
|
||||
let no_hash = no_hash.is_some();
|
||||
let returns_error_guaranteed = returns_error_guaranteed(&query.return_ty);
|
||||
let separate_provide_extern = separate_provide_extern.is_some();
|
||||
@@ -273,12 +273,12 @@ fn make_modifiers_stream(query: &Query) -> proc_macro2::TokenStream {
|
||||
query_name_span =>
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
// tidy-alphabetical-start
|
||||
anon: #anon,
|
||||
arena_cache: #arena_cache,
|
||||
cache_on_disk: #cache_on_disk,
|
||||
depth_limit: #depth_limit,
|
||||
eval_always: #eval_always,
|
||||
feedable: #feedable,
|
||||
no_force: #no_force,
|
||||
no_hash: #no_hash,
|
||||
returns_error_guaranteed: #returns_error_guaranteed,
|
||||
separate_provide_extern: #separate_provide_extern,
|
||||
@@ -387,13 +387,15 @@ macro_rules! doc_link {
|
||||
}
|
||||
|
||||
doc_link!(
|
||||
// tidy-alphabetical-start
|
||||
arena_cache,
|
||||
no_hash,
|
||||
anon,
|
||||
eval_always,
|
||||
depth_limit,
|
||||
separate_provide_extern,
|
||||
eval_always,
|
||||
feedable,
|
||||
no_force,
|
||||
no_hash,
|
||||
separate_provide_extern,
|
||||
// tidy-alphabetical-end
|
||||
);
|
||||
|
||||
let name = &query.name;
|
||||
@@ -476,11 +478,6 @@ fn #name(#key_ty) #return_ty
|
||||
});
|
||||
|
||||
if let Some(feedable) = &modifiers.feedable {
|
||||
assert!(
|
||||
modifiers.anon.is_none(),
|
||||
feedable.span(),
|
||||
"Query {name} cannot be both `feedable` and `anon`."
|
||||
);
|
||||
assert!(
|
||||
modifiers.eval_always.is_none(),
|
||||
feedable.span(),
|
||||
|
||||
@@ -94,10 +94,14 @@ pub const fn as_usize(&self) -> usize {
|
||||
pub struct DepNode {
|
||||
pub kind: DepKind,
|
||||
|
||||
/// This is _typically_ a hash of the query key, but sometimes not.
|
||||
/// If `kind` is a query method, then its "key fingerprint" is always a
|
||||
/// stable hash of the query key.
|
||||
///
|
||||
/// For example, `anon` nodes have a fingerprint that is derived from their
|
||||
/// dependencies instead of a key.
|
||||
/// For non-query nodes, the content of this field varies:
|
||||
/// - Some dep kinds always use a dummy `ZERO` fingerprint.
|
||||
/// - Some dep kinds use the stable hash of some relevant key-like value.
|
||||
/// - Some dep kinds use the `with_anon_task` mechanism, and set their key
|
||||
/// fingerprint to a hash derived from the task's dependencies.
|
||||
///
|
||||
/// In some cases the key value can be reconstructed from this fingerprint;
|
||||
/// see [`KeyFingerprintStyle`].
|
||||
|
||||
@@ -375,9 +375,8 @@ pub fn with_task<'tcx, A: Debug, R>(
|
||||
/// incorrectly marked green.
|
||||
///
|
||||
/// FIXME: This could perhaps return a `WithDepNode` to ensure that the
|
||||
/// user of this function actually performs the read; we'll have to see
|
||||
/// how to make that work with `anon` in `execute_job_incr`, though.
|
||||
pub fn with_anon_task_inner<'tcx, OP, R>(
|
||||
/// user of this function actually performs the read.
|
||||
fn with_anon_task_inner<'tcx, OP, R>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dep_kind: DepKind,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
|
||||
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, spawn, try_par_for_each_in};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
||||
@@ -1245,7 +1245,25 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
|
||||
}
|
||||
}
|
||||
|
||||
fn force_delayed_owners_lowering(tcx: TyCtxt<'_>) {
|
||||
let krate = tcx.hir_crate(());
|
||||
for &id in &krate.delayed_ids {
|
||||
tcx.ensure_done().lower_delayed_owner(id);
|
||||
}
|
||||
|
||||
let (_, krate) = krate.delayed_resolver.steal();
|
||||
let prof = tcx.sess.prof.clone();
|
||||
|
||||
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
|
||||
spawn(move || {
|
||||
let _timer = prof.verbose_generic_activity("drop_ast");
|
||||
drop(krate);
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
|
||||
force_delayed_owners_lowering(tcx);
|
||||
|
||||
let mut collector = ItemCollector::new(tcx, true);
|
||||
|
||||
// A "crate collector" and "module collector" start at a
|
||||
|
||||
@@ -6,19 +6,83 @@
|
||||
pub mod nested_filter;
|
||||
pub mod place;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::*;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_span::{ErrorGuaranteed, ExpnId, Span};
|
||||
|
||||
use crate::query::Providers;
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::{ResolverAstLowering, TyCtxt};
|
||||
|
||||
/// The top-level data structure that stores the entire contents of
|
||||
/// the crate currently being compiled.
|
||||
///
|
||||
/// For more details, see the [rustc dev guide].
|
||||
///
|
||||
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
|
||||
#[derive(Debug)]
|
||||
pub struct Crate<'hir> {
|
||||
// This field is private by intention, access it through `owner` method.
|
||||
owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
|
||||
// Ids of delayed AST owners which are lowered through `lower_delayed_owner` query.
|
||||
pub delayed_ids: FxIndexSet<LocalDefId>,
|
||||
// The resolver and AST crate which are set in the end of the `hir_crate` query
|
||||
// and then stolen and dropped in `force_delayed_owners_lowering`.
|
||||
pub delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
|
||||
// Only present when incr. comp. is enabled.
|
||||
pub opt_hir_hash: Option<Fingerprint>,
|
||||
}
|
||||
|
||||
impl<'hir> Crate<'hir> {
|
||||
pub fn new(
|
||||
owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
|
||||
delayed_ids: FxIndexSet<LocalDefId>,
|
||||
delayed_resolver: Steal<(ResolverAstLowering<'hir>, Arc<ast::Crate>)>,
|
||||
opt_hir_hash: Option<Fingerprint>,
|
||||
) -> Crate<'hir> {
|
||||
Crate { owners, delayed_ids, delayed_resolver, opt_hir_hash }
|
||||
}
|
||||
|
||||
/// Serves as an entry point for getting `MaybeOwner`. As owner can either be in
|
||||
/// `owners` of `hir_crate` or it can be delayed AST owner (i.e., delegations)
|
||||
/// we need to firstly check in `hir_crate` and then delayed AST owners.
|
||||
/// This method can be invoked when not all delayed AST owners are lowered.
|
||||
pub fn owner(&self, tcx: TyCtxt<'hir>, def_id: LocalDefId) -> MaybeOwner<'hir> {
|
||||
// Delayed LocalDefId can be in `self.owners` if there exists non-delayed LocalDefId
|
||||
// which is greater than delayed LocalDefId, we use IndexVec for owners,
|
||||
// so we will call ensure_contains_elem which will grow it.
|
||||
if let Some(owner) = self.owners.get(def_id)
|
||||
&& (self.delayed_ids.is_empty() || !matches!(owner, MaybeOwner::Phantom))
|
||||
{
|
||||
return *owner;
|
||||
}
|
||||
|
||||
if self.delayed_ids.contains(&def_id) {
|
||||
tcx.ensure_done().lower_delayed_owner(def_id);
|
||||
}
|
||||
|
||||
tcx.delayed_owner(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: HashStableContext> HashStable<HirCtx> for Crate<'_> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let Crate { opt_hir_hash, .. } = self;
|
||||
opt_hir_hash.unwrap().hash_stable(hcx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gather the LocalDefId for each item-like within a module, including items contained within
|
||||
/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
|
||||
@@ -372,7 +436,9 @@ fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId {
|
||||
let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner;
|
||||
HirId {
|
||||
owner: parent_owner_id,
|
||||
local_id: self.hir_crate(()).owners[parent_owner_id.def_id]
|
||||
local_id: self
|
||||
.hir_crate(())
|
||||
.owner(self, parent_owner_id.def_id)
|
||||
.unwrap()
|
||||
.parenting
|
||||
.get(&owner_id.def_id)
|
||||
@@ -406,19 +472,19 @@ pub fn provide(providers: &mut Providers) {
|
||||
providers.hir_crate_items = map::hir_crate_items;
|
||||
providers.crate_hash = map::crate_hash;
|
||||
providers.hir_module_items = map::hir_module_items;
|
||||
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owners[def_id] {
|
||||
providers.local_def_id_to_hir_id = |tcx, def_id| match tcx.hir_crate(()).owner(tcx, def_id) {
|
||||
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
|
||||
MaybeOwner::NonOwner(hir_id) => hir_id,
|
||||
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
|
||||
};
|
||||
providers.opt_hir_owner_nodes =
|
||||
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
|
||||
|tcx, id| tcx.hir_crate(()).owner(tcx, id).as_owner().map(|i| &i.nodes);
|
||||
providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
|
||||
providers.hir_attr_map = |tcx, id| {
|
||||
tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
|
||||
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
|
||||
};
|
||||
providers.opt_ast_lowering_delayed_lints =
|
||||
|tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
|
||||
|tcx, id| tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|o| &o.delayed_lints);
|
||||
providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
|
||||
providers.def_ident_span = |tcx, def_id| {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
@@ -459,6 +525,6 @@ pub fn provide(providers: &mut Providers) {
|
||||
providers.expn_that_defined =
|
||||
|tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root());
|
||||
providers.in_scope_traits_map = |tcx, id| {
|
||||
tcx.hir_crate(()).owners[id.def_id].as_owner().map(|owner_info| &owner_info.trait_map)
|
||||
tcx.hir_crate(()).owner(tcx, id.def_id).as_owner().map(|owner_info| &owner_info.trait_map)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,14 +3,16 @@
|
||||
//! similar to queries, but queries come with a lot of machinery for caching and incremental
|
||||
//! compilation, whereas hooks are just plain function pointers without any of the query magic.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_hir::def_id::{DefId, DefPathHash};
|
||||
use rustc_session::StableCrateId;
|
||||
use rustc_span::def_id::{CrateNum, LocalDefId};
|
||||
use rustc_span::{ExpnHash, ExpnId};
|
||||
use rustc_span::{ExpnHash, ExpnId, Span};
|
||||
|
||||
use crate::mir;
|
||||
use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex};
|
||||
use crate::ty::{Ty, TyCtxt};
|
||||
use crate::{mir, ty};
|
||||
|
||||
macro_rules! declare_hooks {
|
||||
($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
|
||||
@@ -35,8 +37,10 @@ pub struct Providers {
|
||||
|
||||
impl Default for Providers {
|
||||
fn default() -> Self {
|
||||
#[allow(unused)]
|
||||
Providers {
|
||||
$($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),*
|
||||
$($name:
|
||||
|_, $($arg,)*| default_hook(stringify!($name))),*
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,11 +117,32 @@ fn clone(&self) -> Self { *self }
|
||||
encoder: &mut CacheEncoder<'_, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex
|
||||
) -> ();
|
||||
|
||||
/// Tries to normalize an alias, ignoring any errors.
|
||||
///
|
||||
/// Generalization with the new trait solver calls into this,
|
||||
/// when generalizing outside of the trait solver in `hir_typeck`.
|
||||
hook try_eagerly_normalize_alias(
|
||||
type_erased_infcx: TypeErasedInfcx<'_, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
span: Span,
|
||||
alias: ty::AliasTy<'tcx>
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
/// The `try_eagerly_normalize_alias` hook passes an `Infcx` from where it's called (in `rustc_infer`)
|
||||
/// to where it's provided (in `rustc_trait_selection`).
|
||||
/// Both of those crates have that type available, but `rustc_middle` does not.
|
||||
/// Instead we pass this type-erased `Infcx` and transmute on both sides.
|
||||
///
|
||||
/// Has to be `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct.
|
||||
#[repr(transparent)]
|
||||
pub struct TypeErasedInfcx<'a, 'tcx> {
|
||||
_infcx: *const (),
|
||||
phantom: PhantomData<&'a mut &'tcx ()>,
|
||||
}
|
||||
|
||||
#[cold]
|
||||
fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! {
|
||||
bug!(
|
||||
"`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function"
|
||||
)
|
||||
fn default_hook(name: &str) -> ! {
|
||||
bug!("`tcx.{name}` cannot be called as `{name}` was never assigned to a provider function")
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId,
|
||||
};
|
||||
use rustc_hir::lang_items::{LangItem, LanguageItems};
|
||||
use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
|
||||
use rustc_hir::{ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_lint_defs::LintId;
|
||||
use rustc_macros::rustc_queries;
|
||||
@@ -82,6 +82,7 @@
|
||||
use rustc_span::{DUMMY_SP, LocalExpnId, Span, Spanned, Symbol};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
use crate::hir::Crate;
|
||||
use crate::infer::canonical::{self, Canonical};
|
||||
use crate::lint::LintExpectation;
|
||||
use crate::metadata::ModChild;
|
||||
@@ -101,7 +102,7 @@
|
||||
CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions, NormalizationErrorInMono,
|
||||
};
|
||||
use crate::query::describe_as_module;
|
||||
use crate::query::plumbing::{define_callbacks, query_helper_param_ty};
|
||||
use crate::query::plumbing::{define_callbacks, maybe_into_query_key};
|
||||
use crate::traits::query::{
|
||||
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
|
||||
CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
@@ -210,6 +211,16 @@
|
||||
desc { "getting the crate HIR" }
|
||||
}
|
||||
|
||||
query lower_delayed_owner(def_id: LocalDefId) {
|
||||
eval_always
|
||||
desc { "lowering the delayed AST owner `{}`", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
||||
query delayed_owner(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> {
|
||||
feedable
|
||||
desc { "getting child of lowered delayed AST owner `{}`", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
||||
/// All items in the crate.
|
||||
query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
|
||||
arena_cache
|
||||
@@ -574,16 +585,15 @@
|
||||
desc { "checking if `{}` is representable", tcx.def_path_str(key) }
|
||||
// We don't want recursive representability calls to be forced with
|
||||
// incremental compilation because, if a cycle occurs, we need the
|
||||
// entire cycle to be in memory for diagnostics. This means we can't
|
||||
// use `ensure_ok()` with this query.
|
||||
anon
|
||||
// entire cycle to be in memory for diagnostics.
|
||||
no_force
|
||||
}
|
||||
|
||||
/// An implementation detail for the `check_representability` query. See that query for more
|
||||
/// details, particularly on the modifiers.
|
||||
query check_representability_adt_ty(key: Ty<'tcx>) {
|
||||
desc { "checking if `{}` is representable", key }
|
||||
anon
|
||||
no_force
|
||||
}
|
||||
|
||||
/// Set of param indexes for type params that are in the type's representation
|
||||
@@ -757,14 +767,10 @@
|
||||
/// Normally you would just use `tcx.erase_and_anonymize_regions(value)`,
|
||||
/// however, which uses this query as a kind of cache.
|
||||
query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// This query is not expected to have input -- as a result, it
|
||||
// is not a good candidates for "replay" because it is essentially a
|
||||
// pure function of its input (and hence the expectation is that
|
||||
// no caller would be green **apart** from just these
|
||||
// queries). Making it anonymous avoids hashing the result, which
|
||||
// may save a bit of time.
|
||||
anon
|
||||
desc { "erasing regions from `{}`", ty }
|
||||
// Not hashing the return value appears to give marginally better perf for this query,
|
||||
// which should always be marked green for having no dependencies anyway.
|
||||
no_hash
|
||||
}
|
||||
|
||||
query wasm_import_module_map(_: CrateNum) -> &'tcx DefIdMap<String> {
|
||||
|
||||
@@ -77,23 +77,34 @@ pub(crate) fn query_ensure_result<'tcx, C, T>(
|
||||
C: QueryCache<Value = Erased<Result<T, ErrorGuaranteed>>>,
|
||||
Result<T, ErrorGuaranteed>: Erasable,
|
||||
{
|
||||
let convert = |value: Erased<Result<T, ErrorGuaranteed>>| -> Result<(), ErrorGuaranteed> {
|
||||
match erase::restore_val(value) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(guar) => Err(guar),
|
||||
}
|
||||
};
|
||||
|
||||
match try_get_cached(tcx, &query.cache, key) {
|
||||
Some(value) => erase::restore_val(value).map(drop),
|
||||
None => (query.execute_query_fn)(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
key,
|
||||
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
|
||||
)
|
||||
.map(erase::restore_val)
|
||||
.map(|value| value.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
|
||||
// incremental cache. If it is green, that means that the previous compilation
|
||||
// that wrote to the incremental cache compiles successfully. That is only
|
||||
// possible if the cache entry was `Ok(())`, so we emit that here, without
|
||||
// actually encoding the `Result` in the cache or loading it from there.
|
||||
.unwrap_or(Ok(())),
|
||||
Some(value) => convert(value),
|
||||
None => {
|
||||
match (query.execute_query_fn)(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
key,
|
||||
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
|
||||
) {
|
||||
// We executed the query. Convert the successful result.
|
||||
Some(res) => convert(res),
|
||||
|
||||
// Reaching here means we didn't execute the query, but we can just assume the
|
||||
// query succeeded, because it was green in the incremental cache. If it is green,
|
||||
// that means that the previous compilation that wrote to the incremental cache
|
||||
// compiles successfully. That is only possible if the cache entry was `Ok(())`, so
|
||||
// we emit that here, without actually encoding the `Result` in the cache or
|
||||
// loading it from there.
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
// tidy-alphabetical-start
|
||||
//
|
||||
/// # `anon` query modifier
|
||||
///
|
||||
/// Generate a dep node based not on the query key, but on the query's dependencies.
|
||||
pub(crate) struct anon;
|
||||
|
||||
/// # `arena_cache` query modifier
|
||||
///
|
||||
/// Query return values must impl `Copy` and be small, but some queries must return values that
|
||||
@@ -59,6 +54,16 @@
|
||||
/// Generate a `feed` method to set the query's value from another query.
|
||||
pub(crate) struct feedable;
|
||||
|
||||
/// # `no_force` query modifier
|
||||
///
|
||||
/// Dep nodes of queries with this modifier will never be "forced" when trying
|
||||
/// to mark their dependents green, even if their key is recoverable from the
|
||||
/// key fingerprint.
|
||||
///
|
||||
/// Used by some queries with custom cycle-handlers to ensure that if a cycle
|
||||
/// occurs, all of the relevant query calls will be on the query stack.
|
||||
pub(crate) struct no_force;
|
||||
|
||||
/// # `no_hash` query modifier
|
||||
///
|
||||
/// Do not hash the query's return value for incremental compilation. If the value needs to be
|
||||
|
||||
@@ -77,8 +77,6 @@ pub enum EnsureMode {
|
||||
pub struct QueryVTable<'tcx, C: QueryCache> {
|
||||
pub name: &'static str,
|
||||
|
||||
/// True if this query has the `anon` modifier.
|
||||
pub anon: bool,
|
||||
/// True if this query has the `eval_always` modifier.
|
||||
pub eval_always: bool,
|
||||
/// True if this query has the `depth_limit` modifier.
|
||||
@@ -201,6 +199,13 @@ pub struct TyCtxtEnsureDone<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns a transparent wrapper for `TyCtxt` which uses
|
||||
/// `span` as the location of queries performed through it.
|
||||
#[inline(always)]
|
||||
pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
|
||||
TyCtxtAt { tcx: self, span }
|
||||
}
|
||||
|
||||
/// FIXME: `ensure_ok`'s effects are subtle. Is this comment fully accurate?
|
||||
///
|
||||
/// Wrapper that calls queries in a special "ensure OK" mode, for callers
|
||||
@@ -258,16 +263,9 @@ pub fn ensure_result(self) -> TyCtxtEnsureResult<'tcx> {
|
||||
pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> {
|
||||
TyCtxtEnsureDone { tcx: self }
|
||||
}
|
||||
|
||||
/// Returns a transparent wrapper for `TyCtxt` which uses
|
||||
/// `span` as the location of queries performed through it.
|
||||
#[inline(always)]
|
||||
pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
|
||||
TyCtxtAt { tcx: self, span }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! query_helper_param_ty {
|
||||
macro_rules! maybe_into_query_key {
|
||||
(DefId) => { impl $crate::query::IntoQueryKey<DefId> };
|
||||
(LocalDefId) => { impl $crate::query::IntoQueryKey<LocalDefId> };
|
||||
($K:ty) => { $K };
|
||||
@@ -276,19 +274,19 @@ macro_rules! query_helper_param_ty {
|
||||
macro_rules! define_callbacks {
|
||||
(
|
||||
// You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
|
||||
// `query_helper_param_ty!` can match on specific type names.
|
||||
// `maybe_into_query_key!` can match on specific type names.
|
||||
queries {
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
fn $name:ident($($K:tt)*) -> $V:ty
|
||||
{
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
anon: $anon:literal,
|
||||
arena_cache: $arena_cache:literal,
|
||||
cache_on_disk: $cache_on_disk:literal,
|
||||
depth_limit: $depth_limit:literal,
|
||||
eval_always: $eval_always:literal,
|
||||
feedable: $feedable:literal,
|
||||
no_force: $no_force:literal,
|
||||
no_hash: $no_hash:literal,
|
||||
returns_error_guaranteed: $returns_error_guaranteed:literal,
|
||||
separate_provide_extern: $separate_provide_extern:literal,
|
||||
@@ -323,6 +321,9 @@ pub mod $name {
|
||||
#[cfg(not($arena_cache))]
|
||||
pub type ProvidedValue<'tcx> = Value<'tcx>;
|
||||
|
||||
pub type Cache<'tcx> =
|
||||
<Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
|
||||
|
||||
/// This helper function takes a value returned by the query provider
|
||||
/// (or loaded from disk, or supplied by query feeding), allocates
|
||||
/// it in an arena if requested by the `arena_cache` modifier, and
|
||||
@@ -354,9 +355,6 @@ pub fn provided_to_erased<'tcx>(
|
||||
erase::erase_val(value)
|
||||
}
|
||||
|
||||
pub type Cache<'tcx> =
|
||||
<Key<'tcx> as $crate::query::QueryKey>::Cache<Erased<Value<'tcx>>>;
|
||||
|
||||
// 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
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
@@ -390,116 +388,8 @@ pub fn provided_to_erased<'tcx>(
|
||||
}
|
||||
)*
|
||||
|
||||
/// Holds per-query arenas for queries with the `arena_cache` modifier.
|
||||
#[derive(Default)]
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$(
|
||||
// Use the `ArenaCached` helper trait to determine the arena's value type.
|
||||
#[cfg($arena_cache)]
|
||||
pub $name: TypedArena<
|
||||
<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
|
||||
>,
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
|
||||
crate::query::inner::query_ensure_ok_or_done(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
$crate::query::EnsureMode::Ok,
|
||||
)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
// Only defined when the `ensure_result` modifier is present.
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
|
||||
$(
|
||||
#[cfg($returns_error_guaranteed)]
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(
|
||||
self,
|
||||
key: query_helper_param_ty!($($K)*),
|
||||
) -> Result<(), rustc_errors::ErrorGuaranteed> {
|
||||
crate::query::inner::query_ensure_result(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
|
||||
crate::query::inner::query_ensure_ok_or_done(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
$crate::query::EnsureMode::Done,
|
||||
);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
|
||||
self.at(DUMMY_SP).$name(key)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
|
||||
use $crate::query::{erase, inner};
|
||||
|
||||
erase::restore_val::<$V>(inner::query_get_at(
|
||||
self.tcx,
|
||||
self.span,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
))
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
#[cfg($feedable)]
|
||||
impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
|
||||
TyCtxtFeed<'tcx, K>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
|
||||
let key = self.key().into_query_key();
|
||||
let erased_value = $name::provided_to_erased(self.tcx, value);
|
||||
$crate::query::inner::query_feed(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
key,
|
||||
erased_value,
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a number.
|
||||
/// Identifies a query by kind and key. This is in contrast to `QueryJobId` which is just a
|
||||
/// number.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TaggedQueryKey<'tcx> {
|
||||
@@ -528,7 +418,8 @@ pub fn query_name(&self) -> &'static str {
|
||||
pub fn description(&self, tcx: TyCtxt<'tcx>) -> String {
|
||||
let (name, description) = ty::print::with_no_queries!(match self {
|
||||
$(
|
||||
TaggedQueryKey::$name(key) => (stringify!($name), _description_fns::$name(tcx, *key)),
|
||||
TaggedQueryKey::$name(key) =>
|
||||
(stringify!($name), _description_fns::$name(tcx, *key)),
|
||||
)*
|
||||
});
|
||||
if tcx.sess.verbose_internals() {
|
||||
@@ -550,7 +441,8 @@ pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
|
||||
}
|
||||
match self {
|
||||
$(
|
||||
TaggedQueryKey::$name(key) => crate::query::QueryKey::default_span(key, tcx),
|
||||
TaggedQueryKey::$name(key) =>
|
||||
$crate::query::QueryKey::default_span(key, tcx),
|
||||
)*
|
||||
}
|
||||
}
|
||||
@@ -558,14 +450,20 @@ pub fn default_span(&self, tcx: TyCtxt<'tcx>, span: Span) -> Span {
|
||||
pub fn def_kind(&self, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
|
||||
// This is used to reduce code generation as it
|
||||
// can be reused for queries with the same key type.
|
||||
fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<DefKind> {
|
||||
key.key_as_def_id().and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
|
||||
fn inner<'tcx>(key: &impl $crate::query::QueryKey, tcx: TyCtxt<'tcx>)
|
||||
-> Option<DefKind>
|
||||
{
|
||||
key
|
||||
.key_as_def_id()
|
||||
.and_then(|def_id| def_id.as_local())
|
||||
.map(|def_id| tcx.def_kind(def_id))
|
||||
}
|
||||
|
||||
if let TaggedQueryKey::def_kind(..) = self {
|
||||
// Try to avoid infinite recursion.
|
||||
return None
|
||||
}
|
||||
|
||||
match self {
|
||||
$(
|
||||
TaggedQueryKey::$name(key) => inner(key, tcx),
|
||||
@@ -577,7 +475,19 @@ fn inner<'tcx>(key: &impl crate::query::QueryKey, tcx: TyCtxt<'tcx>) -> Option<D
|
||||
/// Holds a `QueryVTable` for each query.
|
||||
pub struct QueryVTables<'tcx> {
|
||||
$(
|
||||
pub $name: crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
|
||||
pub $name: $crate::query::QueryVTable<'tcx, $name::Cache<'tcx>>,
|
||||
)*
|
||||
}
|
||||
|
||||
/// Holds per-query arenas for queries with the `arena_cache` modifier.
|
||||
#[derive(Default)]
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$(
|
||||
// Use the `ArenaCached` helper trait to determine the arena's value type.
|
||||
#[cfg($arena_cache)]
|
||||
pub $name: TypedArena<
|
||||
<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
|
||||
>,
|
||||
)*
|
||||
}
|
||||
|
||||
@@ -637,12 +547,108 @@ impl Copy for ExternProviders {}
|
||||
impl Clone for ExternProviders {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
|
||||
self.at(DUMMY_SP).$name(key)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtAt<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: maybe_into_query_key!($($K)*)) -> $V {
|
||||
use $crate::query::{erase, inner};
|
||||
|
||||
erase::restore_val::<$V>(inner::query_get_at(
|
||||
self.tcx,
|
||||
self.span,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
))
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
|
||||
$crate::query::inner::query_ensure_ok_or_done(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
$crate::query::EnsureMode::Ok,
|
||||
)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
// Only defined when the `returns_error_guaranteed` modifier is present.
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureResult<'tcx> {
|
||||
$(
|
||||
#[cfg($returns_error_guaranteed)]
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(
|
||||
self,
|
||||
key: maybe_into_query_key!($($K)*),
|
||||
) -> Result<(), rustc_errors::ErrorGuaranteed> {
|
||||
$crate::query::inner::query_ensure_result(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
)
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'tcx> $crate::query::TyCtxtEnsureDone<'tcx> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, key: maybe_into_query_key!($($K)*)) {
|
||||
$crate::query::inner::query_ensure_ok_or_done(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryKey::into_query_key(key),
|
||||
$crate::query::EnsureMode::Done,
|
||||
);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
// Only defined when the `feedable` modifier is present.
|
||||
#[cfg($feedable)]
|
||||
impl<'tcx, K: $crate::query::IntoQueryKey<$name::Key<'tcx>> + Copy>
|
||||
TyCtxtFeed<'tcx, K>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
|
||||
$crate::query::inner::query_feed(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
self.key().into_query_key(),
|
||||
$name::provided_to_erased(self.tcx, value),
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
// Re-export `macro_rules!` macros as normal items, so that they can be imported normally.
|
||||
pub(crate) use define_callbacks;
|
||||
pub(crate) use query_helper_param_ty;
|
||||
pub(crate) use maybe_into_query_key;
|
||||
|
||||
#[cold]
|
||||
pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
|
||||
|
||||
@@ -866,6 +866,13 @@ pub enum PatKind<'tcx> {
|
||||
pats: Box<[Pat<'tcx>]>,
|
||||
},
|
||||
|
||||
/// A guard pattern, e.g. `x if guard(x)`
|
||||
Guard {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
#[type_visitable(ignore)]
|
||||
condition: ExprId,
|
||||
},
|
||||
|
||||
/// A never pattern `!`.
|
||||
Never,
|
||||
|
||||
|
||||
@@ -247,6 +247,12 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||
visitor: &mut V,
|
||||
pat: &'thir Pat<'tcx>,
|
||||
) {
|
||||
if let PatKind::Guard { subpattern, condition } = &pat.kind {
|
||||
visitor.visit_pat(subpattern);
|
||||
visitor.visit_expr(&visitor.thir()[*condition]);
|
||||
return;
|
||||
};
|
||||
|
||||
for_each_immediate_subpat(pat, |p| visitor.visit_pat(p));
|
||||
}
|
||||
|
||||
@@ -287,5 +293,9 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
||||
callback(pat);
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Guard { subpattern, .. } => {
|
||||
callback(subpattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,10 @@ pub struct LitToConstInput<'tcx> {
|
||||
/// The absolute value of the resultant constant.
|
||||
pub lit: LitKind,
|
||||
/// The type of the constant.
|
||||
pub ty: Ty<'tcx>,
|
||||
///
|
||||
/// `None` is used by const generics when the type of the constant is unknown, e.g.
|
||||
/// if there are inference variables
|
||||
pub ty: Option<Ty<'tcx>>,
|
||||
/// If the constant is negative.
|
||||
pub neg: bool,
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr};
|
||||
use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, MaybeOwner, Node, TraitCandidate, find_attr};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_session::Session;
|
||||
@@ -657,6 +657,11 @@ pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<'tcx,
|
||||
debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
|
||||
TyCtxtFeed { tcx: self, key }.type_of(value)
|
||||
}
|
||||
|
||||
/// Feeds the HIR delayed owner during AST -> HIR delayed lowering.
|
||||
pub fn feed_delayed_owner(self, key: LocalDefId, owner: MaybeOwner<'tcx>) {
|
||||
TyCtxtFeed { tcx: self, key }.delayed_owner(owner);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
|
||||
|
||||
@@ -61,7 +61,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
/// requires calling [`InhabitedPredicate::instantiate`]
|
||||
fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
let _ = tcx.check_representability(def_id);
|
||||
tcx.ensure_ok().check_representability(def_id);
|
||||
}
|
||||
|
||||
let adt = tcx.adt_def(def_id);
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx,
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::AttrVec;
|
||||
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
|
||||
@@ -221,43 +220,15 @@ pub struct ResolverAstLowering<'tcx> {
|
||||
/// Lints that were emitted by the resolver and early lints.
|
||||
pub lint_buffer: Steal<LintBuffer>,
|
||||
|
||||
/// Information about functions signatures for delegation items expansion
|
||||
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
|
||||
// Information about delegations which is used when handling recursive delegations
|
||||
pub delegation_infos: LocalDefIdMap<DelegationInfo>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct DelegationFnSigAttrs: u8 {
|
||||
const TARGET_FEATURE = 1 << 0;
|
||||
const MUST_USE = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub const DELEGATION_INHERIT_ATTRS_START: DelegationFnSigAttrs = DelegationFnSigAttrs::MUST_USE;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DelegationInfo {
|
||||
// NodeId (either delegation.id or item_id in case of a trait impl) for signature resolution,
|
||||
// for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914
|
||||
pub resolution_node: ast::NodeId,
|
||||
pub attrs: DelegationAttrs,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DelegationAttrs {
|
||||
pub flags: DelegationFnSigAttrs,
|
||||
pub to_inherit: AttrVec,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DelegationFnSig {
|
||||
pub header: ast::FnHeader,
|
||||
pub param_count: usize,
|
||||
pub has_self: bool,
|
||||
pub c_variadic: bool,
|
||||
pub attrs: DelegationAttrs,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable)]
|
||||
|
||||
@@ -50,7 +50,8 @@ pub(crate) fn as_constant_inner<'tcx>(
|
||||
|
||||
match *kind {
|
||||
ExprKind::Literal { lit, neg } => {
|
||||
let const_ = lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty, neg });
|
||||
let const_ =
|
||||
lit_to_mir_constant(tcx, LitToConstInput { lit: lit.node, ty: Some(ty), neg });
|
||||
|
||||
ConstOperand { span, user_ty: None, const_ }
|
||||
}
|
||||
@@ -109,6 +110,8 @@ pub(crate) fn as_constant_inner<'tcx>(
|
||||
fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>) -> Const<'tcx> {
|
||||
let LitToConstInput { lit, ty, neg } = lit_input;
|
||||
|
||||
let ty = ty.expect("type of literal must be known at this point");
|
||||
|
||||
if let Err(guar) = ty.error_reported() {
|
||||
return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
|
||||
}
|
||||
|
||||
@@ -360,6 +360,11 @@ pub(super) fn for_pattern(
|
||||
Some(TestableCase::Deref { temp, mutability })
|
||||
}
|
||||
|
||||
PatKind::Guard { .. } => {
|
||||
// FIXME(guard_patterns)
|
||||
None
|
||||
}
|
||||
|
||||
PatKind::Never => Some(TestableCase::Never),
|
||||
};
|
||||
|
||||
|
||||
@@ -944,6 +944,9 @@ fn visit_primary_bindings_special(
|
||||
visit_subpat(self, subpattern, user_tys, f);
|
||||
}
|
||||
}
|
||||
PatKind::Guard { ref subpattern, .. } => {
|
||||
visit_subpat(self, subpattern, user_tys, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +315,7 @@ fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Slice { .. }
|
||||
| PatKind::Array { .. }
|
||||
| PatKind::Guard { .. }
|
||||
// Never constitutes a witness of uninhabitedness.
|
||||
| PatKind::Never => {
|
||||
self.requires_unsafe(pat.span, AccessToUnionField);
|
||||
|
||||
@@ -31,25 +31,27 @@ pub(crate) fn lit_to_const<'tcx>(
|
||||
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
|
||||
};
|
||||
|
||||
let (valtree, valtree_ty) = match (lit, expected_ty.kind()) {
|
||||
let (valtree, valtree_ty) = match (lit, expected_ty.map(|ty| ty.kind())) {
|
||||
(ast::LitKind::Str(s, _), _) => {
|
||||
let str_bytes = s.as_str().as_bytes();
|
||||
let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_);
|
||||
(ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty)
|
||||
}
|
||||
(ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
|
||||
(ast::LitKind::ByteStr(byte_sym, _), Some(ty::Ref(_, inner_ty, _)))
|
||||
if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
|
||||
&& let ty::Uint(UintTy::U8) = ty.kind() =>
|
||||
{
|
||||
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
|
||||
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
|
||||
}
|
||||
(ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
|
||||
if tcx.features().deref_patterns()
|
||||
&& let ty::Uint(UintTy::U8) = inner_ty.kind() =>
|
||||
(
|
||||
ast::LitKind::ByteStr(byte_sym, _),
|
||||
Some(ty::Slice(inner_ty) | ty::Array(inner_ty, _)),
|
||||
) if tcx.features().deref_patterns()
|
||||
&& let ty::Uint(UintTy::U8) = inner_ty.kind() =>
|
||||
{
|
||||
// Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
|
||||
// enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
|
||||
(ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty.unwrap())
|
||||
}
|
||||
(ast::LitKind::ByteStr(byte_sym, _), _) => {
|
||||
let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
|
||||
@@ -79,11 +81,11 @@ pub(crate) fn lit_to_const<'tcx>(
|
||||
trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
|
||||
(ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i))
|
||||
}
|
||||
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => {
|
||||
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Uint(ui))) if !neg => {
|
||||
let scalar_int = trunc(n.get(), *ui);
|
||||
(ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui))
|
||||
}
|
||||
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => {
|
||||
(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), Some(ty::Int(i))) => {
|
||||
// Unsigned "negation" has the same bitwise effect as signed negation,
|
||||
// which gets the result we want without additional casts.
|
||||
let scalar_int =
|
||||
@@ -101,7 +103,7 @@ pub(crate) fn lit_to_const<'tcx>(
|
||||
let bits = parse_float_into_scalar(n, fty, neg)?;
|
||||
(ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty))
|
||||
}
|
||||
(ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => {
|
||||
(ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), Some(ty::Float(fty))) => {
|
||||
let bits = parse_float_into_scalar(n, *fty, neg)?;
|
||||
(ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty))
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ fn mirror_stmts(
|
||||
}
|
||||
Some(_) | None => local.span,
|
||||
};
|
||||
let initializer = local.init.map(|init| self.mirror_expr(init));
|
||||
let stmt = Stmt {
|
||||
kind: StmtKind::Let {
|
||||
remainder_scope,
|
||||
@@ -91,7 +92,7 @@ fn mirror_stmts(
|
||||
data: region::ScopeData::Node,
|
||||
},
|
||||
pattern,
|
||||
initializer: local.init.map(|init| self.mirror_expr(init)),
|
||||
initializer,
|
||||
else_block,
|
||||
hir_id: local.hir_id,
|
||||
span,
|
||||
|
||||
@@ -876,7 +876,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
|
||||
};
|
||||
|
||||
let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap();
|
||||
let mut expr = None::<ExprKind<'tcx>>;
|
||||
let mut expr = None::<ExprKind<'_>>;
|
||||
|
||||
for &(container, variant, field) in indices.iter() {
|
||||
let next = mk_call(&mut self.thir, container, variant, field);
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
/// Query implementation for [`TyCtxt::thir_body`].
|
||||
pub(crate) fn thir_body(
|
||||
tcx: TyCtxt<'_>,
|
||||
pub(crate) fn thir_body<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
owner_def: LocalDefId,
|
||||
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
|
||||
) -> Result<(&'tcx Steal<Thir<'tcx>>, ExprId), ErrorGuaranteed> {
|
||||
debug_assert!(!tcx.is_type_const(owner_def.to_def_id()), "thir_body queried for type_const");
|
||||
|
||||
let body = tcx.hir_body_owned_by(owner_def);
|
||||
let mut cx = ThirBuildCx::new(tcx, owner_def);
|
||||
let mut cx: ThirBuildCx<'tcx> = ThirBuildCx::new(tcx, owner_def);
|
||||
if let Some(reported) = cx.typeck_results.tainted_by_errors {
|
||||
return Err(reported);
|
||||
}
|
||||
@@ -50,7 +50,7 @@ pub(crate) fn thir_body(
|
||||
}
|
||||
|
||||
/// Context for lowering HIR to THIR for a single function body (or other kind of body).
|
||||
struct ThirBuildCx<'tcx> {
|
||||
pub(crate) struct ThirBuildCx<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// The THIR data that this context is building.
|
||||
thir: Thir<'tcx>,
|
||||
@@ -118,6 +118,7 @@ fn pattern_from_hir_with_annotation(
|
||||
let_stmt_type: Option<&hir::Ty<'tcx>>,
|
||||
) -> Box<Pat<'tcx>> {
|
||||
crate::thir::pattern::pat_from_hir(
|
||||
self,
|
||||
self.tcx,
|
||||
self.typing_env,
|
||||
self.typeck_results,
|
||||
@@ -201,7 +202,7 @@ fn explicit_params(
|
||||
fn_sig.inputs()[index]
|
||||
};
|
||||
|
||||
let pat = self.pattern_from_hir(param.pat);
|
||||
let pat: Box<Pat<'tcx>> = self.pattern_from_hir(param.pat);
|
||||
Param { pat: Some(pat), ty, ty_span, self_kind, hir_id: Some(param.hir_id) }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern,
|
||||
};
|
||||
|
||||
impl<'tcx> PatCtxt<'tcx> {
|
||||
impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> {
|
||||
/// Converts a constant to a pattern (if possible).
|
||||
/// This means aggregate values (like structs and enums) are converted
|
||||
/// to a pattern that matches the value (as if you'd compared via structural equality).
|
||||
@@ -61,7 +61,7 @@ struct ConstToPat<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> ConstToPat<'tcx> {
|
||||
fn new(pat_ctxt: &PatCtxt<'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
|
||||
fn new(pat_ctxt: &PatCtxt<'tcx, '_>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
|
||||
trace!(?pat_ctxt.typeck_results.hir_owner);
|
||||
ConstToPat { tcx: pat_ctxt.tcx, typing_env: pat_ctxt.typing_env, span, id, c }
|
||||
}
|
||||
|
||||
@@ -30,9 +30,11 @@
|
||||
pub(crate) use self::check_match::check_match;
|
||||
use self::migration::PatMigration;
|
||||
use crate::errors::*;
|
||||
use crate::thir::cx::ThirBuildCx;
|
||||
|
||||
/// Context for lowering HIR patterns to THIR patterns.
|
||||
struct PatCtxt<'tcx> {
|
||||
struct PatCtxt<'tcx, 'ptcx> {
|
||||
upper: &'ptcx mut ThirBuildCx<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
@@ -41,8 +43,9 @@ struct PatCtxt<'tcx> {
|
||||
rust_2024_migration: Option<PatMigration<'tcx>>,
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(tcx, typing_env, typeck_results), ret)]
|
||||
pub(super) fn pat_from_hir<'tcx>(
|
||||
#[instrument(level = "debug", skip(upper, tcx, typing_env, typeck_results), ret)]
|
||||
pub(super) fn pat_from_hir<'tcx, 'ptcx>(
|
||||
upper: &'ptcx mut ThirBuildCx<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
@@ -51,6 +54,7 @@ pub(super) fn pat_from_hir<'tcx>(
|
||||
let_stmt_type: Option<&hir::Ty<'tcx>>,
|
||||
) -> Box<Pat<'tcx>> {
|
||||
let mut pcx = PatCtxt {
|
||||
upper,
|
||||
tcx,
|
||||
typing_env,
|
||||
typeck_results,
|
||||
@@ -87,7 +91,7 @@ pub(super) fn pat_from_hir<'tcx>(
|
||||
thir_pat
|
||||
}
|
||||
|
||||
impl<'tcx> PatCtxt<'tcx> {
|
||||
impl<'tcx, 'ptcx> PatCtxt<'tcx, 'ptcx> {
|
||||
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
|
||||
let adjustments: &[PatAdjustment<'tcx>] =
|
||||
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
|
||||
@@ -443,8 +447,10 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
|
||||
|
||||
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
|
||||
|
||||
// FIXME(guard_patterns): implement guard pattern lowering
|
||||
hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
|
||||
hir::PatKind::Guard(pat, condition) => PatKind::Guard {
|
||||
subpattern: self.lower_pattern(pat),
|
||||
condition: self.upper.mirror_expr(condition),
|
||||
},
|
||||
|
||||
hir::PatKind::Err(guar) => PatKind::Error(guar),
|
||||
};
|
||||
@@ -696,7 +702,7 @@ fn lower_pat_expr(
|
||||
// patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.
|
||||
|
||||
let pat_ty = self.typeck_results.node_type(pat.hir_id);
|
||||
let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated };
|
||||
let lit_input = LitToConstInput { lit: lit.node, ty: Some(pat_ty), neg: *negated };
|
||||
let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated)
|
||||
.then(|| self.tcx.at(expr.span).lit_to_const(lit_input))
|
||||
.flatten()
|
||||
|
||||
@@ -844,6 +844,14 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
|
||||
print_indented!(self, "]", depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Guard { subpattern, condition } => {
|
||||
print_indented!(self, "Guard pattern: {", depth_lvl + 1);
|
||||
print_indented!(self, "subpattern: ", depth_lvl + 2);
|
||||
self.print_pat(subpattern, depth_lvl + 3);
|
||||
print_indented!(self, "guard: ", depth_lvl + 2);
|
||||
self.print_expr(*condition, depth_lvl + 3);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Error(_) => {
|
||||
print_indented!(self, "Error", depth_lvl + 1);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,11 @@ fn canonicalize_param_env(
|
||||
cache: Default::default(),
|
||||
};
|
||||
let param_env = param_env.fold_with(&mut env_canonicalizer);
|
||||
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
|
||||
debug_assert!(
|
||||
env_canonicalizer.sub_root_lookup_table.is_empty(),
|
||||
"{:?}",
|
||||
env_canonicalizer.sub_root_lookup_table
|
||||
);
|
||||
(
|
||||
param_env,
|
||||
env_canonicalizer.variables,
|
||||
|
||||
@@ -987,7 +987,12 @@ fn try_eagerly_replace_alias(
|
||||
let replacement = self.ecx.instantiate_binder_with_infer(*replacement);
|
||||
self.nested.extend(
|
||||
self.ecx
|
||||
.eq_and_get_goals(self.param_env, alias_term, replacement.projection_term)
|
||||
.relate_and_get_goals(
|
||||
self.param_env,
|
||||
alias_term,
|
||||
ty::Invariant,
|
||||
replacement.projection_term,
|
||||
)
|
||||
.expect("expected to be able to unify goal projection with dyn's projection"),
|
||||
);
|
||||
|
||||
|
||||
@@ -408,7 +408,7 @@ pub(super) fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsage
|
||||
|
||||
/// Recursively evaluates `goal`, returning whether any inference vars have
|
||||
/// been constrained and the certainty of the result.
|
||||
fn evaluate_goal(
|
||||
pub(super) fn evaluate_goal(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
@@ -1018,7 +1018,8 @@ pub(super) fn relate<T: Relate<I>>(
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
|
||||
let goals = self.relate_and_get_goals(param_env, lhs, variance, rhs)?;
|
||||
|
||||
for &goal in goals.iter() {
|
||||
let source = match goal.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
|
||||
@@ -1039,13 +1040,37 @@ pub(super) fn relate<T: Relate<I>>(
|
||||
/// If possible, try using `eq` instead which automatically handles nested
|
||||
/// goals correctly.
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
pub(super) fn eq_and_get_goals<T: Relate<I>>(
|
||||
&self,
|
||||
pub(super) fn relate_and_get_goals<T: Relate<I>>(
|
||||
&mut self,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
|
||||
Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
|
||||
let cx = self.cx();
|
||||
let delegate = self.delegate;
|
||||
let origin_span = self.origin_span;
|
||||
|
||||
let mut normalize = |alias: ty::AliasTy<I>| {
|
||||
let inference_var = self.next_ty_infer();
|
||||
|
||||
let goal = Goal::new(
|
||||
cx,
|
||||
param_env,
|
||||
ty::PredicateKind::AliasRelate(
|
||||
alias.to_ty(cx).into(),
|
||||
inference_var.into(),
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
|
||||
// Ignore the result. If we can't eagerly normalize, returning the inference variable is enough.
|
||||
let _ = self.evaluate_goal(GoalSource::TypeRelating, goal, None);
|
||||
|
||||
self.resolve_vars_if_possible(inference_var)
|
||||
};
|
||||
|
||||
Ok(delegate.relate(param_env, lhs, variance, rhs, origin_span, &mut normalize)?)
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
|
||||
|
||||
@@ -4499,3 +4499,111 @@ pub(super) fn from_token(token: &Token) -> Option<Self> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression"
|
||||
)]
|
||||
pub(crate) struct BreakWithLabelAndLoop {
|
||||
#[subdiagnostic]
|
||||
pub sub: BreakWithLabelAndLoopSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion("wrap this expression in parentheses", applicability = "machine-applicable")]
|
||||
pub(crate) struct BreakWithLabelAndLoopSub {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("prefix `'r` is reserved")]
|
||||
pub(crate) struct RawPrefix {
|
||||
#[label("reserved prefix")]
|
||||
pub label: Span,
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unicode codepoint changing visible direction of text present in comment")]
|
||||
#[note(
|
||||
"these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
|
||||
)]
|
||||
pub(crate) struct UnicodeTextFlow {
|
||||
#[label(
|
||||
"{$num_codepoints ->
|
||||
[1] this comment contains an invisible unicode text flow control codepoint
|
||||
*[other] this comment contains invisible unicode text flow control codepoints
|
||||
}"
|
||||
)]
|
||||
pub comment_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub characters: Vec<UnicodeCharNoteSub>,
|
||||
#[subdiagnostic]
|
||||
pub suggestions: Option<UnicodeTextFlowSuggestion>,
|
||||
|
||||
pub num_codepoints: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label("{$c_debug}")]
|
||||
pub(crate) struct UnicodeCharNoteSub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub c_debug: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
"if their presence wasn't intentional, you can remove them",
|
||||
applicability = "machine-applicable",
|
||||
style = "hidden"
|
||||
)]
|
||||
pub(crate) struct UnicodeTextFlowSuggestion {
|
||||
#[suggestion_part(code = "")]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("prefix `{$prefix}` is unknown")]
|
||||
pub(crate) struct ReservedPrefix {
|
||||
#[label("unknown prefix")]
|
||||
pub label: Span,
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("will be parsed as a guarded string in Rust 2024")]
|
||||
pub(crate) struct ReservedStringLint {
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("reserved token in Rust 2024")]
|
||||
pub(crate) struct ReservedMultihashLint {
|
||||
#[suggestion(
|
||||
"insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
|
||||
code = " ",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_control_chars};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, StashKey};
|
||||
use rustc_lexer::{
|
||||
Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_horizontal_whitespace,
|
||||
};
|
||||
use rustc_literal_escaper::{EscapeError, Mode, check_for_errors};
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{
|
||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
|
||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
|
||||
@@ -388,7 +387,10 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) {
|
||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
||||
prefix_span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::RawPrefix(prefix_span),
|
||||
errors::RawPrefix {
|
||||
label: prefix_span,
|
||||
suggestion: prefix_span.shrink_to_hi()
|
||||
},
|
||||
);
|
||||
|
||||
// Reset the state so we just lex the `'r`.
|
||||
@@ -498,11 +500,41 @@ fn lint_unicode_text_flow(&self, start: BytePos) {
|
||||
let content = self.str_from(content_start);
|
||||
if contains_text_flow_control_chars(content) {
|
||||
let span = self.mk_sp(start, self.pos);
|
||||
self.psess.buffer_lint(
|
||||
let content = content.to_string();
|
||||
self.psess.dyn_buffer_lint(
|
||||
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()),
|
||||
move |dcx, level| {
|
||||
let spans: Vec<_> = content
|
||||
.char_indices()
|
||||
.filter_map(|(i, c)| {
|
||||
TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
|
||||
let lo = span.lo() + BytePos(2 + i as u32);
|
||||
(c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let characters = spans
|
||||
.iter()
|
||||
.map(|&(c, span)| errors::UnicodeCharNoteSub {
|
||||
span,
|
||||
c_debug: format!("{c:?}"),
|
||||
})
|
||||
.collect();
|
||||
let suggestions =
|
||||
(!spans.is_empty()).then_some(errors::UnicodeTextFlowSuggestion {
|
||||
spans: spans.iter().map(|(_c, span)| *span).collect(),
|
||||
});
|
||||
|
||||
errors::UnicodeTextFlow {
|
||||
comment_span: span,
|
||||
characters,
|
||||
suggestions,
|
||||
num_codepoints: spans.len(),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1038,7 +1070,11 @@ fn report_unknown_prefix(&self, start: BytePos) {
|
||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
||||
prefix_span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()),
|
||||
errors::ReservedPrefix {
|
||||
label: prefix_span,
|
||||
suggestion: prefix_span.shrink_to_hi(),
|
||||
prefix: prefix.to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1112,11 +1148,18 @@ fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) ->
|
||||
})
|
||||
} else {
|
||||
// Before Rust 2024, only emit a lint for migration.
|
||||
self.psess.buffer_lint(
|
||||
self.psess.dyn_buffer_lint(
|
||||
RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::ReservedString { is_string, suggestion: space_span },
|
||||
move |dcx, level| {
|
||||
if is_string {
|
||||
errors::ReservedStringLint { suggestion: space_span }.into_diag(dcx, level)
|
||||
} else {
|
||||
errors::ReservedMultihashLint { suggestion: space_span }
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// For backwards compatibility, roll back to after just the first `#`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user