mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #124650 - oli-obk:pattern_types_syntax, r=nnethercote
Create const block DefIds in typeck instead of ast lowering this is a prerequisite for cleaning up pattern types and the range pattern HIR nodes in general. Right now they contain expressions, but they are supposed to only contain constants. In order to generate the anonymous constants lazily during typeck, we need to support generating new items with bodies during typeck in general. Transforming const blocks was the simplest change I could find to allow us to do that (everything else is much more invasive if we haven't already done it for const blocks).
This commit is contained in:
commit
7717a306b2
@ -1393,7 +1393,7 @@ pub enum ExprKind {
|
||||
/// An array (e.g, `[a, b, c, d]`).
|
||||
Array(ThinVec<P<Expr>>),
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(AnonConst),
|
||||
ConstBlock(P<Expr>),
|
||||
/// A function call
|
||||
///
|
||||
/// The first field resolves to the function itself,
|
||||
|
@ -1411,7 +1411,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
match kind {
|
||||
ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis),
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
vis.visit_anon_const(anon_const);
|
||||
vis.visit_expr(anon_const);
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
vis.visit_expr(expr);
|
||||
|
@ -951,7 +951,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
||||
ExprKind::Array(subexpressions) => {
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)),
|
||||
ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_expr(anon_const)),
|
||||
ExprKind::Repeat(element, count) => {
|
||||
try_visit!(visitor.visit_expr(element));
|
||||
try_visit!(visitor.visit_anon_const(count));
|
||||
|
@ -75,12 +75,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(c) => {
|
||||
let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock {
|
||||
def_id: this.local_def_id(c.id),
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
self.has_inline_consts = true;
|
||||
hir::ExprKind::ConstBlock(self.lower_expr(c))
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
|
@ -236,14 +236,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
|
||||
self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant));
|
||||
|
||||
self.with_parent(constant.hir_id, |this| {
|
||||
intravisit::walk_inline_const(this, constant);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
|
||||
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
|
||||
|
||||
|
@ -96,6 +96,8 @@ struct LoweringContext<'a, 'hir> {
|
||||
|
||||
/// Bodies inside the owner being lowered.
|
||||
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
|
||||
/// Whether there were inline consts that typeck will split out into bodies
|
||||
has_inline_consts: bool,
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
@ -158,6 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
item_local_id_counter: hir::ItemLocalId::ZERO,
|
||||
node_id_to_local_id: Default::default(),
|
||||
trait_map: Default::default(),
|
||||
has_inline_consts: false,
|
||||
|
||||
// Lowering state.
|
||||
catch_scope: None,
|
||||
@ -567,6 +570,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_has_inline_consts = std::mem::take(&mut self.has_inline_consts);
|
||||
let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_trait_map = std::mem::take(&mut self.trait_map);
|
||||
let current_owner =
|
||||
@ -593,6 +597,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.has_inline_consts = current_has_inline_consts;
|
||||
self.node_id_to_local_id = current_node_ids;
|
||||
self.trait_map = current_trait_map;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
@ -629,6 +634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
let has_inline_consts = std::mem::take(&mut self.has_inline_consts);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
@ -646,7 +652,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies, has_inline_consts };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
|
||||
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
|
@ -380,8 +380,9 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Array(exprs) => {
|
||||
self.print_expr_vec(exprs);
|
||||
}
|
||||
ast::ExprKind::ConstBlock(anon_const) => {
|
||||
self.print_expr_anon_const(anon_const, attrs);
|
||||
ast::ExprKind::ConstBlock(expr) => {
|
||||
self.word_space("const");
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
}
|
||||
ast::ExprKind::Repeat(element, count) => {
|
||||
self.print_expr_repeat(element, count);
|
||||
|
@ -38,7 +38,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
match node {
|
||||
hir::Node::Ctor(_)
|
||||
| hir::Node::AnonConst(_)
|
||||
| hir::Node::ConstBlock(_)
|
||||
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => {
|
||||
hir::Constness::Const
|
||||
}
|
||||
@ -57,6 +56,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
||||
if is_const { hir::Constness::Const } else { hir::Constness::NotConst }
|
||||
}
|
||||
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
|
||||
hir::Node::Expr(e) if let hir::ExprKind::ConstBlock(_) = e.kind => hir::Constness::Const,
|
||||
_ => {
|
||||
if let Some(fn_kind) = node.fn_kind() {
|
||||
if fn_kind.constness() == hir::Constness::Const {
|
||||
|
@ -6,7 +6,6 @@ use std::ops::ControlFlow;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::fx::IndexEntry;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::LangItem;
|
||||
@ -392,18 +391,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> {
|
||||
instance: ty::InstanceDef<'tcx>,
|
||||
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
|
||||
match instance {
|
||||
ty::InstanceDef::Item(def) => {
|
||||
if ecx.tcx.is_ctfe_mir_available(def) {
|
||||
Ok(ecx.tcx.mir_for_ctfe(def))
|
||||
} else if ecx.tcx.def_kind(def) == DefKind::AssocConst {
|
||||
ecx.tcx.dcx().bug("This is likely a const item that is missing from its impl");
|
||||
} else {
|
||||
// `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
|
||||
// so this should be unreachable.
|
||||
let path = ecx.tcx.def_path_str(def);
|
||||
bug!("trying to call extern function `{path}` at compile-time");
|
||||
}
|
||||
}
|
||||
ty::InstanceDef::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)),
|
||||
_ => Ok(ecx.tcx.instance_mir(instance)),
|
||||
}
|
||||
}
|
||||
|
@ -876,6 +876,9 @@ pub struct OwnerNodes<'tcx> {
|
||||
pub nodes: IndexVec<ItemLocalId, ParentedNode<'tcx>>,
|
||||
/// Content of local bodies.
|
||||
pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
|
||||
/// Whether the body contains inline constants that are created for the query system during typeck
|
||||
/// of the body.
|
||||
pub has_inline_consts: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> OwnerNodes<'tcx> {
|
||||
@ -1592,14 +1595,6 @@ pub struct AnonConst {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// An inline constant expression `const { something }`.
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub struct ConstBlock {
|
||||
pub hir_id: HirId,
|
||||
pub def_id: LocalDefId,
|
||||
pub body: BodyId,
|
||||
}
|
||||
|
||||
/// An expression.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Expr<'hir> {
|
||||
@ -1886,7 +1881,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum ExprKind<'hir> {
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(ConstBlock),
|
||||
ConstBlock(&'hir Expr<'hir>),
|
||||
/// An array (e.g., `[a, b, c, d]`).
|
||||
Array(&'hir [Expr<'hir>]),
|
||||
/// A function call.
|
||||
@ -3609,7 +3604,6 @@ pub enum Node<'hir> {
|
||||
Variant(&'hir Variant<'hir>),
|
||||
Field(&'hir FieldDef<'hir>),
|
||||
AnonConst(&'hir AnonConst),
|
||||
ConstBlock(&'hir ConstBlock),
|
||||
Expr(&'hir Expr<'hir>),
|
||||
ExprField(&'hir ExprField<'hir>),
|
||||
Stmt(&'hir Stmt<'hir>),
|
||||
@ -3670,7 +3664,6 @@ impl<'hir> Node<'hir> {
|
||||
Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::ConstBlock(..)
|
||||
| Node::Expr(..)
|
||||
| Node::Stmt(..)
|
||||
| Node::Block(..)
|
||||
@ -3768,7 +3761,6 @@ impl<'hir> Node<'hir> {
|
||||
}
|
||||
|
||||
Node::AnonConst(constant) => Some((constant.def_id, constant.body)),
|
||||
Node::ConstBlock(constant) => Some((constant.def_id, constant.body)),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
@ -3837,7 +3829,6 @@ impl<'hir> Node<'hir> {
|
||||
expect_variant, &'hir Variant<'hir>, Node::Variant(n), n;
|
||||
expect_field, &'hir FieldDef<'hir>, Node::Field(n), n;
|
||||
expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n;
|
||||
expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n;
|
||||
expect_expr, &'hir Expr<'hir>, Node::Expr(n), n;
|
||||
expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n;
|
||||
expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n;
|
||||
|
@ -344,9 +344,6 @@ pub trait Visitor<'v>: Sized {
|
||||
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
|
||||
walk_anon_const(self, c)
|
||||
}
|
||||
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
|
||||
walk_inline_const(self, c)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
|
||||
walk_expr(self, ex)
|
||||
}
|
||||
@ -716,14 +713,6 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
|
||||
visitor.visit_nested_body(constant.body)
|
||||
}
|
||||
|
||||
pub fn walk_inline_const<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
constant: &'v ConstBlock,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(constant.hir_id));
|
||||
visitor.visit_nested_body(constant.body)
|
||||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(expression.hir_id));
|
||||
match expression.kind {
|
||||
@ -731,7 +720,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
ExprKind::ConstBlock(ref const_block) => {
|
||||
try_visit!(visitor.visit_inline_const(const_block))
|
||||
try_visit!(visitor.visit_expr(const_block))
|
||||
}
|
||||
ExprKind::Repeat(ref element, ref count) => {
|
||||
try_visit!(visitor.visit_expr(element));
|
||||
|
@ -93,7 +93,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
|
||||
// `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
|
||||
// the body satisfies the condition of two nodes being different have different
|
||||
// `hash_stable` results.
|
||||
let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self;
|
||||
let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _, has_inline_consts: _ } =
|
||||
*self;
|
||||
opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
@ -407,11 +407,14 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
||||
match expr.kind {
|
||||
// Manually recurse over closures and inline consts, because they are the only
|
||||
// case of nested bodies that share the parent environment.
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. })
|
||||
| hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => visitor.enter_body(expr.hir_id, |this| {
|
||||
this.cx.var_parent = None;
|
||||
resolve_local(this, None, Some(expr));
|
||||
}),
|
||||
hir::ExprKind::AssignOp(_, left_expr, right_expr) => {
|
||||
debug!(
|
||||
"resolve_expr - enabling pessimistic_yield, was previously {}",
|
||||
@ -782,6 +785,32 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
|
||||
}
|
||||
self.enter_scope(Scope { id, data: ScopeData::Node });
|
||||
}
|
||||
|
||||
fn enter_body(&mut self, hir_id: hir::HirId, f: impl FnOnce(&mut Self)) {
|
||||
// Save all state that is specific to the outer function
|
||||
// body. These will be restored once down below, once we've
|
||||
// visited the body.
|
||||
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
|
||||
let outer_cx = self.cx;
|
||||
let outer_ts = mem::take(&mut self.terminating_scopes);
|
||||
// The 'pessimistic yield' flag is set to true when we are
|
||||
// processing a `+=` statement and have to make pessimistic
|
||||
// control flow assumptions. This doesn't apply to nested
|
||||
// bodies within the `+=` statements. See #69307.
|
||||
let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
|
||||
self.terminating_scopes.insert(hir_id.local_id);
|
||||
|
||||
self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::CallSite });
|
||||
self.enter_scope(Scope { id: hir_id.local_id, data: ScopeData::Arguments });
|
||||
|
||||
f(self);
|
||||
|
||||
// Restore context we had at the start.
|
||||
self.expr_and_pat_count = outer_ec;
|
||||
self.cx = outer_cx;
|
||||
self.terminating_scopes = outer_ts;
|
||||
self.pessimistic_yield = outer_pessimistic_yield;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
@ -801,60 +830,40 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
||||
self.cx.parent
|
||||
);
|
||||
|
||||
// Save all state that is specific to the outer function
|
||||
// body. These will be restored once down below, once we've
|
||||
// visited the body.
|
||||
let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
|
||||
let outer_cx = self.cx;
|
||||
let outer_ts = mem::take(&mut self.terminating_scopes);
|
||||
// The 'pessimistic yield' flag is set to true when we are
|
||||
// processing a `+=` statement and have to make pessimistic
|
||||
// control flow assumptions. This doesn't apply to nested
|
||||
// bodies within the `+=` statements. See #69307.
|
||||
let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
|
||||
self.terminating_scopes.insert(body.value.hir_id.local_id);
|
||||
self.enter_body(body.value.hir_id, |this| {
|
||||
if this.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
|
||||
// The arguments and `self` are parented to the fn.
|
||||
this.cx.var_parent = this.cx.parent.take();
|
||||
for param in body.params {
|
||||
this.visit_pat(param.pat);
|
||||
}
|
||||
|
||||
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite });
|
||||
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments });
|
||||
|
||||
// The arguments and `self` are parented to the fn.
|
||||
self.cx.var_parent = self.cx.parent.take();
|
||||
for param in body.params {
|
||||
self.visit_pat(param.pat);
|
||||
}
|
||||
|
||||
// The body of the every fn is a root scope.
|
||||
self.cx.parent = self.cx.var_parent;
|
||||
if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
|
||||
self.visit_expr(body.value)
|
||||
} else {
|
||||
// Only functions have an outer terminating (drop) scope, while
|
||||
// temporaries in constant initializers may be 'static, but only
|
||||
// according to rvalue lifetime semantics, using the same
|
||||
// syntactical rules used for let initializers.
|
||||
//
|
||||
// e.g., in `let x = &f();`, the temporary holding the result from
|
||||
// the `f()` call lives for the entirety of the surrounding block.
|
||||
//
|
||||
// Similarly, `const X: ... = &f();` would have the result of `f()`
|
||||
// live for `'static`, implying (if Drop restrictions on constants
|
||||
// ever get lifted) that the value *could* have a destructor, but
|
||||
// it'd get leaked instead of the destructor running during the
|
||||
// evaluation of `X` (if at all allowed by CTFE).
|
||||
//
|
||||
// However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
|
||||
// would *not* let the `f()` temporary escape into an outer scope
|
||||
// (i.e., `'static`), which means that after `g` returns, it drops,
|
||||
// and all the associated destruction scope rules apply.
|
||||
self.cx.var_parent = None;
|
||||
resolve_local(self, None, Some(body.value));
|
||||
}
|
||||
|
||||
// Restore context we had at the start.
|
||||
self.expr_and_pat_count = outer_ec;
|
||||
self.cx = outer_cx;
|
||||
self.terminating_scopes = outer_ts;
|
||||
self.pessimistic_yield = outer_pessimistic_yield;
|
||||
// The body of the every fn is a root scope.
|
||||
this.cx.parent = this.cx.var_parent;
|
||||
this.visit_expr(body.value)
|
||||
} else {
|
||||
// Only functions have an outer terminating (drop) scope, while
|
||||
// temporaries in constant initializers may be 'static, but only
|
||||
// according to rvalue lifetime semantics, using the same
|
||||
// syntactical rules used for let initializers.
|
||||
//
|
||||
// e.g., in `let x = &f();`, the temporary holding the result from
|
||||
// the `f()` call lives for the entirety of the surrounding block.
|
||||
//
|
||||
// Similarly, `const X: ... = &f();` would have the result of `f()`
|
||||
// live for `'static`, implying (if Drop restrictions on constants
|
||||
// ever get lifted) that the value *could* have a destructor, but
|
||||
// it'd get leaked instead of the destructor running during the
|
||||
// evaluation of `X` (if at all allowed by CTFE).
|
||||
//
|
||||
// However, `const Y: ... = g(&f());`, like `let y = g(&f());`,
|
||||
// would *not* let the `f()` temporary escape into an outer scope
|
||||
// (i.e., `'static`), which means that after `g` returns, it drops,
|
||||
// and all the associated destruction scope rules apply.
|
||||
this.cx.var_parent = None;
|
||||
resolve_local(this, None, Some(body.value));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) {
|
||||
|
@ -177,10 +177,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::ConstBlock(_)
|
||||
| Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
|
||||
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
||||
}
|
||||
Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure { .. } | hir::ExprKind::ConstBlock { .. },
|
||||
..
|
||||
}) => Some(tcx.typeck_root_def_id(def_id.to_def_id())),
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::OpaqueTy(&hir::OpaqueTy {
|
||||
origin:
|
||||
@ -415,7 +415,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
}
|
||||
|
||||
// provide junk type parameter defs for const blocks.
|
||||
if let Node::ConstBlock(_) = node {
|
||||
if let Node::Expr(Expr { kind: ExprKind::ConstBlock(..), .. }) = node {
|
||||
own_params.push(ty::GenericParamDef {
|
||||
index: next_index(),
|
||||
name: Symbol::intern("<const_ty>"),
|
||||
|
@ -484,8 +484,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
||||
}
|
||||
|
||||
Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
|
||||
|
||||
Node::ConstBlock(_) => {
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(..), .. }) => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id());
|
||||
args.as_inline_const().ty()
|
||||
}
|
||||
|
@ -190,10 +190,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Freeze definitions as we don't add new ones at this point. This improves performance by
|
||||
// allowing lock-free access to them.
|
||||
tcx.untracked().definitions.freeze();
|
||||
|
||||
// FIXME: Remove this when we implement creating `DefId`s
|
||||
// for anon constants during their parents' typeck.
|
||||
// Typeck all body owners in parallel will produce queries
|
||||
@ -205,6 +201,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
}
|
||||
});
|
||||
|
||||
// Freeze definitions as we don't add new ones at this point. This improves performance by
|
||||
// allowing lock-free access to them.
|
||||
tcx.untracked().definitions.freeze();
|
||||
|
||||
tcx.ensure().check_unused_traits(());
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,6 @@ impl<'a> State<'a> {
|
||||
Node::ImplItem(a) => self.print_impl_item(a),
|
||||
Node::Variant(a) => self.print_variant(a),
|
||||
Node::AnonConst(a) => self.print_anon_const(a),
|
||||
Node::ConstBlock(a) => self.print_inline_const(a),
|
||||
Node::Expr(a) => self.print_expr(a),
|
||||
Node::ExprField(a) => self.print_expr_field(a),
|
||||
Node::Stmt(a) => self.print_stmt(a),
|
||||
@ -1049,10 +1048,10 @@ impl<'a> State<'a> {
|
||||
self.end()
|
||||
}
|
||||
|
||||
fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
|
||||
fn print_inline_const(&mut self, constant: &hir::Expr<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word_space("const");
|
||||
self.ann.nested(self, Nested::Body(constant.body));
|
||||
self.print_expr(constant);
|
||||
self.end()
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ use rustc_errors::{
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
|
||||
@ -336,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_with_expectation(block, expected),
|
||||
ExprKind::Repeat(element, ref count) => {
|
||||
self.check_expr_repeat(element, count, expected, expr)
|
||||
}
|
||||
@ -1460,24 +1459,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_const_block(
|
||||
&self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let body = self.tcx.hir().body(block.body);
|
||||
|
||||
// Create a new function context.
|
||||
let def_id = block.def_id;
|
||||
let fcx = FnCtxt::new(self, self.param_env, def_id);
|
||||
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||
|
||||
let ty = fcx.check_expr_with_expectation(body.value, expected);
|
||||
fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized);
|
||||
fcx.write_ty(block.hir_id, ty);
|
||||
ty
|
||||
}
|
||||
|
||||
fn check_expr_repeat(
|
||||
&self,
|
||||
element: &'tcx hir::Expr<'tcx>,
|
||||
|
@ -1055,6 +1055,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.take_while(|(_, node)| {
|
||||
// look at parents until we find the first body owner
|
||||
node.body_id().is_none()
|
||||
&& !matches!(
|
||||
node,
|
||||
Node::Expr(Expr { kind: ExprKind::ConstBlock { .. }, .. })
|
||||
)
|
||||
})
|
||||
.any(|(parent_id, _)| self.is_loop(parent_id));
|
||||
|
||||
|
@ -149,10 +149,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
|
||||
self.visit_body(body);
|
||||
self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
let body = self.fcx.tcx.hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// generic parameters.
|
||||
|
||||
use crate::FnCtxt;
|
||||
use hir::def::DefKind;
|
||||
use rustc_data_structures::unord::ExtendUnord;
|
||||
use rustc_errors::{ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
@ -16,7 +17,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::TypeSuperFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::solve;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
@ -295,11 +296,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
|
||||
self.visit_field_id(e.hir_id);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(anon_const) => {
|
||||
self.visit_node_id(e.span, anon_const.hir_id);
|
||||
|
||||
let body = self.tcx().hir().body(anon_const.body);
|
||||
self.visit_body(body);
|
||||
hir::ExprKind::ConstBlock(_) => {
|
||||
let feed = self.tcx().create_def(self.fcx.body_id, kw::Empty, DefKind::InlineConst);
|
||||
feed.def_span(e.span);
|
||||
feed.local_def_id_to_hir_id(e.hir_id);
|
||||
self.typeck_results.inline_consts.insert(e.hir_id.local_id, feed.def_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ impl<'hir> Map<'hir> {
|
||||
|
||||
/// Returns an iterator of the `DefId`s for all body-owners in this
|
||||
/// crate. If you would prefer to iterate over the bodies
|
||||
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
|
||||
/// themselves, you can do `self.hir().krate().owners.iter()`.
|
||||
#[inline]
|
||||
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir {
|
||||
self.tcx.hir_crate_items(()).body_owners.iter().copied()
|
||||
@ -508,7 +508,17 @@ impl<'hir> Map<'hir> {
|
||||
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
||||
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
||||
pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
|
||||
self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
|
||||
for (_, node) in self.parent_iter(hir_id) {
|
||||
if let Some((def_id, _)) = node.associated_body() {
|
||||
return self.body_const_context(def_id).is_some();
|
||||
}
|
||||
if let Node::Expr(e) = node {
|
||||
if let ExprKind::ConstBlock(_) = e.kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
|
||||
@ -891,7 +901,6 @@ impl<'hir> Map<'hir> {
|
||||
Node::Variant(variant) => variant.span,
|
||||
Node::Field(field) => field.span,
|
||||
Node::AnonConst(constant) => constant.span,
|
||||
Node::ConstBlock(constant) => self.body(constant.body).value.span,
|
||||
Node::Expr(expr) => expr.span,
|
||||
Node::ExprField(field) => field.span,
|
||||
Node::Stmt(stmt) => stmt.span,
|
||||
@ -1161,7 +1170,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
|
||||
format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
|
||||
}
|
||||
Node::AnonConst(_) => node_str("const"),
|
||||
Node::ConstBlock(_) => node_str("const"),
|
||||
Node::Expr(_) => node_str("expr"),
|
||||
Node::ExprField(_) => node_str("expr field"),
|
||||
Node::Stmt(_) => node_str("stmt"),
|
||||
@ -1311,11 +1319,6 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
||||
intravisit::walk_anon_const(self, c)
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'hir ConstBlock) {
|
||||
self.body_owners.push(c.def_id);
|
||||
intravisit::walk_inline_const(self, c)
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
|
||||
if let ExprKind::Closure(closure) = ex.kind {
|
||||
self.body_owners.push(closure.def_id);
|
||||
|
@ -737,6 +737,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
|
||||
1,
|
||||
),
|
||||
bodies,
|
||||
has_inline_consts: false,
|
||||
})));
|
||||
self.feed_owner_id().hir_attrs(attrs);
|
||||
}
|
||||
|
@ -217,6 +217,10 @@ pub struct TypeckResults<'tcx> {
|
||||
|
||||
/// Container types and field indices of `offset_of!` expressions
|
||||
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
|
||||
|
||||
/// Maps from `HirId`s of const blocks (the `ExprKind::ConstBlock`, not the inner expression's)
|
||||
/// to the `DefId` of the corresponding inline const.
|
||||
pub inline_consts: FxIndexMap<ItemLocalId, LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeckResults<'tcx> {
|
||||
@ -249,6 +253,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
treat_byte_string_as_slice: Default::default(),
|
||||
closure_size_eval: Default::default(),
|
||||
offset_of_data: Default::default(),
|
||||
inline_consts: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,11 +568,8 @@ fn construct_const<'a, 'tcx>(
|
||||
..
|
||||
}) => (*span, ty.span),
|
||||
Node::AnonConst(ct) => (ct.span, ct.span),
|
||||
Node::ConstBlock(_) => {
|
||||
let span = tcx.def_span(def);
|
||||
(span, span)
|
||||
}
|
||||
_ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
|
||||
Node::Expr(&hir::Expr { span, kind: hir::ExprKind::ConstBlock(_), .. }) => (span, span),
|
||||
node => span_bug!(tcx.def_span(def), "can't build MIR for {def:?}: {node:#?}"),
|
||||
};
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
|
@ -671,9 +671,9 @@ impl<'tcx> Cx<'tcx> {
|
||||
ExprKind::OffsetOf { container, fields }
|
||||
}
|
||||
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
let ty = self.typeck_results().node_type(anon_const.hir_id);
|
||||
let did = anon_const.def_id.to_def_id();
|
||||
hir::ExprKind::ConstBlock(body) => {
|
||||
let ty = self.typeck_results().node_type(body.hir_id);
|
||||
let did = self.typeck_results().inline_consts[&expr.hir_id.local_id].into();
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(did);
|
||||
let parent_args =
|
||||
tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id));
|
||||
|
@ -13,10 +13,10 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::instrument;
|
||||
|
||||
pub(crate) fn thir_body(
|
||||
@ -24,7 +24,22 @@ pub(crate) fn thir_body(
|
||||
owner_def: LocalDefId,
|
||||
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
|
||||
let hir = tcx.hir();
|
||||
let body = hir.body(hir.body_owned_by(owner_def));
|
||||
let body;
|
||||
let body = match tcx.def_kind(owner_def) {
|
||||
// Inline consts do not have bodies of their own, so create one to make the follow-up logic simpler.
|
||||
DefKind::InlineConst => {
|
||||
let e = hir.expect_expr(tcx.local_def_id_to_hir_id(owner_def));
|
||||
body = hir::Body {
|
||||
params: &[],
|
||||
value: match e.kind {
|
||||
hir::ExprKind::ConstBlock(body) => body,
|
||||
_ => span_bug!(e.span, "InlineConst was not a ConstBlock: {e:#?}"),
|
||||
},
|
||||
};
|
||||
&body
|
||||
}
|
||||
_ => hir.body(hir.body_owned_by(owner_def)),
|
||||
};
|
||||
let mut cx = Cx::new(tcx, owner_def);
|
||||
if let Some(reported) = cx.typeck_results.tainted_by_errors {
|
||||
return Err(reported);
|
||||
@ -165,7 +180,7 @@ impl<'tcx> Cx<'tcx> {
|
||||
&'a mut self,
|
||||
owner_id: HirId,
|
||||
fn_decl: &'tcx hir::FnDecl<'tcx>,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
body: &hir::Body<'tcx>,
|
||||
) -> impl Iterator<Item = Param<'tcx>> + 'a {
|
||||
let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id];
|
||||
|
||||
|
@ -637,15 +637,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
/// Converts inline const patterns.
|
||||
fn lower_inline_const(
|
||||
&mut self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
) -> PatKind<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let def_id = block.def_id;
|
||||
let body_id = block.body;
|
||||
let expr = &tcx.hir().body(body_id).value;
|
||||
let ty = tcx.typeck(def_id).node_type(block.hir_id);
|
||||
let def_id = self.typeck_results.inline_consts[&id.local_id];
|
||||
let ty = tcx.typeck(def_id).node_type(expr.hir_id);
|
||||
|
||||
// Special case inline consts that are just literals. This is solely
|
||||
// a performance optimization, as we could also just go through the regular
|
||||
|
@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
||||
}
|
||||
|
||||
fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
tcx.mir_keys(()).contains(&def_id)
|
||||
tcx.hir().maybe_body_owned_by(def_id).is_some()
|
||||
}
|
||||
|
||||
/// Finds the full set of `DefId`s within the current crate that have
|
||||
@ -222,6 +222,15 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
|
||||
// All body-owners have MIR associated with them.
|
||||
set.extend(tcx.hir().body_owners());
|
||||
|
||||
// Inline consts' bodies are created in
|
||||
// typeck instead of during ast lowering, like all other bodies so far.
|
||||
for def_id in tcx.hir().body_owners() {
|
||||
// Incremental performance optimization: only load typeck results for things that actually have inline consts
|
||||
if tcx.hir_owner_nodes(tcx.hir().body_owned_by(def_id).hir_id.owner).has_inline_consts {
|
||||
set.extend(tcx.typeck(def_id).inline_consts.values())
|
||||
}
|
||||
}
|
||||
|
||||
// Additionally, tuple struct/variant constructors have MIR, but
|
||||
// they don't have a BodyId, so we need to build them separately.
|
||||
struct GatherCtors<'a> {
|
||||
|
@ -25,8 +25,8 @@ use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
|
||||
Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
|
||||
self as ast, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, Expr,
|
||||
ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
|
||||
VisibilityKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
@ -1260,12 +1260,9 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
self.eat_keyword(kw::Const);
|
||||
let (attrs, blk) = self.parse_inner_attrs_and_block()?;
|
||||
let anon_const = AnonConst {
|
||||
id: DUMMY_NODE_ID,
|
||||
value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
|
||||
};
|
||||
let blk_span = anon_const.value.span;
|
||||
Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs))
|
||||
let expr = self.mk_expr(blk.span, ExprKind::Block(blk, None));
|
||||
let blk_span = expr.span;
|
||||
Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(expr), attrs))
|
||||
}
|
||||
|
||||
/// Parses mutability (`mut` or nothing).
|
||||
|
@ -196,11 +196,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
|
||||
let kind = Some(hir::ConstContext::Const { inline: true });
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
|
||||
let owner = self.tcx.hir().body_owner_def_id(body.id());
|
||||
let kind = self.tcx.hir().body_const_context(owner);
|
||||
@ -228,6 +223,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
self.const_check_violated(expr, e.span);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
let kind = Some(hir::ConstContext::Const { inline: true });
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr));
|
||||
return;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
@ -587,6 +587,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
||||
hir::ExprKind::OffsetOf(..) => {
|
||||
self.handle_offset_of(expr);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
// When inline const blocks are used in pattern position, paths
|
||||
// referenced by it should be considered as used.
|
||||
let in_pat = mem::replace(&mut self.in_pat, false);
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
|
||||
self.in_pat = in_pat;
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -648,17 +658,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
||||
|
||||
self.in_pat = in_pat;
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
|
||||
// When inline const blocks are used in pattern position, paths
|
||||
// referenced by it should be considered as used.
|
||||
let in_pat = mem::replace(&mut self.in_pat, false);
|
||||
|
||||
self.live_symbols.insert(c.def_id);
|
||||
intravisit::walk_inline_const(self, c);
|
||||
|
||||
self.in_pat = in_pat;
|
||||
}
|
||||
}
|
||||
|
||||
fn has_allow_dead_code_or_lang_attr(
|
||||
|
@ -147,6 +147,11 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run for inline consts, they are collected together with their parent
|
||||
if let DefKind::InlineConst = tcx.def_kind(def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run unused pass for #[naked]
|
||||
if tcx.has_attr(def_id.to_def_id(), sym::naked) {
|
||||
return;
|
||||
@ -1144,12 +1149,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::ConstBlock(..)
|
||||
| hir::ExprKind::Err(_)
|
||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||
| hir::ExprKind::Path(hir::QPath::LangItem(..))
|
||||
| hir::ExprKind::OffsetOf(..) => succ,
|
||||
|
||||
hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ),
|
||||
|
||||
// Note that labels have been resolved, so we don't need to look
|
||||
// at the label ident
|
||||
hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ),
|
||||
|
@ -93,10 +93,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
|
||||
self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
fk: hir::intravisit::FnKind<'hir>,
|
||||
@ -289,6 +285,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
||||
self.cx_stack.len() - 1,
|
||||
)
|
||||
}
|
||||
hir::ExprKind::ConstBlock(expr) => {
|
||||
self.with_context(Constant, |v| intravisit::walk_expr(v, expr));
|
||||
}
|
||||
_ => intravisit::walk_expr(self, e),
|
||||
}
|
||||
}
|
||||
|
@ -325,16 +325,6 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
ExprKind::Gen(_, _, _) => {
|
||||
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
|
||||
}
|
||||
ExprKind::ConstBlock(ref constant) => {
|
||||
let def = self.create_def(
|
||||
constant.id,
|
||||
kw::Empty,
|
||||
DefKind::InlineConst,
|
||||
constant.value.span,
|
||||
);
|
||||
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
|
||||
return;
|
||||
}
|
||||
_ => self.parent_def,
|
||||
};
|
||||
|
||||
|
@ -4502,9 +4502,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
self.visit_expr(elem);
|
||||
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
|
||||
}
|
||||
ExprKind::ConstBlock(ref ct) => {
|
||||
self.resolve_anon_const(ct, AnonConstKind::InlineConst);
|
||||
}
|
||||
ExprKind::Index(ref elem, ref idx, _) => {
|
||||
self.resolve_expr(elem, Some(expr));
|
||||
self.visit_expr(idx);
|
||||
|
@ -6,7 +6,7 @@ use crate::{clip, is_direct_expn_of, sext, unsext};
|
||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
||||
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
|
||||
use rustc_lexer::tokenize;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
||||
@ -412,7 +412,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
|
||||
ExprKind::ConstBlock(e) |
|
||||
ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
||||
@ -491,7 +491,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||
/// leaves the local crate.
|
||||
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
|
||||
ExprKind::ConstBlock(e) |
|
||||
ExprKind::DropTemps(e) => self.expr_is_empty(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
if !self
|
||||
|
@ -295,7 +295,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
|
||||
},
|
||||
(&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false,
|
||||
(&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body),
|
||||
(&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_expr(lb, rb),
|
||||
(&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
|
||||
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
|
||||
},
|
||||
@ -770,7 +770,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
self.hash_expr(self.cx.tcx.hir().body(body).value);
|
||||
},
|
||||
ExprKind::ConstBlock(ref l_id) => {
|
||||
self.hash_body(l_id.body);
|
||||
self.hash_expr(l_id);
|
||||
},
|
||||
ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
|
||||
self.hash_expr(e);
|
||||
|
@ -1,11 +1,35 @@
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:188:36
|
||||
|
|
||||
LL | let _ = const { let mut n = 1; n += 1; n };
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:191:40
|
||||
|
|
||||
LL | let _ = const { let mut n = 1; n = n + 1; n };
|
||||
| ^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:194:40
|
||||
|
|
||||
LL | let _ = const { let mut n = 1; n = 1 + n; n };
|
||||
| ^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:200:59
|
||||
|
|
||||
LL | let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n };
|
||||
| ^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:304:5
|
||||
|
|
||||
LL | _n += 1;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> tests/ui/arithmetic_side_effects.rs:305:5
|
||||
@ -727,5 +751,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec
|
||||
LL | one.sub_assign(1);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 121 previous errors
|
||||
error: aborting due to 125 previous errors
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//@ needs-sanitizer-cfi
|
||||
//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
|
||||
|
||||
#![crate_type="lib"]
|
||||
#![crate_type = "lib"]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate core;
|
||||
@ -14,14 +14,15 @@ pub type Type2 = impl Send;
|
||||
pub type Type3 = impl Send;
|
||||
pub type Type4 = impl Send;
|
||||
|
||||
pub fn foo() where
|
||||
pub fn foo()
|
||||
where
|
||||
Type1: 'static,
|
||||
Type2: 'static,
|
||||
Type3: 'static,
|
||||
Type4: 'static,
|
||||
{
|
||||
// Type in extern path
|
||||
extern {
|
||||
extern "C" {
|
||||
fn bar();
|
||||
}
|
||||
let _: Type1 = bar;
|
||||
@ -35,43 +36,44 @@ pub fn foo() where
|
||||
// Type in const path
|
||||
const {
|
||||
pub struct Foo;
|
||||
fn bar() -> Type3 { Foo }
|
||||
fn bar() -> Type3 {
|
||||
Foo
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Type in impl path
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn bar(&self) { }
|
||||
fn bar(&self) {}
|
||||
}
|
||||
let _: Type4 = <Foo>::bar;
|
||||
}
|
||||
|
||||
// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore
|
||||
|
||||
pub fn foo1(_: &Type1) { }
|
||||
pub fn foo1(_: &Type1) {}
|
||||
// CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo2(_: &Type1, _: &Type1) { }
|
||||
pub fn foo2(_: &Type1, _: &Type1) {}
|
||||
// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo3(_: &Type1, _: &Type1, _: &Type1) { }
|
||||
pub fn foo3(_: &Type1, _: &Type1, _: &Type1) {}
|
||||
// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo4(_: &Type2) { }
|
||||
pub fn foo4(_: &Type2) {}
|
||||
// CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo5(_: &Type2, _: &Type2) { }
|
||||
pub fn foo5(_: &Type2, _: &Type2) {}
|
||||
// CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo6(_: &Type2, _: &Type2, _: &Type2) { }
|
||||
pub fn foo6(_: &Type2, _: &Type2, _: &Type2) {}
|
||||
// CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo7(_: &Type3) { }
|
||||
pub fn foo7(_: &Type3) {}
|
||||
// CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo8(_: &Type3, _: &Type3) { }
|
||||
pub fn foo8(_: &Type3, _: &Type3) {}
|
||||
// CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo9(_: &Type3, _: &Type3, _: &Type3) { }
|
||||
pub fn foo9(_: &Type3, _: &Type3, _: &Type3) {}
|
||||
// CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo10(_: &Type4) { }
|
||||
pub fn foo10(_: &Type4) {}
|
||||
// CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo11(_: &Type4, _: &Type4) { }
|
||||
pub fn foo11(_: &Type4, _: &Type4) {}
|
||||
// CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { }
|
||||
pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {}
|
||||
// CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
|
||||
|
||||
// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"}
|
||||
@ -80,9 +82,9 @@ pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { }
|
||||
// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
|
||||
// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
|
||||
// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEE"}
|
||||
// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_E"}
|
||||
// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_S0_E"}
|
||||
// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
|
||||
// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
|
||||
// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
|
||||
|
@ -10,7 +10,7 @@ fn consts() -> () {
|
||||
|
||||
bb0: {
|
||||
_1 = const 5_u8;
|
||||
_2 = const consts::<C>::{constant#0};
|
||||
_2 = const consts::<C>::{constant#1};
|
||||
_3 = const C;
|
||||
_4 = const D;
|
||||
_5 = consts::<10>;
|
||||
|
@ -206,12 +206,7 @@ fn _11() {
|
||||
let _ = ();
|
||||
()
|
||||
};
|
||||
let const {
|
||||
#![rustc_dummy]
|
||||
} =
|
||||
#[rustc_dummy] const {
|
||||
#![rustc_dummy]
|
||||
};
|
||||
let const {} = #[rustc_dummy] const {};
|
||||
let mut x = 0;
|
||||
let _ = (#[rustc_dummy] x) = 15;
|
||||
let _ = (#[rustc_dummy] x) += 15;
|
||||
|
@ -67,18 +67,13 @@ LL | impl Test {
|
||||
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
|
||||
--> $DIR/consts.rs:50:9
|
||||
|
|
||||
LL | const {
|
||||
| ___________-
|
||||
LL | | impl Test {
|
||||
| | ^^^^^----
|
||||
| | |
|
||||
| | `Test` is not local
|
||||
LL | |
|
||||
LL | | fn hoo() {}
|
||||
... |
|
||||
LL | | 1
|
||||
LL | | };
|
||||
| |_____- move the `impl` block outside of this inline constant `<unnameable>` and up 2 bodies
|
||||
LL | fn main() {
|
||||
| --------- move the `impl` block outside of this function `main`
|
||||
...
|
||||
LL | impl Test {
|
||||
| ^^^^^----
|
||||
| |
|
||||
| `Test` is not local
|
||||
|
|
||||
= note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
|
||||
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
|
||||
|
@ -82,7 +82,8 @@ mod expressions {
|
||||
fn expr_const_block() {
|
||||
const {};
|
||||
const { 1 };
|
||||
const {
|
||||
const
|
||||
{
|
||||
struct S;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user