mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-01 19:23:50 +00:00
Merge from rustc
This commit is contained in:
commit
e720147bf5
@ -2302,6 +2302,9 @@ pub enum InlineAsmOperand {
|
|||||||
Sym {
|
Sym {
|
||||||
sym: InlineAsmSym,
|
sym: InlineAsmSym,
|
||||||
},
|
},
|
||||||
|
Label {
|
||||||
|
block: P<Block>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineAsmOperand {
|
impl InlineAsmOperand {
|
||||||
@ -2311,7 +2314,7 @@ impl InlineAsmOperand {
|
|||||||
| Self::Out { reg, .. }
|
| Self::Out { reg, .. }
|
||||||
| Self::InOut { reg, .. }
|
| Self::InOut { reg, .. }
|
||||||
| Self::SplitInOut { reg, .. } => Some(reg),
|
| Self::SplitInOut { reg, .. } => Some(reg),
|
||||||
Self::Const { .. } | Self::Sym { .. } => None,
|
Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1331,6 +1331,7 @@ pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
|
|||||||
}
|
}
|
||||||
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
|
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
|
||||||
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
|
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
|
||||||
|
InlineAsmOperand::Label { block } => vis.visit_block(block),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,6 +823,7 @@ pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm)
|
|||||||
try_visit!(visitor.visit_anon_const(anon_const))
|
try_visit!(visitor.visit_anon_const(anon_const))
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)),
|
InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)),
|
||||||
|
InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
|
@ -88,6 +88,9 @@ ast_lowering_invalid_abi_suggestion = did you mean
|
|||||||
ast_lowering_invalid_asm_template_modifier_const =
|
ast_lowering_invalid_asm_template_modifier_const =
|
||||||
asm template modifiers are not allowed for `const` arguments
|
asm template modifiers are not allowed for `const` arguments
|
||||||
|
|
||||||
|
ast_lowering_invalid_asm_template_modifier_label =
|
||||||
|
asm template modifiers are not allowed for `label` arguments
|
||||||
|
|
||||||
ast_lowering_invalid_asm_template_modifier_reg_class =
|
ast_lowering_invalid_asm_template_modifier_reg_class =
|
||||||
invalid asm template modifier for this register class
|
invalid asm template modifier for this register class
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringE
|
|||||||
use super::errors::{
|
use super::errors::{
|
||||||
AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
|
AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
|
||||||
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
|
||||||
InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub,
|
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
|
||||||
InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber,
|
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
|
||||||
RegisterConflict,
|
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
|
||||||
};
|
};
|
||||||
use super::LoweringContext;
|
use super::LoweringContext;
|
||||||
|
|
||||||
@ -237,6 +237,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::Label { block } => {
|
||||||
|
if !self.tcx.features().asm_goto {
|
||||||
|
feature_err(
|
||||||
|
sess,
|
||||||
|
sym::asm_goto,
|
||||||
|
*op_sp,
|
||||||
|
"label operands for inline assembly are unstable",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
(op, self.lower_span(*op_sp))
|
(op, self.lower_span(*op_sp))
|
||||||
})
|
})
|
||||||
@ -296,6 +308,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
op_span: op_sp,
|
op_span: op_sp,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
hir::InlineAsmOperand::Label { .. } => {
|
||||||
|
self.dcx().emit_err(InvalidAsmTemplateModifierLabel {
|
||||||
|
placeholder_span,
|
||||||
|
op_span: op_sp,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,7 +353,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
|
|
||||||
hir::InlineAsmOperand::Const { .. }
|
hir::InlineAsmOperand::Const { .. }
|
||||||
| hir::InlineAsmOperand::SymFn { .. }
|
| hir::InlineAsmOperand::SymFn { .. }
|
||||||
| hir::InlineAsmOperand::SymStatic { .. } => {
|
| hir::InlineAsmOperand::SymStatic { .. }
|
||||||
|
| hir::InlineAsmOperand::Label { .. } => {
|
||||||
unreachable!("{op:?} is not a register operand");
|
unreachable!("{op:?} is not a register operand");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -261,6 +261,16 @@ pub struct InvalidAsmTemplateModifierSym {
|
|||||||
pub op_span: Span,
|
pub op_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic, Clone, Copy)]
|
||||||
|
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||||
|
pub struct InvalidAsmTemplateModifierLabel {
|
||||||
|
#[primary_span]
|
||||||
|
#[label(ast_lowering_template_modifier)]
|
||||||
|
pub placeholder_span: Span,
|
||||||
|
#[label(ast_lowering_argument)]
|
||||||
|
pub op_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic, Clone, Copy)]
|
#[derive(Diagnostic, Clone, Copy)]
|
||||||
#[diag(ast_lowering_register_class_only_clobber)]
|
#[diag(ast_lowering_register_class_only_clobber)]
|
||||||
pub struct RegisterClassOnlyClobber {
|
pub struct RegisterClassOnlyClobber {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use super::LoweringContext;
|
use super::LoweringContext;
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::visit::Visitor;
|
use rustc_ast::visit::Visitor;
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
@ -594,30 +595,32 @@ fn expand_format_args<'hir>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
||||||
struct MayContainYieldPoint(bool);
|
struct MayContainYieldPoint;
|
||||||
|
|
||||||
impl Visitor<'_> for MayContainYieldPoint {
|
impl Visitor<'_> for MayContainYieldPoint {
|
||||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
type Result = ControlFlow<()>;
|
||||||
|
|
||||||
|
fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
|
||||||
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
|
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
|
||||||
self.0 = true;
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
visit::walk_expr(self, e);
|
visit::walk_expr(self, e);
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_mac_call(&mut self, _: &ast::MacCall) {
|
fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
|
||||||
// Macros should be expanded at this point.
|
// Macros should be expanded at this point.
|
||||||
unreachable!("unexpanded macro in ast lowering");
|
unreachable!("unexpanded macro in ast lowering");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(&mut self, _: &ast::Item) {
|
fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
|
||||||
// Do not recurse into nested items.
|
// Do not recurse into nested items.
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = MayContainYieldPoint(false);
|
MayContainYieldPoint.visit_expr(e).is_break()
|
||||||
visitor.visit_expr(e);
|
|
||||||
visitor.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
|
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
|
||||||
|
@ -275,7 +275,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
}
|
}
|
||||||
Some(ty) => this.lower_ty(
|
Some(ty) => this.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
|
ImplTraitContext::OpaqueTy {
|
||||||
|
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||||
|
parent: this.local_def_id(id),
|
||||||
|
in_assoc_ty: false,
|
||||||
|
},
|
||||||
|
fn_kind: None,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -936,7 +942,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
Some(ty) => {
|
Some(ty) => {
|
||||||
let ty = this.lower_ty(
|
let ty = this.lower_ty(
|
||||||
ty,
|
ty,
|
||||||
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
|
ImplTraitContext::OpaqueTy {
|
||||||
|
origin: hir::OpaqueTyOrigin::TyAlias {
|
||||||
|
parent: this.local_def_id(i.id),
|
||||||
|
in_assoc_ty: true,
|
||||||
|
},
|
||||||
|
fn_kind: None,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
hir::ImplItemKind::Type(ty)
|
hir::ImplItemKind::Type(ty)
|
||||||
}
|
}
|
||||||
|
@ -265,13 +265,12 @@ enum ImplTraitContext {
|
|||||||
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
||||||
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
|
/// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`.
|
||||||
///
|
///
|
||||||
ReturnPositionOpaqueTy {
|
OpaqueTy {
|
||||||
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
|
|
||||||
origin: hir::OpaqueTyOrigin,
|
origin: hir::OpaqueTyOrigin,
|
||||||
fn_kind: FnDeclKind,
|
/// Only used to change the lifetime capture rules, since
|
||||||
|
/// RPITIT captures all in scope, RPIT does not.
|
||||||
|
fn_kind: Option<FnDeclKind>,
|
||||||
},
|
},
|
||||||
/// Impl trait in type aliases.
|
|
||||||
TypeAliasesOpaqueTy { in_assoc_ty: bool },
|
|
||||||
/// `impl Trait` is unstably accepted in this position.
|
/// `impl Trait` is unstably accepted in this position.
|
||||||
FeatureGated(ImplTraitPosition, Symbol),
|
FeatureGated(ImplTraitPosition, Symbol),
|
||||||
/// `impl Trait` is not accepted in this position.
|
/// `impl Trait` is not accepted in this position.
|
||||||
@ -1075,9 +1074,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
// Disallow ATB in dyn types
|
// Disallow ATB in dyn types
|
||||||
if self.is_in_dyn_type {
|
if self.is_in_dyn_type {
|
||||||
let suggestion = match itctx {
|
let suggestion = match itctx {
|
||||||
ImplTraitContext::ReturnPositionOpaqueTy { .. }
|
ImplTraitContext::OpaqueTy { .. } | ImplTraitContext::Universal => {
|
||||||
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
|
|
||||||
| ImplTraitContext::Universal => {
|
|
||||||
let bound_end_span = constraint
|
let bound_end_span = constraint
|
||||||
.gen_args
|
.gen_args
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -1417,22 +1414,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
TyKind::ImplTrait(def_node_id, bounds) => {
|
TyKind::ImplTrait(def_node_id, bounds) => {
|
||||||
let span = t.span;
|
let span = t.span;
|
||||||
match itctx {
|
match itctx {
|
||||||
ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self
|
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
||||||
.lower_opaque_impl_trait(
|
|
||||||
span,
|
span,
|
||||||
origin,
|
origin,
|
||||||
*def_node_id,
|
*def_node_id,
|
||||||
bounds,
|
bounds,
|
||||||
Some(fn_kind),
|
fn_kind,
|
||||||
itctx,
|
|
||||||
),
|
|
||||||
ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
|
|
||||||
.lower_opaque_impl_trait(
|
|
||||||
span,
|
|
||||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
|
|
||||||
*def_node_id,
|
|
||||||
bounds,
|
|
||||||
None,
|
|
||||||
itctx,
|
itctx,
|
||||||
),
|
),
|
||||||
ImplTraitContext::Universal => {
|
ImplTraitContext::Universal => {
|
||||||
@ -1553,9 +1540,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
|
|
||||||
let captured_lifetimes_to_duplicate = match origin {
|
let captured_lifetimes_to_duplicate = match origin {
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
|
// type alias impl trait and associated type position impl trait were
|
||||||
// lifetimes, since we don't have the issue that any are late-bound.
|
// decided to capture all in-scope lifetimes, which we collect for
|
||||||
Vec::new()
|
// all opaques during resolution.
|
||||||
|
self.resolver
|
||||||
|
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||||
if matches!(
|
if matches!(
|
||||||
@ -1823,9 +1815,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
FnDeclKind::Fn
|
FnDeclKind::Fn
|
||||||
| FnDeclKind::Inherent
|
| FnDeclKind::Inherent
|
||||||
| FnDeclKind::Trait
|
| FnDeclKind::Trait
|
||||||
| FnDeclKind::Impl => ImplTraitContext::ReturnPositionOpaqueTy {
|
| FnDeclKind::Impl => ImplTraitContext::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
|
origin: hir::OpaqueTyOrigin::FnReturn(self.local_def_id(fn_node_id)),
|
||||||
fn_kind: kind,
|
fn_kind: Some(kind),
|
||||||
},
|
},
|
||||||
FnDeclKind::ExternFn => {
|
FnDeclKind::ExternFn => {
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
|
ImplTraitContext::Disallowed(ImplTraitPosition::ExternFnReturn)
|
||||||
@ -1919,9 +1911,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
output,
|
output,
|
||||||
coro,
|
coro,
|
||||||
opaque_ty_span,
|
opaque_ty_span,
|
||||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
ImplTraitContext::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||||
fn_kind,
|
fn_kind: Some(fn_kind),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
arena_vec![this; bound]
|
arena_vec![this; bound]
|
||||||
|
@ -423,7 +423,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
|
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
|
||||||
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
|
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
|
||||||
// ```
|
// ```
|
||||||
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. }) => {
|
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
|
||||||
if self.tcx.features().impl_trait_in_fn_trait_return {
|
if self.tcx.features().impl_trait_in_fn_trait_return {
|
||||||
self.lower_ty(ty, itctx)
|
self.lower_ty(ty, itctx)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1452,6 +1452,10 @@ impl<'a> State<'a> {
|
|||||||
s.print_path(&sym.path, true, 0);
|
s.print_path(&sym.path, true, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::Label { block } => {
|
||||||
|
s.head("label");
|
||||||
|
s.print_block(block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AsmArg::ClobberAbi(abi) => {
|
AsmArg::ClobberAbi(abi) => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||||
#![allow(rustc::untranslatable_diagnostic)]
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use hir::ExprKind;
|
use hir::ExprKind;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Applicability, Diag};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
@ -727,30 +728,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
_ => local_decl.source_info.span,
|
_ => local_decl.source_info.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BindingFinder {
|
|
||||||
span: Span,
|
|
||||||
hir_id: Option<hir::HirId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
|
||||||
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
|
||||||
if let hir::StmtKind::Local(local) = s.kind {
|
|
||||||
if local.pat.span == self.span {
|
|
||||||
self.hir_id = Some(local.hir_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::intravisit::walk_stmt(self, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let def_id = self.body.source.def_id();
|
let def_id = self.body.source.def_id();
|
||||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||||
{
|
{
|
||||||
let body = self.infcx.tcx.hir().body(body_id);
|
let body = self.infcx.tcx.hir().body(body_id);
|
||||||
let mut v = BindingFinder { span: pat_span, hir_id: None };
|
BindingFinder { span: pat_span }.visit_body(body).break_value()
|
||||||
v.visit_body(body);
|
|
||||||
v.hir_id
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -859,17 +842,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hir_map = self.infcx.tcx.hir();
|
let hir_map = self.infcx.tcx.hir();
|
||||||
struct Finder<'tcx> {
|
struct Finder {
|
||||||
span: Span,
|
span: Span,
|
||||||
expr: Option<&'tcx Expr<'tcx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for Finder<'tcx> {
|
impl<'tcx> Visitor<'tcx> for Finder {
|
||||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
type Result = ControlFlow<&'tcx Expr<'tcx>>;
|
||||||
if e.span == self.span && self.expr.is_none() {
|
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
|
||||||
self.expr = Some(e);
|
if e.span == self.span {
|
||||||
|
ControlFlow::Break(e)
|
||||||
|
} else {
|
||||||
|
hir::intravisit::walk_expr(self, e)
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_expr(self, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
||||||
@ -878,9 +862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
||||||
// expression with that span in order to identify potential fixes when encountering a
|
// expression with that span in order to identify potential fixes when encountering a
|
||||||
// read-only iterator that should be mutable.
|
// read-only iterator that should be mutable.
|
||||||
let mut v = Finder { span, expr: None };
|
if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
|
||||||
v.visit_block(block);
|
|
||||||
if let Some(expr) = v.expr
|
|
||||||
&& let Call(_, [expr]) = expr.kind
|
&& let Call(_, [expr]) = expr.kind
|
||||||
{
|
{
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
@ -1179,29 +1161,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some((false, err_label_span, message)) => {
|
Some((false, err_label_span, message)) => {
|
||||||
struct BindingFinder {
|
|
||||||
span: Span,
|
|
||||||
hir_id: Option<hir::HirId>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
|
||||||
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
|
||||||
if let hir::StmtKind::Local(local) = s.kind {
|
|
||||||
if local.pat.span == self.span {
|
|
||||||
self.hir_id = Some(local.hir_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::intravisit::walk_stmt(self, s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let def_id = self.body.source.def_id();
|
let def_id = self.body.source.def_id();
|
||||||
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
let hir_id = if let Some(local_def_id) = def_id.as_local()
|
||||||
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
|
||||||
{
|
{
|
||||||
let body = self.infcx.tcx.hir().body(body_id);
|
let body = self.infcx.tcx.hir().body(body_id);
|
||||||
let mut v = BindingFinder { span: err_label_span, hir_id: None };
|
BindingFinder { span: err_label_span }.visit_body(body).break_value()
|
||||||
v.visit_body(body);
|
|
||||||
v.hir_id
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -1333,6 +1298,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BindingFinder {
|
||||||
|
span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Visitor<'tcx> for BindingFinder {
|
||||||
|
type Result = ControlFlow<hir::HirId>;
|
||||||
|
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
|
||||||
|
if let hir::StmtKind::Local(local) = s.kind
|
||||||
|
&& local.pat.span == self.span
|
||||||
|
{
|
||||||
|
ControlFlow::Break(local.hir_id)
|
||||||
|
} else {
|
||||||
|
hir::intravisit::walk_stmt(self, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
|
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
|
||||||
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
|
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
@ -723,7 +724,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
|||||||
operands,
|
operands,
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
targets: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
@ -749,7 +750,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
|||||||
}
|
}
|
||||||
InlineAsmOperand::Const { value: _ }
|
InlineAsmOperand::Const { value: _ }
|
||||||
| InlineAsmOperand::SymFn { value: _ }
|
| InlineAsmOperand::SymFn { value: _ }
|
||||||
| InlineAsmOperand::SymStatic { def_id: _ } => {}
|
| InlineAsmOperand::SymStatic { def_id: _ }
|
||||||
|
| InlineAsmOperand::Label { target_index: _ } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||||||
operands,
|
operands,
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
targets: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
@ -182,7 +182,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
InlineAsmOperand::Const { value: _ }
|
InlineAsmOperand::Const { value: _ }
|
||||||
| InlineAsmOperand::SymFn { value: _ }
|
| InlineAsmOperand::SymFn { value: _ }
|
||||||
| InlineAsmOperand::SymStatic { def_id: _ } => {}
|
| InlineAsmOperand::SymStatic { def_id: _ }
|
||||||
|
| InlineAsmOperand::Label { target_index: _ } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,14 +367,17 @@ fn check_opaque_type_parameter_valid(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
|
let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id);
|
||||||
let is_ty_alias = match opaque_ty_hir.expect_opaque_ty().origin {
|
let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin {
|
||||||
OpaqueTyOrigin::TyAlias { .. } => true,
|
OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true),
|
||||||
OpaqueTyOrigin::AsyncFn(..) | OpaqueTyOrigin::FnReturn(..) => false,
|
OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
let parent_generics = tcx.generics_of(parent);
|
||||||
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
|
||||||
for (i, arg) in opaque_type_key.args.iter().enumerate() {
|
|
||||||
|
// Only check the parent generics, which will ignore any of the
|
||||||
|
// duplicated lifetime args that come from reifying late-bounds.
|
||||||
|
for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() {
|
||||||
if let Err(guar) = arg.error_reported() {
|
if let Err(guar) = arg.error_reported() {
|
||||||
return Err(guar);
|
return Err(guar);
|
||||||
}
|
}
|
||||||
@ -395,7 +398,7 @@ fn check_opaque_type_parameter_valid(
|
|||||||
seen_params.entry(arg).or_default().push(i);
|
seen_params.entry(arg).or_default().push(i);
|
||||||
} else {
|
} else {
|
||||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
let opaque_param = parent_generics.param_at(i, tcx);
|
||||||
let kind = opaque_param.kind.descr();
|
let kind = opaque_param.kind.descr();
|
||||||
|
|
||||||
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
|
||||||
@ -409,10 +412,10 @@ fn check_opaque_type_parameter_valid(
|
|||||||
|
|
||||||
for (_, indices) in seen_params {
|
for (_, indices) in seen_params {
|
||||||
if indices.len() > 1 {
|
if indices.len() > 1 {
|
||||||
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
|
let descr = parent_generics.param_at(indices[0], tcx).kind.descr();
|
||||||
let spans: Vec<_> = indices
|
let spans: Vec<_> = indices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
.map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id))
|
||||||
.collect();
|
.collect();
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
@ -1770,8 +1770,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
|
||||||
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { destination, unwind, .. } => {
|
TerminatorKind::InlineAsm { ref targets, unwind, .. } => {
|
||||||
if let Some(target) = destination {
|
for &target in targets {
|
||||||
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
self.assert_iscleanup(body, block_data, target, is_cleanup);
|
||||||
}
|
}
|
||||||
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
|
||||||
|
@ -19,6 +19,8 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
|
|||||||
|
|
||||||
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
|
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
|
||||||
|
|
||||||
|
builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
|
||||||
|
|
||||||
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
|
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
|
||||||
|
|
||||||
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
|
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
|
||||||
|
@ -164,6 +164,9 @@ pub fn parse_asm_args<'a>(
|
|||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
};
|
};
|
||||||
ast::InlineAsmOperand::Sym { sym }
|
ast::InlineAsmOperand::Sym { sym }
|
||||||
|
} else if !is_global_asm && p.eat_keyword(sym::label) {
|
||||||
|
let block = p.parse_block()?;
|
||||||
|
ast::InlineAsmOperand::Label { block }
|
||||||
} else if allow_templates {
|
} else if allow_templates {
|
||||||
let template = p.parse_expr()?;
|
let template = p.parse_expr()?;
|
||||||
// If it can't possibly expand to a string, provide diagnostics here to include other
|
// If it can't possibly expand to a string, provide diagnostics here to include other
|
||||||
@ -240,6 +243,7 @@ pub fn parse_asm_args<'a>(
|
|||||||
let mut have_real_output = false;
|
let mut have_real_output = false;
|
||||||
let mut outputs_sp = vec![];
|
let mut outputs_sp = vec![];
|
||||||
let mut regclass_outputs = vec![];
|
let mut regclass_outputs = vec![];
|
||||||
|
let mut labels_sp = vec![];
|
||||||
for (op, op_sp) in &args.operands {
|
for (op, op_sp) in &args.operands {
|
||||||
match op {
|
match op {
|
||||||
ast::InlineAsmOperand::Out { reg, expr, .. }
|
ast::InlineAsmOperand::Out { reg, expr, .. }
|
||||||
@ -257,6 +261,9 @@ pub fn parse_asm_args<'a>(
|
|||||||
regclass_outputs.push(*op_sp);
|
regclass_outputs.push(*op_sp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::InlineAsmOperand::Label { .. } => {
|
||||||
|
labels_sp.push(*op_sp);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,6 +275,9 @@ pub fn parse_asm_args<'a>(
|
|||||||
// Bail out now since this is likely to confuse MIR
|
// Bail out now since this is likely to confuse MIR
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
|
||||||
|
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
|
||||||
|
}
|
||||||
|
|
||||||
if args.clobber_abis.len() > 0 {
|
if args.clobber_abis.len() > 0 {
|
||||||
if is_global_asm {
|
if is_global_asm {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::mut_visit::MutVisitor;
|
use rustc_ast::mut_visit::MutVisitor;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
@ -87,41 +88,40 @@ fn flat_map_annotatable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CfgFinder {
|
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
||||||
has_cfg_or_cfg_attr: bool,
|
struct CfgFinder;
|
||||||
}
|
|
||||||
|
|
||||||
impl CfgFinder {
|
impl<'ast> visit::Visitor<'ast> for CfgFinder {
|
||||||
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
|
type Result = ControlFlow<()>;
|
||||||
let mut finder = CfgFinder { has_cfg_or_cfg_attr: false };
|
fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
|
||||||
match annotatable {
|
if attr
|
||||||
Annotatable::Item(item) => finder.visit_item(item),
|
|
||||||
Annotatable::TraitItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Trait),
|
|
||||||
Annotatable::ImplItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Impl),
|
|
||||||
Annotatable::ForeignItem(item) => finder.visit_foreign_item(item),
|
|
||||||
Annotatable::Stmt(stmt) => finder.visit_stmt(stmt),
|
|
||||||
Annotatable::Expr(expr) => finder.visit_expr(expr),
|
|
||||||
Annotatable::Arm(arm) => finder.visit_arm(arm),
|
|
||||||
Annotatable::ExprField(field) => finder.visit_expr_field(field),
|
|
||||||
Annotatable::PatField(field) => finder.visit_pat_field(field),
|
|
||||||
Annotatable::GenericParam(param) => finder.visit_generic_param(param),
|
|
||||||
Annotatable::Param(param) => finder.visit_param(param),
|
|
||||||
Annotatable::FieldDef(field) => finder.visit_field_def(field),
|
|
||||||
Annotatable::Variant(variant) => finder.visit_variant(variant),
|
|
||||||
Annotatable::Crate(krate) => finder.visit_crate(krate),
|
|
||||||
};
|
|
||||||
finder.has_cfg_or_cfg_attr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast> visit::Visitor<'ast> for CfgFinder {
|
|
||||||
fn visit_attribute(&mut self, attr: &'ast Attribute) {
|
|
||||||
// We want short-circuiting behavior, so don't use the '|=' operator.
|
|
||||||
self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
|
|
||||||
|| attr
|
|
||||||
.ident()
|
.ident()
|
||||||
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
|
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
|
||||||
|
{
|
||||||
|
ControlFlow::Break(())
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = match annotatable {
|
||||||
|
Annotatable::Item(item) => CfgFinder.visit_item(item),
|
||||||
|
Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait),
|
||||||
|
Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl),
|
||||||
|
Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
|
||||||
|
Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
|
||||||
|
Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
|
||||||
|
Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
|
||||||
|
Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
|
||||||
|
Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
|
||||||
|
Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
|
||||||
|
Annotatable::Param(param) => CfgFinder.visit_param(param),
|
||||||
|
Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
|
||||||
|
Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
|
||||||
|
Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
|
||||||
|
};
|
||||||
|
res.is_break()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgEval<'_, '_> {
|
impl CfgEval<'_, '_> {
|
||||||
@ -132,7 +132,7 @@ impl CfgEval<'_, '_> {
|
|||||||
fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
|
fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
|
||||||
// Tokenizing and re-parsing the `Annotatable` can have a significant
|
// Tokenizing and re-parsing the `Annotatable` can have a significant
|
||||||
// performance impact, so try to avoid it if possible
|
// performance impact, so try to avoid it if possible
|
||||||
if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) {
|
if !has_cfg_or_cfg_attr(&annotatable) {
|
||||||
return Some(annotatable);
|
return Some(annotatable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::deriving::generic::ty::*;
|
use crate::deriving::generic::ty::*;
|
||||||
use crate::deriving::generic::*;
|
use crate::deriving::generic::*;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::walk_list;
|
||||||
use rustc_ast::{attr, EnumDef, VariantData};
|
use rustc_ast::{attr, EnumDef, VariantData};
|
||||||
@ -231,20 +232,19 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_a_default_variant(item: &Annotatable) -> bool {
|
fn has_a_default_variant(item: &Annotatable) -> bool {
|
||||||
struct HasDefaultAttrOnVariant {
|
struct HasDefaultAttrOnVariant;
|
||||||
found: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
|
impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
|
||||||
fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
|
type Result = ControlFlow<()>;
|
||||||
|
fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) -> ControlFlow<()> {
|
||||||
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
||||||
self.found = true;
|
ControlFlow::Break(())
|
||||||
}
|
} else {
|
||||||
// no need to subrecurse.
|
// no need to subrecurse.
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = HasDefaultAttrOnVariant { found: false };
|
item.visit_with(&mut HasDefaultAttrOnVariant).is_break()
|
||||||
item.visit_with(&mut visitor);
|
|
||||||
visitor.found
|
|
||||||
}
|
}
|
||||||
|
@ -766,6 +766,13 @@ pub(crate) struct AsmNoReturn {
|
|||||||
pub(crate) outputs_sp: Vec<Span>,
|
pub(crate) outputs_sp: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(builtin_macros_asm_mayunwind)]
|
||||||
|
pub(crate) struct AsmMayUnwind {
|
||||||
|
#[primary_span]
|
||||||
|
pub(crate) labels_sp: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(builtin_macros_global_asm_clobber_abi)]
|
#[diag(builtin_macros_global_asm_clobber_abi)]
|
||||||
pub(crate) struct GlobalAsmClobberAbi {
|
pub(crate) struct GlobalAsmClobberAbi {
|
||||||
|
@ -44,9 +44,10 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
TARGET_TRIPLE: x86_64-apple-darwin
|
TARGET_TRIPLE: x86_64-apple-darwin
|
||||||
# cross-compile from Linux to Windows using mingw
|
# cross-compile from Linux to Windows using mingw
|
||||||
- os: ubuntu-latest
|
# FIXME The wine version in Ubuntu 22.04 is missing ProcessPrng
|
||||||
env:
|
#- os: ubuntu-latest
|
||||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
# env:
|
||||||
|
# TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
||||||
@ -80,11 +81,11 @@ jobs:
|
|||||||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||||
run: rustup set default-host x86_64-pc-windows-gnu
|
run: rustup set default-host x86_64-pc-windows-gnu
|
||||||
|
|
||||||
- name: Install MinGW toolchain and wine
|
#- name: Install MinGW toolchain and wine
|
||||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
# if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get update
|
# sudo apt-get update
|
||||||
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
# sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||||
|
|
||||||
- name: Install AArch64 toolchain and qemu
|
- name: Install AArch64 toolchain and qemu
|
||||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
|
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
|
||||||
|
23
compiler/rustc_codegen_cranelift/.gitignore
vendored
23
compiler/rustc_codegen_cranelift/.gitignore
vendored
@ -1,18 +1,21 @@
|
|||||||
/target
|
# Build artifacts during normal use
|
||||||
/build_system/target
|
|
||||||
**/*.rs.bk
|
|
||||||
*.rlib
|
|
||||||
*.o
|
|
||||||
perf.data
|
|
||||||
perf.data.old
|
|
||||||
*.events
|
|
||||||
*.string*
|
|
||||||
/y.bin
|
/y.bin
|
||||||
/y.bin.dSYM
|
/y.bin.dSYM
|
||||||
/y.exe
|
/y.exe
|
||||||
/y.pdb
|
/y.pdb
|
||||||
|
/download
|
||||||
/build
|
/build
|
||||||
/dist
|
/dist
|
||||||
|
/target
|
||||||
|
/build_system/target
|
||||||
|
|
||||||
|
# Downloaded by certain scripts
|
||||||
/rust
|
/rust
|
||||||
/download
|
|
||||||
/git-fixed-subtree.sh
|
/git-fixed-subtree.sh
|
||||||
|
|
||||||
|
# Various things that can be created during development
|
||||||
|
*.rlib
|
||||||
|
*.o
|
||||||
|
perf.data
|
||||||
|
perf.data.old
|
||||||
|
*.mm_profdata
|
||||||
|
@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-bforest"
|
name = "cranelift-bforest"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d819feeda4c420a18f1e28236ca0ce1177b22bf7c8a44ddee92dfe40de15bcf0"
|
checksum = "9515fcc42b6cb5137f76b84c1a6f819782d0cf12473d145d3bc5cd67eedc8bc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-entity",
|
"cranelift-entity",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen"
|
name = "cranelift-codegen"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9b8d03d5bdbca7e5f72b0e0a0f69933ed1f09e24be6c075aa6fe3f802b0cc0c"
|
checksum = "1ad827c6071bfe6d22de1bc331296a29f9ddc506ff926d8415b435ec6a6efce0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"cranelift-bforest",
|
"cranelift-bforest",
|
||||||
@ -76,39 +76,39 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen-meta"
|
name = "cranelift-codegen-meta"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3fd3664e38e51649b17dc30cfdd561273fe2f590dcd013fb75d9eabc6272dfb"
|
checksum = "10e6b36237a9ca2ce2fb4cc7741d418a080afa1327402138412ef85d5367bef1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen-shared",
|
"cranelift-codegen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-codegen-shared"
|
name = "cranelift-codegen-shared"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b031ec5e605828975952622b5a77d49126f20ffe88d33719a0af66b23a0fc36"
|
checksum = "c36bf4bfb86898a94ccfa773a1f86e8a5346b1983ff72059bdd2db4600325251"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-control"
|
name = "cranelift-control"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fada054d017cf2ed8f7ed2336e0517fc1b19e6825be1790de9eb00c94788362b"
|
checksum = "7cbf36560e7a6bd1409ca91e7b43b2cc7ed8429f343d7605eadf9046e8fac0d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-entity"
|
name = "cranelift-entity"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "177b6f94ae8de6348eb45bf977c79ab9e3c40fc3ac8cb7ed8109560ea39bee7d"
|
checksum = "a71e11061a75b1184c09bea97c026a88f08b59ade96a7bb1f259d4ea0df2e942"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-frontend"
|
name = "cranelift-frontend"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebebd23a69a23e3ddea78e98ff3a2de222e88c8e045d81ef4a72f042e0d79dbd"
|
checksum = "af5d4da63143ee3485c7bcedde0a818727d737d1083484a0ceedb8950c89e495"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"log",
|
"log",
|
||||||
@ -118,15 +118,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-isle"
|
name = "cranelift-isle"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1571bfc14df8966d12c6121b5325026591a4b4009e22fea0fe3765ab7cd33b96"
|
checksum = "457a9832b089e26f5eea70dcf49bed8ec6edafed630ce7c83161f24d46ab8085"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-jit"
|
name = "cranelift-jit"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f61e236d7622c3c43016e8b0f3ba27136e21ac7de328c7fda902e61db1de851"
|
checksum = "0af95fe68d5a10919012c8db82b1d59820405b8001c8c6d05f94b08031334fa9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
@ -144,9 +144,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-module"
|
name = "cranelift-module"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f30c6820342015c5009070e3e48d1da7b13521399de904663f1c84f5ee839657"
|
checksum = "11b0b201fa10a4014062d4c56c307c8d18fdf9a84cb5279efe6080241f42c7a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
@ -155,9 +155,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-native"
|
name = "cranelift-native"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35a69c37e0c10b46fe5527f2397ac821046efbf5f7ec112c8b84df25712f465b"
|
checksum = "9b490d579df1ce365e1ea359e24ed86d82289fa785153327c2f6a69a59a731e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
"libc",
|
"libc",
|
||||||
@ -166,9 +166,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cranelift-object"
|
name = "cranelift-object"
|
||||||
version = "0.104.0"
|
version = "0.105.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24425a329b4343177d5f1852243841dcec17f929d72c0e7f41262140155e55e7"
|
checksum = "fb7e821ac6db471bcdbd004e5a4fa0d374f1046bd3a2ce278c332e0b0c01ca63"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cranelift-codegen",
|
"cranelift-codegen",
|
||||||
@ -241,9 +241,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.148"
|
version = "0.2.153"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
@ -410,9 +410,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmtime-jit-icache-coherence"
|
name = "wasmtime-jit-icache-coherence"
|
||||||
version = "17.0.0"
|
version = "18.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bdc26415bb89e9ccd3bdc498fef63aabf665c4c0dd710c107691deb9694955da"
|
checksum = "33f4121cb29dda08139b2824a734dd095d83ce843f2d613a84eb580b9cfc17ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -8,12 +8,12 @@ crate-type = ["dylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# These have to be in sync with each other
|
# These have to be in sync with each other
|
||||||
cranelift-codegen = { version = "0.104", default-features = false, features = ["std", "unwind", "all-arch"] }
|
cranelift-codegen = { version = "0.105.2", default-features = false, features = ["std", "unwind", "all-arch"] }
|
||||||
cranelift-frontend = { version = "0.104" }
|
cranelift-frontend = { version = "0.105.2" }
|
||||||
cranelift-module = { version = "0.104" }
|
cranelift-module = { version = "0.105.2" }
|
||||||
cranelift-native = { version = "0.104" }
|
cranelift-native = { version = "0.105.2" }
|
||||||
cranelift-jit = { version = "0.104", optional = true }
|
cranelift-jit = { version = "0.105.2", optional = true }
|
||||||
cranelift-object = { version = "0.104" }
|
cranelift-object = { version = "0.105.2" }
|
||||||
target-lexicon = "0.12.0"
|
target-lexicon = "0.12.0"
|
||||||
gimli = { version = "0.28", default-features = false, features = ["write"]}
|
gimli = { version = "0.28", default-features = false, features = ["write"]}
|
||||||
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||||
|
@ -123,11 +123,6 @@ You need to do this steps to successfully compile and use the cranelift backend
|
|||||||
|
|
||||||
You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes.
|
You can also set `rust-analyzer.rustc.source` to your rust workspace to get rust-analyzer to understand your changes.
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
|
|
||||||
configuration options.
|
|
||||||
|
|
||||||
## Not yet supported
|
## Not yet supported
|
||||||
|
|
||||||
* SIMD ([tracked here](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
|
* SIMD ([tracked here](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
@ -71,7 +72,11 @@ fn hash_file(file: &std::path::Path) -> u64 {
|
|||||||
let contents = std::fs::read(file).unwrap();
|
let contents = std::fs::read(file).unwrap();
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let mut hasher = std::hash::SipHasher::new();
|
let mut hasher = std::hash::SipHasher::new();
|
||||||
std::hash::Hash::hash(&contents, &mut hasher);
|
// The following is equivalent to
|
||||||
|
// std::hash::Hash::hash(&contents, &mut hasher);
|
||||||
|
// but gives the same result independent of host byte order.
|
||||||
|
hasher.write_usize(contents.len().to_le());
|
||||||
|
Hash::hash_slice(&contents, &mut hasher);
|
||||||
std::hash::Hasher::finish(&hasher)
|
std::hash::Hasher::finish(&hasher)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,16 +85,26 @@ fn hash_dir(dir: &std::path::Path) -> u64 {
|
|||||||
for entry in std::fs::read_dir(dir).unwrap() {
|
for entry in std::fs::read_dir(dir).unwrap() {
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
if entry.file_type().unwrap().is_dir() {
|
if entry.file_type().unwrap().is_dir() {
|
||||||
sub_hashes
|
sub_hashes.insert(
|
||||||
.insert(entry.file_name().to_str().unwrap().to_owned(), hash_dir(&entry.path()));
|
entry.file_name().to_str().unwrap().to_owned(),
|
||||||
|
hash_dir(&entry.path()).to_le(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
sub_hashes
|
sub_hashes.insert(
|
||||||
.insert(entry.file_name().to_str().unwrap().to_owned(), hash_file(&entry.path()));
|
entry.file_name().to_str().unwrap().to_owned(),
|
||||||
|
hash_file(&entry.path()).to_le(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let mut hasher = std::hash::SipHasher::new();
|
let mut hasher = std::hash::SipHasher::new();
|
||||||
std::hash::Hash::hash(&sub_hashes, &mut hasher);
|
// The following is equivalent to
|
||||||
|
// std::hash::Hash::hash(&sub_hashes, &mut hasher);
|
||||||
|
// but gives the same result independent of host byte order.
|
||||||
|
hasher.write_usize(sub_hashes.len().to_le());
|
||||||
|
for elt in sub_hashes {
|
||||||
|
elt.hash(&mut hasher);
|
||||||
|
}
|
||||||
std::hash::Hasher::finish(&hasher)
|
std::hash::Hasher::finish(&hasher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +133,8 @@ pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir
|
|||||||
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
|
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
|
||||||
"rust-lang",
|
"rust-lang",
|
||||||
"portable-simd",
|
"portable-simd",
|
||||||
"97007cc2e70df8c97326ce896a79e2f0ce4dd98b",
|
"5794c837bc605c4cd9dbb884285976dfdb293cce",
|
||||||
"e54a16035cedf205",
|
"a64d8fdd0ed0d9c4",
|
||||||
"portable-simd",
|
"portable-simd",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -39,6 +39,6 @@ index 42a26ae..5ac1042 100644
|
|||||||
+#![cfg(test)]
|
+#![cfg(test)]
|
||||||
#![feature(alloc_layout_extra)]
|
#![feature(alloc_layout_extra)]
|
||||||
#![feature(array_chunks)]
|
#![feature(array_chunks)]
|
||||||
#![feature(array_methods)]
|
#![feature(array_windows)]
|
||||||
--
|
--
|
||||||
2.21.0 (Apple Git-122)
|
2.21.0 (Apple Git-122)
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001
|
|
||||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
|
||||||
Date: Sun, 24 Nov 2019 15:34:06 +0100
|
|
||||||
Subject: [PATCH] [core] Ignore failing tests
|
|
||||||
|
|
||||||
---
|
|
||||||
library/core/tests/iter.rs | 4 ++++
|
|
||||||
library/core/tests/num/bignum.rs | 10 ++++++++++
|
|
||||||
library/core/tests/num/mod.rs | 5 +++--
|
|
||||||
library/core/tests/time.rs | 1 +
|
|
||||||
4 files changed, 18 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/atomic.rs b/atomic.rs
|
|
||||||
index 13b12db..96fe4b9 100644
|
|
||||||
--- a/atomic.rs
|
|
||||||
+++ b/atomic.rs
|
|
||||||
@@ -185,6 +185,7 @@ fn ptr_bitops() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
+#[cfg_attr(target_arch = "s390x", ignore)] // s390x backend doesn't support stack alignment >8 bytes
|
|
||||||
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
|
|
||||||
fn ptr_bitops_tagging() {
|
|
||||||
#[repr(align(16))]
|
|
||||||
--
|
|
||||||
2.21.0 (Apple Git-122)
|
|
@ -150,9 +150,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.3"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"rustc-std-workspace-alloc",
|
"rustc-std-workspace-alloc",
|
||||||
@ -161,9 +161,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.150"
|
version = "0.2.153"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc-std-workspace-core",
|
"rustc-std-workspace-core",
|
||||||
]
|
]
|
||||||
@ -398,6 +398,7 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"core",
|
"core",
|
||||||
"getopts",
|
"getopts",
|
||||||
|
"libc",
|
||||||
"panic_abort",
|
"panic_abort",
|
||||||
"panic_unwind",
|
"panic_unwind",
|
||||||
"std",
|
"std",
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2024-01-26"
|
channel = "nightly-2024-03-08"
|
||||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
ignore = [
|
ignore = [
|
||||||
"y.rs",
|
|
||||||
"example/gen_block_iterate.rs", # uses edition 2024
|
"example/gen_block_iterate.rs", # uses edition 2024
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -10,12 +10,26 @@ pushd rust
|
|||||||
|
|
||||||
command -v rg >/dev/null 2>&1 || cargo install ripgrep
|
command -v rg >/dev/null 2>&1 || cargo install ripgrep
|
||||||
|
|
||||||
|
# FIXME(rust-lang/rust#122196) fix stage0 rmake.rs run-make tests and remove
|
||||||
|
# this workaround
|
||||||
|
for test in $(ls tests/run-make); do
|
||||||
|
if [[ -e "tests/run-make/$test/rmake.rs" ]]; then
|
||||||
|
rm -r "tests/run-make/$test"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# FIXME remove this workaround once ICE tests no longer emit an outdated nightly message
|
||||||
|
for test in $(rg -i --files-with-matches "//@(\[.*\])? failure-status: 101" tests/ui); do
|
||||||
|
echo "rm $test"
|
||||||
|
rm $test
|
||||||
|
done
|
||||||
|
|
||||||
rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
|
rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
|
||||||
for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
|
for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
|
||||||
rm $test
|
rm $test
|
||||||
done
|
done
|
||||||
|
|
||||||
for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do
|
for test in $(rg -i --files-with-matches "//(\[\w+\])?~[^\|]*\s*ERR|//@ error-pattern:|//@(\[.*\])? build-fail|//@(\[.*\])? run-fail|-Cllvm-args" tests/ui); do
|
||||||
rm $test
|
rm $test
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -43,8 +57,8 @@ rm tests/ui/proc-macro/allowed-signatures.rs
|
|||||||
rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
|
rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
|
||||||
|
|
||||||
# vendor intrinsics
|
# vendor intrinsics
|
||||||
rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented
|
|
||||||
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
|
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
|
||||||
|
rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
|
||||||
|
|
||||||
# exotic linkages
|
# exotic linkages
|
||||||
rm tests/ui/issues/issue-33992.rs # unsupported linkages
|
rm tests/ui/issues/issue-33992.rs # unsupported linkages
|
||||||
@ -62,14 +76,12 @@ rm -r tests/run-pass-valgrind/unsized-locals
|
|||||||
# misc unimplemented things
|
# misc unimplemented things
|
||||||
rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics
|
rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics
|
||||||
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
||||||
rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
|
|
||||||
rm -r tests/run-make/emit-named-files # requires full --emit support
|
rm -r tests/run-make/emit-named-files # requires full --emit support
|
||||||
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
||||||
rm -r tests/run-make/split-debuginfo # same
|
rm -r tests/run-make/split-debuginfo # same
|
||||||
rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
|
rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
|
||||||
rm -r tests/run-make/target-specs # i686 not supported by Cranelift
|
rm -r tests/run-make/target-specs # i686 not supported by Cranelift
|
||||||
rm -r tests/run-make/mismatching-target-triples # same
|
rm -r tests/run-make/mismatching-target-triples # same
|
||||||
rm tests/ui/asm/x86_64/issue-82869.rs # vector regs in inline asm not yet supported
|
|
||||||
rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
|
rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
|
||||||
|
|
||||||
# requires LTO
|
# requires LTO
|
||||||
@ -109,8 +121,6 @@ rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific
|
|||||||
rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
|
rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
|
||||||
rm tests/ui/mir/mir_raw_fat_ptr.rs # same
|
rm tests/ui/mir/mir_raw_fat_ptr.rs # same
|
||||||
rm tests/ui/consts/issue-33537.rs # same
|
rm tests/ui/consts/issue-33537.rs # same
|
||||||
rm tests/ui/layout/valid_range_oob.rs # different ICE message
|
|
||||||
rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif
|
|
||||||
|
|
||||||
# rustdoc-clif passes extra args, suppressing the help message when no args are passed
|
# rustdoc-clif passes extra args, suppressing the help message when no args are passed
|
||||||
rm -r tests/run-make/issue-88756-default-output
|
rm -r tests/run-make/issue-88756-default-output
|
||||||
@ -119,15 +129,12 @@ rm -r tests/run-make/issue-88756-default-output
|
|||||||
# should work when using ./x.py test the way it is intended
|
# should work when using ./x.py test the way it is intended
|
||||||
# ============================================================
|
# ============================================================
|
||||||
rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
|
rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
|
||||||
rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
|
|
||||||
|
|
||||||
# genuine bugs
|
# genuine bugs
|
||||||
# ============
|
# ============
|
||||||
rm tests/incremental/spike-neg1.rs # errors out for some reason
|
rm tests/incremental/spike-neg1.rs # errors out for some reason
|
||||||
rm tests/incremental/spike-neg2.rs # same
|
rm tests/incremental/spike-neg2.rs # same
|
||||||
|
|
||||||
rm tests/ui/simd/simd-bitmask.rs # simd_bitmask doesn't implement [u*; N] return type
|
|
||||||
|
|
||||||
rm -r tests/run-make/issue-51671 # wrong filename given in case of --emit=obj
|
rm -r tests/run-make/issue-51671 # wrong filename given in case of --emit=obj
|
||||||
rm -r tests/run-make/issue-30063 # same
|
rm -r tests/run-make/issue-30063 # same
|
||||||
rm -r tests/run-make/multiple-emits # same
|
rm -r tests/run-make/multiple-emits # same
|
||||||
@ -145,6 +152,7 @@ rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug
|
|||||||
# ======================
|
# ======================
|
||||||
rm tests/ui/backtrace.rs # TODO warning
|
rm tests/ui/backtrace.rs # TODO warning
|
||||||
rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
|
rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
|
||||||
|
rm tests/ui/async-await/async-closures/once.rs # FIXME bug in the rustc FnAbi calculation code
|
||||||
|
|
||||||
rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
|
rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
|
||||||
|
|
||||||
|
@ -445,7 +445,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||||||
template,
|
template,
|
||||||
operands,
|
operands,
|
||||||
options,
|
options,
|
||||||
destination,
|
targets,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
@ -456,13 +456,25 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let have_labels = if options.contains(InlineAsmOptions::NORETURN) {
|
||||||
|
!targets.is_empty()
|
||||||
|
} else {
|
||||||
|
targets.len() > 1
|
||||||
|
};
|
||||||
|
if have_labels {
|
||||||
|
fx.tcx.dcx().span_fatal(
|
||||||
|
source_info.span,
|
||||||
|
"cranelift doesn't support labels in inline assembly.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
crate::inline_asm::codegen_inline_asm_terminator(
|
crate::inline_asm::codegen_inline_asm_terminator(
|
||||||
fx,
|
fx,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
template,
|
template,
|
||||||
operands,
|
operands,
|
||||||
*options,
|
*options,
|
||||||
*destination,
|
targets.get(0).copied(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
TerminatorKind::UnwindTerminate(reason) => {
|
TerminatorKind::UnwindTerminate(reason) => {
|
||||||
|
@ -392,18 +392,25 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer {
|
pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer {
|
||||||
if align <= 16 {
|
let abi_align = if self.tcx.sess.target.arch == "s390x" { 8 } else { 16 };
|
||||||
|
if align <= abi_align {
|
||||||
let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
|
let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
|
||||||
kind: StackSlotKind::ExplicitSlot,
|
kind: StackSlotKind::ExplicitSlot,
|
||||||
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
|
// FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets
|
||||||
// specify stack slot alignment.
|
// a way to specify stack slot alignment.
|
||||||
size: (size + 15) / 16 * 16,
|
size: (size + abi_align - 1) / abi_align * abi_align,
|
||||||
});
|
});
|
||||||
Pointer::stack_slot(stack_slot)
|
Pointer::stack_slot(stack_slot)
|
||||||
} else {
|
} else {
|
||||||
// Alignment is too big to handle using the above hack. Dynamically realign a stack slot
|
// Alignment is too big to handle using the above hack. Dynamically realign a stack slot
|
||||||
// instead. This wastes some space for the realignment.
|
// instead. This wastes some space for the realignment.
|
||||||
let base_ptr = self.create_stack_slot(size + align, 16).get_addr(self);
|
let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
|
||||||
|
kind: StackSlotKind::ExplicitSlot,
|
||||||
|
// FIXME Don't force the size to a multiple of <abi_align> bytes once Cranelift gets
|
||||||
|
// a way to specify stack slot alignment.
|
||||||
|
size: (size + align) / abi_align * abi_align,
|
||||||
|
});
|
||||||
|
let base_ptr = self.bcx.ins().stack_addr(self.pointer_type, stack_slot, 0);
|
||||||
let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));
|
let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));
|
||||||
let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align));
|
let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align));
|
||||||
Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset))
|
Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset))
|
||||||
|
@ -372,7 +372,13 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
|
let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
|
||||||
|
if bytes.is_empty() {
|
||||||
|
// FIXME(bytecodealliance/wasmtime#7918) cranelift-jit has a bug where it causes UB on
|
||||||
|
// empty data objects
|
||||||
|
data.define(Box::new([0]));
|
||||||
|
} else {
|
||||||
data.define(bytes.into_boxed_slice());
|
data.define(bytes.into_boxed_slice());
|
||||||
|
}
|
||||||
|
|
||||||
for &(offset, prov) in alloc.provenance().ptrs().iter() {
|
for &(offset, prov) in alloc.provenance().ptrs().iter() {
|
||||||
let alloc_id = prov.alloc_id();
|
let alloc_id = prov.alloc_id();
|
||||||
|
@ -78,7 +78,8 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
|
|||||||
InlineAsmOperand::In { .. }
|
InlineAsmOperand::In { .. }
|
||||||
| InlineAsmOperand::Out { .. }
|
| InlineAsmOperand::Out { .. }
|
||||||
| InlineAsmOperand::InOut { .. }
|
| InlineAsmOperand::InOut { .. }
|
||||||
| InlineAsmOperand::SplitInOut { .. } => {
|
| InlineAsmOperand::SplitInOut { .. }
|
||||||
|
| InlineAsmOperand::Label { .. } => {
|
||||||
span_bug!(op_sp, "invalid operand type for global_asm!")
|
span_bug!(op_sp, "invalid operand type for global_asm!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,9 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
|
|||||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||||
CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() }
|
CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() }
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::Label { .. } => {
|
||||||
|
span_bug!(span, "asm! label operands are not yet supported");
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -170,6 +170,65 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sse.add.ss" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_ss&ig_expand=171
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
assert_eq!(a.layout(), b.layout());
|
||||||
|
assert_eq!(a.layout(), ret.layout());
|
||||||
|
let layout = a.layout();
|
||||||
|
|
||||||
|
let (_, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
|
||||||
|
assert!(lane_ty.is_floating_point());
|
||||||
|
let ret_lane_layout = fx.layout_of(lane_ty);
|
||||||
|
|
||||||
|
ret.write_cvalue(fx, a);
|
||||||
|
|
||||||
|
let a_lane = a.value_lane(fx, 0).load_scalar(fx);
|
||||||
|
let b_lane = b.value_lane(fx, 0).load_scalar(fx);
|
||||||
|
|
||||||
|
let res = fx.bcx.ins().fadd(a_lane, b_lane);
|
||||||
|
|
||||||
|
let res_lane = CValue::by_val(res, ret_lane_layout);
|
||||||
|
ret.place_lane(fx, 0).write_cvalue(fx, res_lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sse.sqrt.ps" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sqrt_ps&ig_expand=6245
|
||||||
|
intrinsic_args!(fx, args => (a); intrinsic);
|
||||||
|
|
||||||
|
// FIXME use vector instructions when possible
|
||||||
|
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
|
||||||
|
fx.bcx.ins().sqrt(lane)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sse.max.ps" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_ps&ig_expand=4357
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
simd_pair_for_each_lane(
|
||||||
|
fx,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
ret,
|
||||||
|
&|fx, _lane_ty, _res_lane_ty, a_lane, b_lane| fx.bcx.ins().fmax(a_lane, b_lane),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sse.min.ps" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_ps&ig_expand=4489
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
simd_pair_for_each_lane(
|
||||||
|
fx,
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
ret,
|
||||||
|
&|fx, _lane_ty, _res_lane_ty, a_lane, b_lane| fx.bcx.ins().fmin(a_lane, b_lane),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
"llvm.x86.sse.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
|
"llvm.x86.sse.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
|
||||||
let (x, y, kind) = match args {
|
let (x, y, kind) = match args {
|
||||||
[x, y, kind] => (x, y, kind),
|
[x, y, kind] => (x, y, kind),
|
||||||
@ -1067,6 +1126,122 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sha1rnds4" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha1rnds4_epu32&ig_expand=5877
|
||||||
|
intrinsic_args!(fx, args => (a, b, _func); intrinsic);
|
||||||
|
|
||||||
|
let a = a.load_scalar(fx);
|
||||||
|
let b = b.load_scalar(fx);
|
||||||
|
|
||||||
|
let func = if let Some(func) =
|
||||||
|
crate::constant::mir_operand_get_const_val(fx, &args[2].node)
|
||||||
|
{
|
||||||
|
func
|
||||||
|
} else {
|
||||||
|
fx.tcx
|
||||||
|
.dcx()
|
||||||
|
.span_fatal(span, "Func argument for `_mm_sha1rnds4_epu32` is not a constant");
|
||||||
|
};
|
||||||
|
|
||||||
|
let func = func.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", func));
|
||||||
|
|
||||||
|
codegen_inline_asm_inner(
|
||||||
|
fx,
|
||||||
|
&[InlineAsmTemplatePiece::String(format!("sha1rnds4 xmm1, xmm2, {func}"))],
|
||||||
|
&[
|
||||||
|
CInlineAsmOperand::InOut {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||||
|
_late: true,
|
||||||
|
in_value: a,
|
||||||
|
out_place: Some(ret),
|
||||||
|
},
|
||||||
|
CInlineAsmOperand::In {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||||
|
value: b,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sha1msg1" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha1msg1_epu32&ig_expand=5874
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
let a = a.load_scalar(fx);
|
||||||
|
let b = b.load_scalar(fx);
|
||||||
|
|
||||||
|
codegen_inline_asm_inner(
|
||||||
|
fx,
|
||||||
|
&[InlineAsmTemplatePiece::String("sha1msg1 xmm1, xmm2".to_string())],
|
||||||
|
&[
|
||||||
|
CInlineAsmOperand::InOut {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||||
|
_late: true,
|
||||||
|
in_value: a,
|
||||||
|
out_place: Some(ret),
|
||||||
|
},
|
||||||
|
CInlineAsmOperand::In {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||||
|
value: b,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sha1msg2" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha1msg2_epu32&ig_expand=5875
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
let a = a.load_scalar(fx);
|
||||||
|
let b = b.load_scalar(fx);
|
||||||
|
|
||||||
|
codegen_inline_asm_inner(
|
||||||
|
fx,
|
||||||
|
&[InlineAsmTemplatePiece::String("sha1msg2 xmm1, xmm2".to_string())],
|
||||||
|
&[
|
||||||
|
CInlineAsmOperand::InOut {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||||
|
_late: true,
|
||||||
|
in_value: a,
|
||||||
|
out_place: Some(ret),
|
||||||
|
},
|
||||||
|
CInlineAsmOperand::In {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||||
|
value: b,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
"llvm.x86.sha1nexte" => {
|
||||||
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha1nexte_epu32&ig_expand=5876
|
||||||
|
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||||
|
|
||||||
|
let a = a.load_scalar(fx);
|
||||||
|
let b = b.load_scalar(fx);
|
||||||
|
|
||||||
|
codegen_inline_asm_inner(
|
||||||
|
fx,
|
||||||
|
&[InlineAsmTemplatePiece::String("sha1nexte xmm1, xmm2".to_string())],
|
||||||
|
&[
|
||||||
|
CInlineAsmOperand::InOut {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||||
|
_late: true,
|
||||||
|
in_value: a,
|
||||||
|
out_place: Some(ret),
|
||||||
|
},
|
||||||
|
CInlineAsmOperand::In {
|
||||||
|
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||||
|
value: b,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
"llvm.x86.sha256rnds2" => {
|
"llvm.x86.sha256rnds2" => {
|
||||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256rnds2_epu32&ig_expand=5977
|
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256rnds2_epu32&ig_expand=5977
|
||||||
intrinsic_args!(fx, args => (a, b, k); intrinsic);
|
intrinsic_args!(fx, args => (a, b, k); intrinsic);
|
||||||
|
@ -391,12 +391,15 @@ fn codegen_float_intrinsic_call<'tcx>(
|
|||||||
| sym::ceilf32
|
| sym::ceilf32
|
||||||
| sym::ceilf64
|
| sym::ceilf64
|
||||||
| sym::truncf32
|
| sym::truncf32
|
||||||
| sym::truncf64 => {
|
| sym::truncf64
|
||||||
|
| sym::sqrtf32
|
||||||
|
| sym::sqrtf64 => {
|
||||||
let val = match intrinsic {
|
let val = match intrinsic {
|
||||||
sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]),
|
sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]),
|
||||||
sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]),
|
sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]),
|
||||||
sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]),
|
sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]),
|
||||||
sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]),
|
sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]),
|
||||||
|
sym::sqrtf32 | sym::sqrtf64 => fx.bcx.ins().sqrt(args[0]),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -853,7 +853,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
for lane in 0..lane_count {
|
for lane in 0..lane_count {
|
||||||
let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(lane) as i64);
|
// The bit order of the mask depends on the byte endianness, LSB-first for
|
||||||
|
// little endian and MSB-first for big endian.
|
||||||
|
let mask_lane = match fx.tcx.sess.target.endian {
|
||||||
|
Endian::Big => lane_count - 1 - lane,
|
||||||
|
Endian::Little => lane,
|
||||||
|
};
|
||||||
|
let m_lane = fx.bcx.ins().ushr_imm(m, u64::from(mask_lane) as i64);
|
||||||
let m_lane = fx.bcx.ins().band_imm(m_lane, 1);
|
let m_lane = fx.bcx.ins().band_imm(m_lane, 1);
|
||||||
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
|
let a_lane = a.value_lane(fx, lane).load_scalar(fx);
|
||||||
let b_lane = b.value_lane(fx, lane).load_scalar(fx);
|
let b_lane = b.value_lane(fx, lane).load_scalar(fx);
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#![deny(unsafe_code)] /*This line is ignored by bash
|
|
||||||
# This block is ignored by rustc
|
|
||||||
echo "Warning: y.rs is a deprecated alias for y.sh" 1>&2
|
|
||||||
exec ./y.sh "$@"
|
|
||||||
*/
|
|
@ -107,7 +107,7 @@ enum ConstraintOrRegister {
|
|||||||
|
|
||||||
|
|
||||||
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||||
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
|
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, dest: Option<Self::BasicBlock>, _catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>) {
|
||||||
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||||
self.sess().dcx()
|
self.sess().dcx()
|
||||||
.create_err(UnwindingInlineAsm { span: span[0] })
|
.create_err(UnwindingInlineAsm { span: span[0] })
|
||||||
@ -126,6 +126,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
// added to `outputs.len()`
|
// added to `outputs.len()`
|
||||||
let mut inputs = vec![];
|
let mut inputs = vec![];
|
||||||
|
|
||||||
|
// GCC index of a label equals its position in the array added to
|
||||||
|
// `outputs.len() + inputs.len()`.
|
||||||
|
let mut labels = vec![];
|
||||||
|
|
||||||
// Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
|
// Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
|
||||||
let mut clobbers = vec![];
|
let mut clobbers = vec![];
|
||||||
|
|
||||||
@ -269,6 +273,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
// some targets to add a leading underscore (Mach-O).
|
// some targets to add a leading underscore (Mach-O).
|
||||||
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
|
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InlineAsmOperandRef::Label { label } => {
|
||||||
|
labels.push(label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +376,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
InlineAsmOperandRef::Const { .. } => {
|
InlineAsmOperandRef::Const { .. } => {
|
||||||
// processed in the previous pass
|
// processed in the previous pass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InlineAsmOperandRef::Label { .. } => {
|
||||||
|
// processed in the previous pass
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,6 +466,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
InlineAsmOperandRef::Const { ref string } => {
|
InlineAsmOperandRef::Const { ref string } => {
|
||||||
template_str.push_str(string);
|
template_str.push_str(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InlineAsmOperandRef::Label { label } => {
|
||||||
|
let label_gcc_index = labels.iter()
|
||||||
|
.position(|&l| l == label)
|
||||||
|
.expect("wrong rust index");
|
||||||
|
let gcc_index = label_gcc_index + outputs.len() + inputs.len();
|
||||||
|
push_to_template(Some('l'), gcc_index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -466,7 +486,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
// 4. Generate Extended Asm block
|
// 4. Generate Extended Asm block
|
||||||
|
|
||||||
let block = self.llbb();
|
let block = self.llbb();
|
||||||
let extended_asm = block.add_extended_asm(None, &template_str);
|
let extended_asm = if let Some(dest) = dest {
|
||||||
|
assert!(!labels.is_empty());
|
||||||
|
block.end_with_extended_asm_goto(None, &template_str, &labels, Some(dest))
|
||||||
|
} else {
|
||||||
|
block.add_extended_asm(None, &template_str)
|
||||||
|
};
|
||||||
|
|
||||||
for op in &outputs {
|
for op in &outputs {
|
||||||
extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
|
extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
|
||||||
@ -494,7 +519,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
if !options.contains(InlineAsmOptions::NOSTACK) {
|
if !options.contains(InlineAsmOptions::NOSTACK) {
|
||||||
// TODO(@Commeownist): figure out how to align stack
|
// TODO(@Commeownist): figure out how to align stack
|
||||||
}
|
}
|
||||||
if options.contains(InlineAsmOptions::NORETURN) {
|
if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) {
|
||||||
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
|
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
|
||||||
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
|
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
|
||||||
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
|
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
|
||||||
|
@ -28,7 +28,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
options: InlineAsmOptions,
|
options: InlineAsmOptions,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
|
dest: Option<Self::BasicBlock>,
|
||||||
|
catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
|
||||||
) {
|
) {
|
||||||
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
let asm_arch = self.tcx.sess.asm_arch.unwrap();
|
||||||
|
|
||||||
@ -165,6 +166,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the template string
|
// Build the template string
|
||||||
|
let mut labels = vec![];
|
||||||
let mut template_str = String::new();
|
let mut template_str = String::new();
|
||||||
for piece in template {
|
for piece in template {
|
||||||
match *piece {
|
match *piece {
|
||||||
@ -205,6 +207,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
// Only emit the raw symbol name
|
// Only emit the raw symbol name
|
||||||
template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx]));
|
template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx]));
|
||||||
}
|
}
|
||||||
|
InlineAsmOperandRef::Label { label } => {
|
||||||
|
template_str.push_str(&format!("${{{}:l}}", constraints.len()));
|
||||||
|
constraints.push("!i".to_owned());
|
||||||
|
labels.push(label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,12 +299,14 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
&constraints.join(","),
|
&constraints.join(","),
|
||||||
&inputs,
|
&inputs,
|
||||||
output_type,
|
output_type,
|
||||||
|
&labels,
|
||||||
volatile,
|
volatile,
|
||||||
alignstack,
|
alignstack,
|
||||||
dialect,
|
dialect,
|
||||||
line_spans,
|
line_spans,
|
||||||
options.contains(InlineAsmOptions::MAY_UNWIND),
|
options.contains(InlineAsmOptions::MAY_UNWIND),
|
||||||
dest_catch_funclet,
|
dest,
|
||||||
|
catch_funclet,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
|
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
|
||||||
|
|
||||||
@ -317,7 +326,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
|
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
|
||||||
|
|
||||||
// Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
|
// Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
|
||||||
if let Some((dest, _, _)) = dest_catch_funclet {
|
if let Some(dest) = dest {
|
||||||
self.switch_to_block(dest);
|
self.switch_to_block(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,16 +424,14 @@ pub(crate) fn inline_asm_call<'ll>(
|
|||||||
cons: &str,
|
cons: &str,
|
||||||
inputs: &[&'ll Value],
|
inputs: &[&'ll Value],
|
||||||
output: &'ll llvm::Type,
|
output: &'ll llvm::Type,
|
||||||
|
labels: &[&'ll llvm::BasicBlock],
|
||||||
volatile: bool,
|
volatile: bool,
|
||||||
alignstack: bool,
|
alignstack: bool,
|
||||||
dia: llvm::AsmDialect,
|
dia: llvm::AsmDialect,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
unwind: bool,
|
unwind: bool,
|
||||||
dest_catch_funclet: Option<(
|
dest: Option<&'ll llvm::BasicBlock>,
|
||||||
&'ll llvm::BasicBlock,
|
catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>,
|
||||||
&'ll llvm::BasicBlock,
|
|
||||||
Option<&Funclet<'ll>>,
|
|
||||||
)>,
|
|
||||||
) -> Option<&'ll Value> {
|
) -> Option<&'ll Value> {
|
||||||
let volatile = if volatile { llvm::True } else { llvm::False };
|
let volatile = if volatile { llvm::True } else { llvm::False };
|
||||||
let alignstack = if alignstack { llvm::True } else { llvm::False };
|
let alignstack = if alignstack { llvm::True } else { llvm::False };
|
||||||
@ -457,8 +464,11 @@ pub(crate) fn inline_asm_call<'ll>(
|
|||||||
can_throw,
|
can_throw,
|
||||||
);
|
);
|
||||||
|
|
||||||
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
|
let call = if !labels.is_empty() {
|
||||||
bx.invoke(fty, None, None, v, inputs, dest, catch, funclet)
|
assert!(catch_funclet.is_none());
|
||||||
|
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None)
|
||||||
|
} else if let Some((catch, funclet)) = catch_funclet {
|
||||||
|
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet)
|
||||||
} else {
|
} else {
|
||||||
bx.call(fty, None, None, v, inputs, None)
|
bx.call(fty, None, None, v, inputs, None)
|
||||||
};
|
};
|
||||||
|
@ -1538,6 +1538,58 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn callbr(
|
||||||
|
&mut self,
|
||||||
|
llty: &'ll Type,
|
||||||
|
fn_attrs: Option<&CodegenFnAttrs>,
|
||||||
|
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||||
|
llfn: &'ll Value,
|
||||||
|
args: &[&'ll Value],
|
||||||
|
default_dest: &'ll BasicBlock,
|
||||||
|
indirect_dest: &[&'ll BasicBlock],
|
||||||
|
funclet: Option<&Funclet<'ll>>,
|
||||||
|
) -> &'ll Value {
|
||||||
|
debug!("invoke {:?} with args ({:?})", llfn, args);
|
||||||
|
|
||||||
|
let args = self.check_call("callbr", llty, llfn, args);
|
||||||
|
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
|
||||||
|
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
|
||||||
|
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
|
||||||
|
if let Some(funclet_bundle) = funclet_bundle {
|
||||||
|
bundles.push(funclet_bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit CFI pointer type membership test
|
||||||
|
self.cfi_type_test(fn_attrs, fn_abi, llfn);
|
||||||
|
|
||||||
|
// Emit KCFI operand bundle
|
||||||
|
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
|
||||||
|
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
|
||||||
|
if let Some(kcfi_bundle) = kcfi_bundle {
|
||||||
|
bundles.push(kcfi_bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let callbr = unsafe {
|
||||||
|
llvm::LLVMRustBuildCallBr(
|
||||||
|
self.llbuilder,
|
||||||
|
llty,
|
||||||
|
llfn,
|
||||||
|
default_dest,
|
||||||
|
indirect_dest.as_ptr(),
|
||||||
|
indirect_dest.len() as c_uint,
|
||||||
|
args.as_ptr(),
|
||||||
|
args.len() as c_uint,
|
||||||
|
bundles.as_ptr(),
|
||||||
|
bundles.len() as c_uint,
|
||||||
|
UNNAMED,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if let Some(fn_abi) = fn_abi {
|
||||||
|
fn_abi.apply_attrs_callsite(self, callbr);
|
||||||
|
}
|
||||||
|
callbr
|
||||||
|
}
|
||||||
|
|
||||||
// Emits CFI pointer type membership tests.
|
// Emits CFI pointer type membership tests.
|
||||||
fn cfi_type_test(
|
fn cfi_type_test(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -260,35 +260,29 @@ pub unsafe fn create_module<'ll>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
||||||
let behavior = if llvm_version >= (15, 0, 0) {
|
|
||||||
llvm::LLVMModFlagBehavior::Min
|
|
||||||
} else {
|
|
||||||
llvm::LLVMModFlagBehavior::Error
|
|
||||||
};
|
|
||||||
|
|
||||||
if sess.target.arch == "aarch64" {
|
if sess.target.arch == "aarch64" {
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
behavior,
|
llvm::LLVMModFlagBehavior::Min,
|
||||||
c"branch-target-enforcement".as_ptr().cast(),
|
c"branch-target-enforcement".as_ptr().cast(),
|
||||||
bti.into(),
|
bti.into(),
|
||||||
);
|
);
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
behavior,
|
llvm::LLVMModFlagBehavior::Min,
|
||||||
c"sign-return-address".as_ptr().cast(),
|
c"sign-return-address".as_ptr().cast(),
|
||||||
pac_ret.is_some().into(),
|
pac_ret.is_some().into(),
|
||||||
);
|
);
|
||||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
behavior,
|
llvm::LLVMModFlagBehavior::Min,
|
||||||
c"sign-return-address-all".as_ptr().cast(),
|
c"sign-return-address-all".as_ptr().cast(),
|
||||||
pac_opts.leaf.into(),
|
pac_opts.leaf.into(),
|
||||||
);
|
);
|
||||||
llvm::LLVMRustAddModuleFlag(
|
llvm::LLVMRustAddModuleFlag(
|
||||||
llmod,
|
llmod,
|
||||||
behavior,
|
llvm::LLVMModFlagBehavior::Min,
|
||||||
c"sign-return-address-with-bkey".as_ptr().cast(),
|
c"sign-return-address-with-bkey".as_ptr().cast(),
|
||||||
u32::from(pac_opts.key == PAuthKey::B),
|
u32::from(pac_opts.key == PAuthKey::B),
|
||||||
);
|
);
|
||||||
|
@ -448,12 +448,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
constraint,
|
constraint,
|
||||||
inputs,
|
inputs,
|
||||||
self.type_void(),
|
self.type_void(),
|
||||||
|
&[],
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
llvm::AsmDialect::Att,
|
llvm::AsmDialect::Att,
|
||||||
&[span],
|
&[span],
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
|
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
|
||||||
|
|
||||||
|
@ -1616,6 +1616,20 @@ extern "C" {
|
|||||||
Name: *const c_char,
|
Name: *const c_char,
|
||||||
) -> &'a Value;
|
) -> &'a Value;
|
||||||
|
|
||||||
|
pub fn LLVMRustBuildCallBr<'a>(
|
||||||
|
B: &Builder<'a>,
|
||||||
|
Ty: &'a Type,
|
||||||
|
Fn: &'a Value,
|
||||||
|
DefaultDest: &'a BasicBlock,
|
||||||
|
IndirectDests: *const &'a BasicBlock,
|
||||||
|
NumIndirectDests: c_uint,
|
||||||
|
Args: *const &'a Value,
|
||||||
|
NumArgs: c_uint,
|
||||||
|
OpBundles: *const &OperandBundleDef<'a>,
|
||||||
|
NumOpBundles: c_uint,
|
||||||
|
Name: *const c_char,
|
||||||
|
) -> &'a Value;
|
||||||
|
|
||||||
pub fn LLVMRustSetFastMath(Instr: &Value);
|
pub fn LLVMRustSetFastMath(Instr: &Value);
|
||||||
pub fn LLVMRustSetAlgebraicMath(Instr: &Value);
|
pub fn LLVMRustSetAlgebraicMath(Instr: &Value);
|
||||||
pub fn LLVMRustSetAllowReassoc(Instr: &Value);
|
pub fn LLVMRustSetAllowReassoc(Instr: &Value);
|
||||||
|
@ -510,11 +510,13 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
// Params for UEFI
|
// Params for UEFI
|
||||||
let param_handle = bx.get_param(0);
|
let param_handle = bx.get_param(0);
|
||||||
let param_system_table = bx.get_param(1);
|
let param_system_table = bx.get_param(1);
|
||||||
|
let ptr_size = bx.tcx().data_layout.pointer_size;
|
||||||
|
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||||
let arg_argc = bx.const_int(cx.type_isize(), 2);
|
let arg_argc = bx.const_int(cx.type_isize(), 2);
|
||||||
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), Align::ONE);
|
let arg_argv = bx.alloca(cx.type_array(cx.type_ptr(), 2), ptr_align);
|
||||||
bx.store(param_handle, arg_argv, Align::ONE);
|
bx.store(param_handle, arg_argv, ptr_align);
|
||||||
let arg_argv_el1 = bx.gep(cx.type_ptr(), arg_argv, &[bx.const_int(cx.type_int(), 1)]);
|
let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes()));
|
||||||
bx.store(param_system_table, arg_argv_el1, Align::ONE);
|
bx.store(param_system_table, arg_argv_el1, ptr_align);
|
||||||
(arg_argc, arg_argv)
|
(arg_argc, arg_argv)
|
||||||
} else if cx.sess().target.main_needs_argc_argv {
|
} else if cx.sess().target.main_needs_argc_argv {
|
||||||
// Params from native `main()` used as args for rust start function
|
// Params from native `main()` used as args for rust start function
|
||||||
|
@ -264,7 +264,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||||||
mir::UnwindAction::Unreachable => None,
|
mir::UnwindAction::Unreachable => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(cleanup) = unwind_target {
|
if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) {
|
||||||
|
assert!(unwind_target.is_none());
|
||||||
let ret_llbb = if let Some(target) = destination {
|
let ret_llbb = if let Some(target) = destination {
|
||||||
fx.llbb(target)
|
fx.llbb(target)
|
||||||
} else {
|
} else {
|
||||||
@ -277,11 +278,29 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
instance,
|
instance,
|
||||||
Some((ret_llbb, cleanup, self.funclet(fx))),
|
Some(ret_llbb),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
MergingSucc::False
|
||||||
|
} else if let Some(cleanup) = unwind_target {
|
||||||
|
let ret_llbb = if let Some(target) = destination {
|
||||||
|
fx.llbb(target)
|
||||||
|
} else {
|
||||||
|
fx.unreachable_block()
|
||||||
|
};
|
||||||
|
|
||||||
|
bx.codegen_inline_asm(
|
||||||
|
template,
|
||||||
|
operands,
|
||||||
|
options,
|
||||||
|
line_spans,
|
||||||
|
instance,
|
||||||
|
Some(ret_llbb),
|
||||||
|
Some((cleanup, self.funclet(fx))),
|
||||||
);
|
);
|
||||||
MergingSucc::False
|
MergingSucc::False
|
||||||
} else {
|
} else {
|
||||||
bx.codegen_inline_asm(template, operands, options, line_spans, instance, None);
|
bx.codegen_inline_asm(template, operands, options, line_spans, instance, None, None);
|
||||||
|
|
||||||
if let Some(target) = destination {
|
if let Some(target) = destination {
|
||||||
self.funclet_br(fx, bx, target, mergeable_succ)
|
self.funclet_br(fx, bx, target, mergeable_succ)
|
||||||
@ -1100,7 +1119,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
operands: &[mir::InlineAsmOperand<'tcx>],
|
operands: &[mir::InlineAsmOperand<'tcx>],
|
||||||
options: ast::InlineAsmOptions,
|
options: ast::InlineAsmOptions,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
destination: Option<mir::BasicBlock>,
|
targets: &[mir::BasicBlock],
|
||||||
unwind: mir::UnwindAction,
|
unwind: mir::UnwindAction,
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
mergeable_succ: bool,
|
mergeable_succ: bool,
|
||||||
@ -1152,6 +1171,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
mir::InlineAsmOperand::SymStatic { def_id } => {
|
mir::InlineAsmOperand::SymStatic { def_id } => {
|
||||||
InlineAsmOperandRef::SymStatic { def_id }
|
InlineAsmOperandRef::SymStatic { def_id }
|
||||||
}
|
}
|
||||||
|
mir::InlineAsmOperand::Label { target_index } => {
|
||||||
|
InlineAsmOperandRef::Label { label: self.llbb(targets[target_index]) }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -1162,7 +1184,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
&operands,
|
&operands,
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
if options.contains(InlineAsmOptions::NORETURN) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
targets.get(0).copied()
|
||||||
|
},
|
||||||
unwind,
|
unwind,
|
||||||
instance,
|
instance,
|
||||||
mergeable_succ,
|
mergeable_succ,
|
||||||
@ -1318,7 +1344,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
ref operands,
|
ref operands,
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
ref targets,
|
||||||
unwind,
|
unwind,
|
||||||
} => self.codegen_asm_terminator(
|
} => self.codegen_asm_terminator(
|
||||||
helper,
|
helper,
|
||||||
@ -1328,7 +1354,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
operands,
|
operands,
|
||||||
options,
|
options,
|
||||||
line_spans,
|
line_spans,
|
||||||
destination,
|
targets,
|
||||||
unwind,
|
unwind,
|
||||||
self.instance,
|
self.instance,
|
||||||
mergeable_succ(),
|
mergeable_succ(),
|
||||||
|
@ -76,7 +76,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
|||||||
hir::InlineAsmOperand::In { .. }
|
hir::InlineAsmOperand::In { .. }
|
||||||
| hir::InlineAsmOperand::Out { .. }
|
| hir::InlineAsmOperand::Out { .. }
|
||||||
| hir::InlineAsmOperand::InOut { .. }
|
| hir::InlineAsmOperand::InOut { .. }
|
||||||
| hir::InlineAsmOperand::SplitInOut { .. } => {
|
| hir::InlineAsmOperand::SplitInOut { .. }
|
||||||
|
| hir::InlineAsmOperand::Label { .. } => {
|
||||||
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -33,6 +33,9 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
|
|||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
},
|
},
|
||||||
|
Label {
|
||||||
|
label: B::BasicBlock,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -51,7 +54,8 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
|||||||
options: InlineAsmOptions,
|
options: InlineAsmOptions,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
instance: Instance<'_>,
|
instance: Instance<'_>,
|
||||||
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
|
dest: Option<Self::BasicBlock>,
|
||||||
|
catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,9 +232,6 @@ const_eval_non_const_fn_call =
|
|||||||
const_eval_non_const_impl =
|
const_eval_non_const_impl =
|
||||||
impl defined here, but it is not `const`
|
impl defined here, but it is not `const`
|
||||||
|
|
||||||
const_eval_noreturn_asm_returned =
|
|
||||||
returned from noreturn inline assembly
|
|
||||||
|
|
||||||
const_eval_not_enough_caller_args =
|
const_eval_not_enough_caller_args =
|
||||||
calling a function with fewer arguments than it requires
|
calling a function with fewer arguments than it requires
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||||||
if self.tcx.has_attr(def_id, sym::rustc_const_panic_str)
|
if self.tcx.has_attr(def_id, sym::rustc_const_panic_str)
|
||||||
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
||||||
{
|
{
|
||||||
let args = self.copy_fn_args(args)?;
|
let args = self.copy_fn_args(args);
|
||||||
// &str or &&str
|
// &str or &&str
|
||||||
assert!(args.len() == 1);
|
assert!(args.len() == 1);
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||||||
|
|
||||||
return Ok(Some(new_instance));
|
return Ok(Some(new_instance));
|
||||||
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
|
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
|
||||||
let args = self.copy_fn_args(args)?;
|
let args = self.copy_fn_args(args);
|
||||||
// For align_offset, we replace the function call if the pointer has no address.
|
// For align_offset, we replace the function call if the pointer has no address.
|
||||||
match self.align_offset(instance, &args, dest, ret)? {
|
match self.align_offset(instance, &args, dest, ret)? {
|
||||||
ControlFlow::Continue(()) => return Ok(Some(instance)),
|
ControlFlow::Continue(()) => return Ok(Some(instance)),
|
||||||
|
@ -10,6 +10,8 @@ use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable}
|
|||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
/// Writes the discriminant of the given variant.
|
/// Writes the discriminant of the given variant.
|
||||||
|
///
|
||||||
|
/// If the variant is uninhabited, this is UB.
|
||||||
#[instrument(skip(self), level = "trace")]
|
#[instrument(skip(self), level = "trace")]
|
||||||
pub fn write_discriminant(
|
pub fn write_discriminant(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -102,6 +104,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
|
|
||||||
/// Read discriminant, return the runtime value as well as the variant index.
|
/// Read discriminant, return the runtime value as well as the variant index.
|
||||||
/// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
|
/// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
|
||||||
|
///
|
||||||
|
/// Will never return an uninhabited variant.
|
||||||
#[instrument(skip(self), level = "trace")]
|
#[instrument(skip(self), level = "trace")]
|
||||||
pub fn read_discriminant(
|
pub fn read_discriminant(
|
||||||
&self,
|
&self,
|
||||||
@ -244,7 +248,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
variant
|
variant
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// For consistency with `write_discriminant`, and to make sure that `project_downcast` cannot fail due to strange layouts, we declare immediate UB for uninhabited variants.
|
// Reading the discriminant of an uninhabited variant is UB. This is the basis for the
|
||||||
|
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
|
||||||
|
// `write_discriminant`.
|
||||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
||||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||||
}
|
}
|
||||||
|
@ -374,11 +374,17 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
||||||
|
|
||||||
|
/// Evaluate the inline assembly.
|
||||||
|
///
|
||||||
|
/// This should take care of jumping to the next block (one of `targets`) when asm goto
|
||||||
|
/// is triggered, `targets[0]` when the assembly falls through, or diverge in case of
|
||||||
|
/// `InlineAsmOptions::NORETURN` being set.
|
||||||
fn eval_inline_asm(
|
fn eval_inline_asm(
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_template: &'tcx [InlineAsmTemplatePiece],
|
_template: &'tcx [InlineAsmTemplatePiece],
|
||||||
_operands: &[mir::InlineAsmOperand<'tcx>],
|
_operands: &[mir::InlineAsmOperand<'tcx>],
|
||||||
_options: InlineAsmOptions,
|
_options: InlineAsmOptions,
|
||||||
|
_targets: &[mir::BasicBlock],
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
throw_unsup_format!("inline assembly is not supported")
|
throw_unsup_format!("inline assembly is not supported")
|
||||||
}
|
}
|
||||||
@ -466,11 +472,11 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||||||
/// argument/return value was actually copied or passed in-place..
|
/// argument/return value was actually copied or passed in-place..
|
||||||
fn protect_in_place_function_argument(
|
fn protect_in_place_function_argument(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
place: &PlaceTy<'tcx, Self::Provenance>,
|
mplace: &MPlaceTy<'tcx, Self::Provenance>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
// Without an aliasing model, all we can do is put `Uninit` into the place.
|
// Without an aliasing model, all we can do is put `Uninit` into the place.
|
||||||
// Conveniently this also ensures that the place actually points to suitable memory.
|
// Conveniently this also ensures that the place actually points to suitable memory.
|
||||||
ecx.write_uninit(place)
|
ecx.write_uninit(mplace)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called immediately before a new stack frame gets pushed.
|
/// Called immediately before a new stack frame gets pushed.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_ast::ast::InlineAsmOptions;
|
use either::Either;
|
||||||
|
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
mir,
|
mir,
|
||||||
ty::{
|
ty::{
|
||||||
@ -30,14 +31,14 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
|
|||||||
Copy(OpTy<'tcx, Prov>),
|
Copy(OpTy<'tcx, Prov>),
|
||||||
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
|
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
|
||||||
/// make the place inaccessible for the duration of the function call.
|
/// make the place inaccessible for the duration of the function call.
|
||||||
InPlace(PlaceTy<'tcx, Prov>),
|
InPlace(MPlaceTy<'tcx, Prov>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
|
impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
|
||||||
pub fn layout(&self) -> &TyAndLayout<'tcx> {
|
pub fn layout(&self) -> &TyAndLayout<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
FnArg::Copy(op) => &op.layout,
|
FnArg::Copy(op) => &op.layout,
|
||||||
FnArg::InPlace(place) => &place.layout,
|
FnArg::InPlace(mplace) => &mplace.layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,13 +46,10 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
|
|||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
|
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
|
||||||
/// original memory occurs.
|
/// original memory occurs.
|
||||||
pub fn copy_fn_arg(
|
pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> {
|
||||||
&self,
|
|
||||||
arg: &FnArg<'tcx, M::Provenance>,
|
|
||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
|
||||||
match arg {
|
match arg {
|
||||||
FnArg::Copy(op) => Ok(op.clone()),
|
FnArg::Copy(op) => op.clone(),
|
||||||
FnArg::InPlace(place) => self.place_to_op(place),
|
FnArg::InPlace(mplace) => mplace.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
pub fn copy_fn_args(
|
pub fn copy_fn_args(
|
||||||
&self,
|
&self,
|
||||||
args: &[FnArg<'tcx, M::Provenance>],
|
args: &[FnArg<'tcx, M::Provenance>],
|
||||||
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
|
) -> Vec<OpTy<'tcx, M::Provenance>> {
|
||||||
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
|
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
|
||||||
Ok(match arg {
|
Ok(match arg {
|
||||||
FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?),
|
FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?),
|
||||||
FnArg::InPlace(place) => FnArg::InPlace(self.project_field(place, field)?),
|
FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,15 +222,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
terminator.kind
|
terminator.kind
|
||||||
),
|
),
|
||||||
|
|
||||||
InlineAsm { template, ref operands, options, destination, .. } => {
|
InlineAsm { template, ref operands, options, ref targets, .. } => {
|
||||||
M::eval_inline_asm(self, template, operands, options)?;
|
M::eval_inline_asm(self, template, operands, options, targets)?;
|
||||||
if options.contains(InlineAsmOptions::NORETURN) {
|
|
||||||
throw_ub_custom!(fluent::const_eval_noreturn_asm_returned);
|
|
||||||
}
|
|
||||||
self.go_to_block(
|
|
||||||
destination
|
|
||||||
.expect("InlineAsm terminators without noreturn must have a destination"),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,10 +237,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
|
) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
|
||||||
ops.iter()
|
ops.iter()
|
||||||
.map(|op| {
|
.map(|op| {
|
||||||
Ok(match &op.node {
|
let arg = match &op.node {
|
||||||
mir::Operand::Move(place) => FnArg::InPlace(self.eval_place(*place)?),
|
mir::Operand::Copy(_) | mir::Operand::Constant(_) => {
|
||||||
_ => FnArg::Copy(self.eval_operand(&op.node, None)?),
|
// Make a regular copy.
|
||||||
})
|
let op = self.eval_operand(&op.node, None)?;
|
||||||
|
FnArg::Copy(op)
|
||||||
|
}
|
||||||
|
mir::Operand::Move(place) => {
|
||||||
|
// If this place lives in memory, preserve its location.
|
||||||
|
// We call `place_to_op` which will be an `MPlaceTy` whenever there exists
|
||||||
|
// an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
|
||||||
|
// which can return a local even if that has an mplace.)
|
||||||
|
let place = self.eval_place(*place)?;
|
||||||
|
let op = self.place_to_op(&place)?;
|
||||||
|
|
||||||
|
match op.as_mplace_or_imm() {
|
||||||
|
Either::Left(mplace) => FnArg::InPlace(mplace),
|
||||||
|
Either::Right(_imm) => {
|
||||||
|
// This argument doesn't live in memory, so there's no place
|
||||||
|
// to make inaccessible during the call.
|
||||||
|
// We rely on there not being any stray `PlaceTy` that would let the
|
||||||
|
// caller directly access this local!
|
||||||
|
// This is also crucial for tail calls, where we want the `FnArg` to
|
||||||
|
// stay valid when the old stack frame gets popped.
|
||||||
|
FnArg::Copy(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(arg)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
@ -459,7 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// We work with a copy of the argument for now; if this is in-place argument passing, we
|
// We work with a copy of the argument for now; if this is in-place argument passing, we
|
||||||
// will later protect the source it comes from. This means the callee cannot observe if we
|
// will later protect the source it comes from. This means the callee cannot observe if we
|
||||||
// did in-place of by-copy argument passing, except for pointer equality tests.
|
// did in-place of by-copy argument passing, except for pointer equality tests.
|
||||||
let caller_arg_copy = self.copy_fn_arg(caller_arg)?;
|
let caller_arg_copy = self.copy_fn_arg(caller_arg);
|
||||||
if !already_live {
|
if !already_live {
|
||||||
let local = callee_arg.as_local().unwrap();
|
let local = callee_arg.as_local().unwrap();
|
||||||
let meta = caller_arg_copy.meta();
|
let meta = caller_arg_copy.meta();
|
||||||
@ -477,8 +494,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// specifically.)
|
// specifically.)
|
||||||
self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?;
|
self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?;
|
||||||
// If this was an in-place pass, protect the place it comes from for the duration of the call.
|
// If this was an in-place pass, protect the place it comes from for the duration of the call.
|
||||||
if let FnArg::InPlace(place) = caller_arg {
|
if let FnArg::InPlace(mplace) = caller_arg {
|
||||||
M::protect_in_place_function_argument(self, place)?;
|
M::protect_in_place_function_argument(self, mplace)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -525,7 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
M::call_intrinsic(
|
M::call_intrinsic(
|
||||||
self,
|
self,
|
||||||
instance,
|
instance,
|
||||||
&self.copy_fn_args(args)?,
|
&self.copy_fn_args(args),
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind,
|
unwind,
|
||||||
@ -602,8 +619,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
.map(|arg| (
|
.map(|arg| (
|
||||||
arg.layout().ty,
|
arg.layout().ty,
|
||||||
match arg {
|
match arg {
|
||||||
FnArg::Copy(op) => format!("copy({:?})", *op),
|
FnArg::Copy(op) => format!("copy({op:?})"),
|
||||||
FnArg::InPlace(place) => format!("in-place({:?})", *place),
|
FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
@ -725,8 +742,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
callee_ty: callee_fn_abi.ret.layout.ty
|
callee_ty: callee_fn_abi.ret.layout.ty
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protect return place for in-place return value passing.
|
// Protect return place for in-place return value passing.
|
||||||
M::protect_in_place_function_argument(self, &destination.clone().into())?;
|
M::protect_in_place_function_argument(self, &destination)?;
|
||||||
|
|
||||||
// Don't forget to mark "initially live" locals as live.
|
// Don't forget to mark "initially live" locals as live.
|
||||||
self.storage_live_for_always_live_locals()?;
|
self.storage_live_for_always_live_locals()?;
|
||||||
@ -749,7 +767,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
|
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
|
||||||
// really pass the argument in-place anyway, and we are constructing a new
|
// really pass the argument in-place anyway, and we are constructing a new
|
||||||
// `Immediate` receiver.
|
// `Immediate` receiver.
|
||||||
let mut receiver = self.copy_fn_arg(&args[0])?;
|
let mut receiver = self.copy_fn_arg(&args[0]);
|
||||||
let receiver_place = loop {
|
let receiver_place = loop {
|
||||||
match receiver.layout.ty.kind() {
|
match receiver.layout.ty.kind() {
|
||||||
ty::Ref(..) | ty::RawPtr(..) => {
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
|
@ -581,7 +581,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||||||
if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
|
if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
|
||||||
// Int, bool, and char operations are fine.
|
// Int, bool, and char operations are fine.
|
||||||
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
|
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
|
||||||
assert_eq!(lhs_ty, rhs_ty);
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
op,
|
op,
|
||||||
BinOp::Eq
|
BinOp::Eq
|
||||||
|
@ -471,9 +471,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||||||
self.check_edge(location, *real_target, EdgeKind::Normal);
|
self.check_edge(location, *real_target, EdgeKind::Normal);
|
||||||
self.check_unwind_edge(location, *unwind);
|
self.check_unwind_edge(location, *unwind);
|
||||||
}
|
}
|
||||||
TerminatorKind::InlineAsm { destination, unwind, .. } => {
|
TerminatorKind::InlineAsm { targets, unwind, .. } => {
|
||||||
if let Some(destination) = destination {
|
for &target in targets {
|
||||||
self.check_edge(location, *destination, EdgeKind::Normal);
|
self.check_edge(location, target, EdgeKind::Normal);
|
||||||
}
|
}
|
||||||
self.check_unwind_edge(location, *unwind);
|
self.check_unwind_edge(location, *unwind);
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,26 @@
|
|||||||
A lifetime bound on a trait implementation was captured at an incorrect place.
|
An `impl Trait` captured a higher-ranked lifetime, which is not supported.
|
||||||
|
|
||||||
|
Currently, `impl Trait` types are only allowed to capture lifetimes from
|
||||||
|
their parent items, and not from any `for<'a>` binders in scope.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0657
|
```compile_fail,E0657
|
||||||
trait Id<T> {}
|
trait BorrowInto<'a> {
|
||||||
trait Lt<'a> {}
|
type Target;
|
||||||
|
|
||||||
impl<'a> Lt<'a> for () {}
|
fn borrow_into(&'a self) -> Self::Target;
|
||||||
impl<T> Id<T> for T {}
|
|
||||||
|
|
||||||
fn free_fn_capture_hrtb_in_impl_trait()
|
|
||||||
-> Box<for<'a> Id<impl Lt<'a>>> // error!
|
|
||||||
{
|
|
||||||
Box::new(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo;
|
impl<'a> BorrowInto<'a> for () {
|
||||||
impl Foo {
|
type Target = &'a ();
|
||||||
fn impl_fn_capture_hrtb_in_impl_trait()
|
|
||||||
-> Box<for<'a> Id<impl Lt<'a>>> // error!
|
fn borrow_into(&'a self) -> Self::Target {
|
||||||
{
|
self
|
||||||
Box::new(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
Here, you have used the inappropriate lifetime in the `impl Trait`,
|
fn opaque() -> impl for<'a> BorrowInto<'a, Target = impl Sized + 'a> {
|
||||||
The `impl Trait` can only capture lifetimes bound at the fn or impl
|
()
|
||||||
level.
|
|
||||||
|
|
||||||
To fix this we have to define the lifetime at the function or impl
|
|
||||||
level and use that lifetime in the `impl Trait`. For example you can
|
|
||||||
define the lifetime at the function:
|
|
||||||
|
|
||||||
```
|
|
||||||
trait Id<T> {}
|
|
||||||
trait Lt<'a> {}
|
|
||||||
|
|
||||||
impl<'a> Lt<'a> for () {}
|
|
||||||
impl<T> Id<T> for T {}
|
|
||||||
|
|
||||||
fn free_fn_capture_hrtb_in_impl_trait<'b>()
|
|
||||||
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
|
|
||||||
{
|
|
||||||
Box::new(())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Foo;
|
|
||||||
impl Foo {
|
|
||||||
fn impl_fn_capture_hrtb_in_impl_trait<'b>()
|
|
||||||
-> Box<for<'a> Id<impl Lt<'b>>> // ok!
|
|
||||||
{
|
|
||||||
Box::new(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -345,6 +345,8 @@ declare_features! (
|
|||||||
(unstable, asm_const, "1.58.0", Some(93332)),
|
(unstable, asm_const, "1.58.0", Some(93332)),
|
||||||
/// Enables experimental inline assembly support for additional architectures.
|
/// Enables experimental inline assembly support for additional architectures.
|
||||||
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
||||||
|
/// Allows using `label` operands in inline assembly.
|
||||||
|
(unstable, asm_goto, "CURRENT_RUSTC_VERSION", Some(119364)),
|
||||||
/// Allows the `may_unwind` option in inline assembly.
|
/// Allows the `may_unwind` option in inline assembly.
|
||||||
(unstable, asm_unwind, "1.58.0", Some(93334)),
|
(unstable, asm_unwind, "1.58.0", Some(93334)),
|
||||||
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
/// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
|
||||||
|
@ -2562,6 +2562,8 @@ pub enum OpaqueTyOrigin {
|
|||||||
AsyncFn(LocalDefId),
|
AsyncFn(LocalDefId),
|
||||||
/// type aliases: `type Foo = impl Trait;`
|
/// type aliases: `type Foo = impl Trait;`
|
||||||
TyAlias {
|
TyAlias {
|
||||||
|
/// The type alias or associated type parent of the TAIT/ATPIT
|
||||||
|
parent: LocalDefId,
|
||||||
/// associated types in impl blocks for traits.
|
/// associated types in impl blocks for traits.
|
||||||
in_assoc_ty: bool,
|
in_assoc_ty: bool,
|
||||||
},
|
},
|
||||||
@ -2650,6 +2652,9 @@ pub enum InlineAsmOperand<'hir> {
|
|||||||
path: QPath<'hir>,
|
path: QPath<'hir>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
},
|
},
|
||||||
|
Label {
|
||||||
|
block: &'hir Block<'hir>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> InlineAsmOperand<'hir> {
|
impl<'hir> InlineAsmOperand<'hir> {
|
||||||
@ -2659,7 +2664,10 @@ impl<'hir> InlineAsmOperand<'hir> {
|
|||||||
| Self::Out { reg, .. }
|
| Self::Out { reg, .. }
|
||||||
| Self::InOut { reg, .. }
|
| Self::InOut { reg, .. }
|
||||||
| Self::SplitInOut { reg, .. } => Some(reg),
|
| Self::SplitInOut { reg, .. } => Some(reg),
|
||||||
Self::Const { .. } | Self::SymFn { .. } | Self::SymStatic { .. } => None,
|
Self::Const { .. }
|
||||||
|
| Self::SymFn { .. }
|
||||||
|
| Self::SymStatic { .. }
|
||||||
|
| Self::Label { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2680,6 +2688,12 @@ pub struct InlineAsm<'hir> {
|
|||||||
pub line_spans: &'hir [Span],
|
pub line_spans: &'hir [Span],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InlineAsm<'_> {
|
||||||
|
pub fn contains_label(&self) -> bool {
|
||||||
|
self.operands.iter().any(|x| matches!(x.0, InlineAsmOperand::Label { .. }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a parameter in a function header.
|
/// Represents a parameter in a function header.
|
||||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||||
pub struct Param<'hir> {
|
pub struct Param<'hir> {
|
||||||
|
@ -1289,6 +1289,7 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
|
|||||||
InlineAsmOperand::SymStatic { path, .. } => {
|
InlineAsmOperand::SymStatic { path, .. } => {
|
||||||
try_visit!(visitor.visit_qpath(path, id, *op_sp));
|
try_visit!(visitor.visit_qpath(path, id, *op_sp));
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
|
@ -312,6 +312,10 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current
|
|||||||
|
|
||||||
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
|
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
|
||||||
|
|
||||||
|
hir_analysis_opaque_captures_higher_ranked_lifetime = `impl Trait` cannot capture {$bad_place}
|
||||||
|
.label = `impl Trait` implicitly captures all lifetimes in scope
|
||||||
|
.note = lifetime declared here
|
||||||
|
|
||||||
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
|
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
|
||||||
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
|
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
|
||||||
|
|
||||||
|
@ -339,8 +339,9 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||||||
origin: &hir::OpaqueTyOrigin,
|
origin: &hir::OpaqueTyOrigin,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let defining_use_anchor = match *origin {
|
let defining_use_anchor = match *origin {
|
||||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
hir::OpaqueTyOrigin::FnReturn(did)
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
|
| hir::OpaqueTyOrigin::AsyncFn(did)
|
||||||
|
| hir::OpaqueTyOrigin::TyAlias { parent: did, .. } => did,
|
||||||
};
|
};
|
||||||
let param_env = tcx.param_env(defining_use_anchor);
|
let param_env = tcx.param_env(defining_use_anchor);
|
||||||
|
|
||||||
@ -351,14 +352,14 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
|
|
||||||
let args = match *origin {
|
let args = match *origin {
|
||||||
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
|
hir::OpaqueTyOrigin::FnReturn(parent)
|
||||||
GenericArgs::identity_for_item(tcx, parent).extend_to(
|
| hir::OpaqueTyOrigin::AsyncFn(parent)
|
||||||
tcx,
|
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
|
||||||
def_id.to_def_id(),
|
tcx, parent,
|
||||||
|param, _| tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()).into(),
|
|
||||||
)
|
)
|
||||||
}
|
.extend_to(tcx, def_id.to_def_id(), |param, _| {
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. } => GenericArgs::identity_for_item(tcx, def_id),
|
tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::potentially_plural_count;
|
use super::potentially_plural_count;
|
||||||
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
|
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
use hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||||
@ -520,14 +521,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||||||
)
|
)
|
||||||
.fold_with(&mut collector);
|
.fold_with(&mut collector);
|
||||||
|
|
||||||
if !unnormalized_trait_sig.output().references_error() {
|
|
||||||
debug_assert_ne!(
|
|
||||||
collector.types.len(),
|
|
||||||
0,
|
|
||||||
"expect >1 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let trait_sig = ocx.normalize(&misc_cause, param_env, unnormalized_trait_sig);
|
let trait_sig = ocx.normalize(&misc_cause, param_env, unnormalized_trait_sig);
|
||||||
trait_sig.error_reported()?;
|
trait_sig.error_reported()?;
|
||||||
let trait_return_ty = trait_sig.output();
|
let trait_return_ty = trait_sig.output();
|
||||||
@ -646,6 +639,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !unnormalized_trait_sig.output().references_error() {
|
||||||
|
debug_assert!(
|
||||||
|
!collector.types.is_empty(),
|
||||||
|
"expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: This has the same issue as #108544, but since this isn't breaking
|
// FIXME: This has the same issue as #108544, but since this isn't breaking
|
||||||
// existing code, I'm not particularly inclined to do the same hack as above
|
// existing code, I'm not particularly inclined to do the same hack as above
|
||||||
// where we process wf obligations manually. This can be fixed in a forward-
|
// where we process wf obligations manually. This can be fixed in a forward-
|
||||||
@ -1565,24 +1565,24 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
let (sig, _) = impl_m.expect_fn();
|
let (sig, _) = impl_m.expect_fn();
|
||||||
let input_tys = sig.decl.inputs;
|
let input_tys = sig.decl.inputs;
|
||||||
|
|
||||||
struct Visitor(Option<Span>, hir::def_id::LocalDefId);
|
struct Visitor(hir::def_id::LocalDefId);
|
||||||
impl<'v> intravisit::Visitor<'v> for Visitor {
|
impl<'v> intravisit::Visitor<'v> for Visitor {
|
||||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
type Result = ControlFlow<Span>;
|
||||||
intravisit::walk_ty(self, ty);
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
|
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
|
||||||
&& let Res::Def(DefKind::TyParam, def_id) = path.res
|
&& let Res::Def(DefKind::TyParam, def_id) = path.res
|
||||||
&& def_id == self.1.to_def_id()
|
&& def_id == self.0.to_def_id()
|
||||||
{
|
{
|
||||||
self.0 = Some(ty.span);
|
ControlFlow::Break(ty.span)
|
||||||
|
} else {
|
||||||
|
intravisit::walk_ty(self, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = Visitor(None, impl_def_id);
|
let span = input_tys.iter().find_map(|ty| {
|
||||||
for ty in input_tys {
|
intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
|
||||||
intravisit::Visitor::visit_ty(&mut visitor, ty);
|
})?;
|
||||||
}
|
|
||||||
let span = visitor.0?;
|
|
||||||
|
|
||||||
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
|
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
|
||||||
let bounds = bounds.first()?.span().to(bounds.last()?.span());
|
let bounds = bounds.first()?.span().to(bounds.last()?.span());
|
||||||
|
@ -470,6 +470,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// No special checking is needed for labels.
|
||||||
|
hir::InlineAsmOperand::Label { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::autoderef::Autoderef;
|
use crate::autoderef::Autoderef;
|
||||||
|
use crate::collect::CollectItemTypesVisitor;
|
||||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
|
||||||
|
use hir::intravisit::Visitor;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||||
@ -225,6 +227,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||||||
?item.owner_id,
|
?item.owner_id,
|
||||||
item.name = ? tcx.def_path_str(def_id)
|
item.name = ? tcx.def_path_str(def_id)
|
||||||
);
|
);
|
||||||
|
CollectItemTypesVisitor { tcx }.visit_item(item);
|
||||||
|
|
||||||
let res = match item.kind {
|
let res = match item.kind {
|
||||||
// Right now we check that every default trait implementation
|
// Right now we check that every default trait implementation
|
||||||
@ -336,9 +339,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<(), ErrorGuaranteed> {
|
fn check_foreign_item<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
item: &'tcx hir::ForeignItem<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let def_id = item.owner_id.def_id;
|
let def_id = item.owner_id.def_id;
|
||||||
|
|
||||||
|
CollectItemTypesVisitor { tcx }.visit_foreign_item(item);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
?item.owner_id,
|
?item.owner_id,
|
||||||
item.name = ? tcx.def_path_str(def_id)
|
item.name = ? tcx.def_path_str(def_id)
|
||||||
@ -355,12 +363,14 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) -> Result<()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait_item(
|
fn check_trait_item<'tcx>(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_item: &hir::TraitItem<'_>,
|
trait_item: &'tcx hir::TraitItem<'tcx>,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let def_id = trait_item.owner_id.def_id;
|
let def_id = trait_item.owner_id.def_id;
|
||||||
|
|
||||||
|
CollectItemTypesVisitor { tcx }.visit_trait_item(trait_item);
|
||||||
|
|
||||||
let (method_sig, span) = match trait_item.kind {
|
let (method_sig, span) = match trait_item.kind {
|
||||||
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
|
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
|
||||||
hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span),
|
hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span),
|
||||||
@ -895,7 +905,12 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> Result<(), ErrorGuaranteed> {
|
fn check_impl_item<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_item: &'tcx hir::ImplItem<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
|
CollectItemTypesVisitor { tcx }.visit_impl_item(impl_item);
|
||||||
|
|
||||||
let (method_sig, span) = match impl_item.kind {
|
let (method_sig, span) = match impl_item.kind {
|
||||||
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
|
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
|
||||||
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
|
// Constrain binding and overflow error spans to `<Ty>` in `type foo = <Ty>`.
|
||||||
|
@ -20,7 +20,7 @@ use rustc_data_structures::unord::UnordMap;
|
|||||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{GenericParamKind, Node};
|
use rustc_hir::{GenericParamKind, Node};
|
||||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||||
@ -52,11 +52,6 @@ mod resolve_bound_vars;
|
|||||||
mod type_of;
|
mod type_of;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Main entry point
|
|
||||||
|
|
||||||
fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
|
||||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
resolve_bound_vars::provide(providers);
|
resolve_bound_vars::provide(providers);
|
||||||
@ -82,7 +77,6 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
impl_trait_header,
|
impl_trait_header,
|
||||||
coroutine_kind,
|
coroutine_kind,
|
||||||
coroutine_for_closure,
|
coroutine_for_closure,
|
||||||
collect_mod_item_types,
|
|
||||||
is_type_alias_impl_trait,
|
is_type_alias_impl_trait,
|
||||||
find_field,
|
find_field,
|
||||||
..*providers
|
..*providers
|
||||||
@ -155,8 +149,8 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CollectItemTypesVisitor<'tcx> {
|
pub struct CollectItemTypesVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
pub tcx: TyCtxt<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
|
/// If there are any placeholder types (`_`), emit an error explaining that this is not allowed
|
||||||
|
@ -339,7 +339,7 @@ fn compute_bidirectional_outlives_predicates<'tcx>(
|
|||||||
predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||||
) {
|
) {
|
||||||
for param in opaque_own_params {
|
for param in opaque_own_params {
|
||||||
let orig_lifetime = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local());
|
let orig_lifetime = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local());
|
||||||
if let ty::ReEarlyParam(..) = *orig_lifetime {
|
if let ty::ReEarlyParam(..) = *orig_lifetime {
|
||||||
let dup_lifetime = ty::Region::new_early_param(
|
let dup_lifetime = ty::Region::new_early_param(
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
|
//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
|
||||||
//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
|
//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
|
||||||
|
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::walk_list;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, struct_span_code_err};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
@ -417,23 +417,18 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
|
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
|
||||||
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
|
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
|
||||||
struct V(Option<Span>);
|
struct V;
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for V {
|
impl<'v> Visitor<'v> for V {
|
||||||
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
|
type Result = ControlFlow<Span>;
|
||||||
match t.kind {
|
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
|
||||||
_ if self.0.is_some() => (),
|
if matches!(t.kind, hir::TyKind::Infer) {
|
||||||
hir::TyKind::Infer => {
|
ControlFlow::Break(t.span)
|
||||||
self.0 = Some(t.span);
|
} else {
|
||||||
}
|
intravisit::walk_ty(self, t)
|
||||||
_ => intravisit::walk_ty(self, t),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
V.visit_ty(ty).break_value()
|
||||||
let mut v = V(None);
|
|
||||||
v.visit_ty(ty);
|
|
||||||
v.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let infer_in_rt_sp = match fn_decl.output {
|
let infer_in_rt_sp = match fn_decl.output {
|
||||||
@ -514,38 +509,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
// These sorts of items have no lifetime parameters at all.
|
// These sorts of items have no lifetime parameters at all.
|
||||||
intravisit::walk_item(self, item);
|
intravisit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// Opaque types are visited when we visit the
|
|
||||||
// `TyKind::OpaqueDef`, so that they have the lifetimes from
|
|
||||||
// their parent opaque_ty in scope.
|
|
||||||
//
|
|
||||||
// The core idea here is that since OpaqueTys are generated with the impl Trait as
|
|
||||||
// their owner, we can keep going until we find the Item that owns that. We then
|
|
||||||
// conservatively add all resolved lifetimes. Otherwise we run into problems in
|
|
||||||
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
|
|
||||||
let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
|
|
||||||
let resolved_lifetimes: &ResolveBoundVars =
|
|
||||||
self.tcx.resolve_bound_vars(parent_item);
|
|
||||||
// We need to add *all* deps, since opaque tys may want them from *us*
|
|
||||||
for (&owner, defs) in resolved_lifetimes.defs.iter() {
|
|
||||||
defs.iter().for_each(|(&local_id, region)| {
|
|
||||||
self.map.defs.insert(hir::HirId { owner, local_id }, *region);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
|
|
||||||
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
|
|
||||||
self.record_late_bound_vars(
|
|
||||||
hir::HirId { owner, local_id },
|
|
||||||
late_bound_vars.clone(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
|
hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
|
origin:
|
||||||
|
hir::OpaqueTyOrigin::FnReturn(parent)
|
||||||
|
| hir::OpaqueTyOrigin::AsyncFn(parent)
|
||||||
|
| hir::OpaqueTyOrigin::TyAlias { parent, .. },
|
||||||
generics,
|
generics,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
@ -683,26 +651,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
// the opaque_ty generics
|
// the opaque_ty generics
|
||||||
let opaque_ty = self.tcx.hir().item(item_id);
|
let opaque_ty = self.tcx.hir().item(item_id);
|
||||||
match &opaque_ty.kind {
|
match &opaque_ty.kind {
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: _, .. }) => {}
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
intravisit::walk_ty(self, ty);
|
|
||||||
|
|
||||||
// Elided lifetimes and late-bound lifetimes (from the parent)
|
|
||||||
// are not allowed in non-return position impl Trait
|
|
||||||
let scope = Scope::LateBoundary {
|
|
||||||
s: &Scope::TraitRefBoundary { s: self.scope },
|
|
||||||
what: "type alias impl trait",
|
|
||||||
};
|
|
||||||
self.with(scope, |this| intravisit::walk_item(this, opaque_ty));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
|
||||||
origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
|
|
||||||
..
|
|
||||||
}) => {}
|
|
||||||
i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -719,34 +668,47 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
// and ban them. Type variables instantiated inside binders aren't
|
// and ban them. Type variables instantiated inside binders aren't
|
||||||
// well-supported at the moment, so this doesn't work.
|
// well-supported at the moment, so this doesn't work.
|
||||||
// In the future, this should be fixed and this error should be removed.
|
// In the future, this should be fixed and this error should be removed.
|
||||||
let def = self.map.defs.get(&lifetime.hir_id).cloned();
|
let def = self.map.defs.get(&lifetime.hir_id).copied();
|
||||||
let Some(ResolvedArg::LateBound(_, _, def_id)) = def else { continue };
|
let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
|
||||||
let Some(def_id) = def_id.as_local() else { continue };
|
let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue };
|
||||||
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
|
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
|
||||||
// Ensure that the parent of the def is an item, not HRTB
|
|
||||||
let parent_id = self.tcx.parent_hir_id(hir_id);
|
let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
|
||||||
if !parent_id.is_owner() {
|
|
||||||
struct_span_code_err!(
|
|
||||||
self.tcx.dcx(),
|
|
||||||
lifetime.ident.span,
|
|
||||||
E0657,
|
|
||||||
"`impl Trait` can only capture lifetimes bound at the fn or impl level"
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
|
|
||||||
}
|
|
||||||
if let hir::Node::Item(hir::Item {
|
|
||||||
kind: hir::ItemKind::OpaqueTy { .. }, ..
|
|
||||||
}) = self.tcx.hir_node(parent_id)
|
|
||||||
{
|
{
|
||||||
self.tcx.dcx().struct_span_err(
|
// Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
|
||||||
lifetime.ident.span,
|
// it must be a reified late-bound lifetime from a trait goal.
|
||||||
"higher kinded lifetime bounds on nested opaque types are not supported yet",
|
hir::Node::Item(hir::Item {
|
||||||
)
|
kind: hir::ItemKind::OpaqueTy { .. }, ..
|
||||||
.with_span_note(self.tcx.def_span(def_id), "lifetime declared here")
|
}) => "higher-ranked lifetime from outer `impl Trait`",
|
||||||
.emit();
|
// Other items are fine.
|
||||||
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
|
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => {
|
||||||
|
"higher-ranked lifetime from function pointer"
|
||||||
|
}
|
||||||
|
hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => {
|
||||||
|
"higher-ranked lifetime from `dyn` type"
|
||||||
|
}
|
||||||
|
_ => "higher-ranked lifetime",
|
||||||
|
};
|
||||||
|
|
||||||
|
let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
|
||||||
|
{
|
||||||
|
let opaque_span = self.tcx.def_span(item_id.owner_id);
|
||||||
|
(opaque_span, Some(opaque_span))
|
||||||
|
} else {
|
||||||
|
(lifetime.ident.span, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensure that the parent of the def is an item, not HRTB
|
||||||
|
self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime {
|
||||||
|
span,
|
||||||
|
label,
|
||||||
|
decl_span: self.tcx.def_span(lifetime_def_id),
|
||||||
|
bad_place,
|
||||||
|
});
|
||||||
|
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => intravisit::walk_ty(self, ty),
|
_ => intravisit::walk_ty(self, ty),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_errors::{Applicability, StashKey};
|
use rustc_errors::{Applicability, StashKey};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
@ -553,11 +554,11 @@ pub(super) fn type_of_opaque(
|
|||||||
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
|
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
|
||||||
Node::Item(item) => match item.kind {
|
Node::Item(item) => match item.kind {
|
||||||
ItemKind::OpaqueTy(OpaqueTy {
|
ItemKind::OpaqueTy(OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
|
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. },
|
||||||
..
|
..
|
||||||
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
|
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
|
||||||
ItemKind::OpaqueTy(OpaqueTy {
|
ItemKind::OpaqueTy(OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
|
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true, .. },
|
||||||
..
|
..
|
||||||
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
|
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
|
||||||
// Opaque types desugared from `impl Trait`.
|
// Opaque types desugared from `impl Trait`.
|
||||||
@ -675,19 +676,16 @@ pub fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
|||||||
if tcx.features().lazy_type_alias {
|
if tcx.features().lazy_type_alias {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
struct HasTait {
|
struct HasTait;
|
||||||
has_type_alias_impl_trait: bool,
|
|
||||||
}
|
|
||||||
impl<'tcx> Visitor<'tcx> for HasTait {
|
impl<'tcx> Visitor<'tcx> for HasTait {
|
||||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
|
type Result = ControlFlow<()>;
|
||||||
|
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||||
if let hir::TyKind::OpaqueDef(..) = t.kind {
|
if let hir::TyKind::OpaqueDef(..) = t.kind {
|
||||||
self.has_type_alias_impl_trait = true;
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
hir::intravisit::walk_ty(self, t);
|
hir::intravisit::walk_ty(self, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut has_tait = HasTait { has_type_alias_impl_trait: false };
|
HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
|
||||||
has_tait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0);
|
|
||||||
has_tait.has_type_alias_impl_trait
|
|
||||||
}
|
}
|
||||||
|
@ -1607,3 +1607,15 @@ pub struct UnnamedFieldsReprFieldDefined {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_analysis_opaque_captures_higher_ranked_lifetime, code = E0657)]
|
||||||
|
pub struct OpaqueCapturesHigherRankedLifetime {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub label: Option<Span>,
|
||||||
|
#[note]
|
||||||
|
pub decl_span: Span,
|
||||||
|
pub bad_place: &'static str,
|
||||||
|
}
|
||||||
|
@ -159,12 +159,6 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
||||||
let _prof_timer = tcx.sess.timer("type_check_crate");
|
let _prof_timer = tcx.sess.timer("type_check_crate");
|
||||||
|
|
||||||
// this ensures that later parts of type checking can assume that items
|
|
||||||
// have valid types and not error
|
|
||||||
tcx.sess.time("type_collecting", || {
|
|
||||||
tcx.hir().for_each_module(|module| tcx.ensure().collect_mod_item_types(module))
|
|
||||||
});
|
|
||||||
|
|
||||||
if tcx.features().rustc_attrs {
|
if tcx.features().rustc_attrs {
|
||||||
tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?;
|
tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?;
|
||||||
}
|
}
|
||||||
|
@ -125,15 +125,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
|||||||
|
|
||||||
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
// By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt
|
||||||
// lifetime generics.
|
// lifetime generics.
|
||||||
let variances = std::iter::repeat(ty::Invariant).take(generics.count());
|
let mut variances = vec![ty::Invariant; generics.count()];
|
||||||
|
|
||||||
let mut variances: Vec<_> = match tcx.opaque_type_origin(item_def_id) {
|
|
||||||
rustc_hir::OpaqueTyOrigin::FnReturn(_) | rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {
|
|
||||||
variances.collect()
|
|
||||||
}
|
|
||||||
// But TAIT are invariant for all generics
|
|
||||||
rustc_hir::OpaqueTyOrigin::TyAlias { .. } => return tcx.arena.alloc_from_iter(variances),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mark all lifetimes from parent generics as unused (Bivariant).
|
// Mark all lifetimes from parent generics as unused (Bivariant).
|
||||||
// This will be overridden later if required.
|
// This will be overridden later if required.
|
||||||
|
@ -1265,6 +1265,10 @@ impl<'a> State<'a> {
|
|||||||
s.space();
|
s.space();
|
||||||
s.print_qpath(path, true);
|
s.print_qpath(path, true);
|
||||||
}
|
}
|
||||||
|
hir::InlineAsmOperand::Label { block } => {
|
||||||
|
s.head("label");
|
||||||
|
s.print_block(block);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
AsmArg::Options(opts) => {
|
AsmArg::Options(opts) => {
|
||||||
s.word("options");
|
s.word("options");
|
||||||
|
@ -3232,6 +3232,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
|
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
|
||||||
|
let mut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN);
|
||||||
|
|
||||||
for (op, _op_sp) in asm.operands {
|
for (op, _op_sp) in asm.operands {
|
||||||
match op {
|
match op {
|
||||||
hir::InlineAsmOperand::In { expr, .. } => {
|
hir::InlineAsmOperand::In { expr, .. } => {
|
||||||
@ -3253,13 +3255,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// be well-formed.
|
// be well-formed.
|
||||||
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
|
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
|
||||||
hir::InlineAsmOperand::SymStatic { .. } => {}
|
hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||||
|
hir::InlineAsmOperand::Label { block } => {
|
||||||
|
let previous_diverges = self.diverges.get();
|
||||||
|
|
||||||
|
// The label blocks should have unit return value or diverge.
|
||||||
|
let ty =
|
||||||
|
self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
|
||||||
|
if !ty.is_never() {
|
||||||
|
self.demand_suptype(block.span, self.tcx.types.unit, ty);
|
||||||
|
diverge = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need this to avoid false unreachable warning when a label diverges.
|
||||||
|
self.diverges.set(previous_diverges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if asm.options.contains(ast::InlineAsmOptions::NORETURN) {
|
|
||||||
self.tcx.types.never
|
|
||||||
} else {
|
|
||||||
Ty::new_unit(self.tcx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if diverge { self.tcx.types.never } else { self.tcx.types.unit }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_offset_of(
|
fn check_offset_of(
|
||||||
|
@ -293,6 +293,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||||||
| hir::InlineAsmOperand::Const { .. }
|
| hir::InlineAsmOperand::Const { .. }
|
||||||
| hir::InlineAsmOperand::SymFn { .. }
|
| hir::InlineAsmOperand::SymFn { .. }
|
||||||
| hir::InlineAsmOperand::SymStatic { .. } => {}
|
| hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||||
|
hir::InlineAsmOperand::Label { block } => {
|
||||||
|
self.walk_block(block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ use rustc_hir::{HirIdMap, Node};
|
|||||||
use rustc_hir_analysis::astconv::AstConv;
|
use rustc_hir_analysis::astconv::AstConv;
|
||||||
use rustc_hir_analysis::check::check_abi;
|
use rustc_hir_analysis::check::check_abi;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use rustc_infer::traits::ObligationInspector;
|
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::traits;
|
use rustc_middle::traits;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
@ -253,6 +253,10 @@ fn typeck_with_fallback<'tcx>(
|
|||||||
let expected_type = expected_type.unwrap_or_else(fallback);
|
let expected_type = expected_type.unwrap_or_else(fallback);
|
||||||
|
|
||||||
let expected_type = fcx.normalize(body.value.span, expected_type);
|
let expected_type = fcx.normalize(body.value.span, expected_type);
|
||||||
|
|
||||||
|
let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
|
||||||
|
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
|
||||||
|
|
||||||
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
||||||
|
|
||||||
// Gather locals in statics (because of block expressions).
|
// Gather locals in statics (because of block expressions).
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
|
use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
|
||||||
use crate::Expectation;
|
use crate::Expectation;
|
||||||
use crate::FnCtxt;
|
use crate::FnCtxt;
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast::ast::Mutability;
|
use rustc_ast::ast::Mutability;
|
||||||
use rustc_attr::parse_confusables;
|
use rustc_attr::parse_confusables;
|
||||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||||
@ -2212,30 +2213,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let map = self.infcx.tcx.hir();
|
let map = self.infcx.tcx.hir();
|
||||||
let body_id = self.tcx.hir().body_owned_by(self.body_id);
|
let body_id = self.tcx.hir().body_owned_by(self.body_id);
|
||||||
let body = map.body(body_id);
|
let body = map.body(body_id);
|
||||||
struct LetVisitor<'a> {
|
struct LetVisitor {
|
||||||
result: Option<&'a hir::Expr<'a>>,
|
|
||||||
ident_name: Symbol,
|
ident_name: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This really should be taking scoping, etc into account.
|
// FIXME: This really should be taking scoping, etc into account.
|
||||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
impl<'v> Visitor<'v> for LetVisitor {
|
||||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
|
||||||
if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind
|
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
|
||||||
|
if let hir::StmtKind::Local(&hir::Local { pat, init, .. }) = ex.kind
|
||||||
&& let Binding(_, _, ident, ..) = pat.kind
|
&& let Binding(_, _, ident, ..) = pat.kind
|
||||||
&& ident.name == self.ident_name
|
&& ident.name == self.ident_name
|
||||||
{
|
{
|
||||||
self.result = *init;
|
ControlFlow::Break(init)
|
||||||
} else {
|
} else {
|
||||||
hir::intravisit::walk_stmt(self, ex);
|
hir::intravisit::walk_stmt(self, ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
|
|
||||||
visitor.visit_body(body);
|
|
||||||
|
|
||||||
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
|
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
|
||||||
&& let Some(expr) = visitor.result
|
&& let ControlFlow::Break(Some(expr)) =
|
||||||
|
(LetVisitor { ident_name: seg1.ident.name }).visit_body(body)
|
||||||
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id)
|
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id)
|
||||||
{
|
{
|
||||||
let probe = self.lookup_probe_for_diagnostic(
|
let probe = self.lookup_probe_for_diagnostic(
|
||||||
|
@ -79,7 +79,7 @@ use rustc_middle::ty::{
|
|||||||
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ops::Deref;
|
use std::ops::{ControlFlow, Deref};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{cmp, fmt, iter};
|
use std::{cmp, fmt, iter};
|
||||||
|
|
||||||
@ -2129,15 +2129,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) {
|
let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) {
|
||||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
|
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
|
||||||
let body = hir.body(*body_id);
|
let body = hir.body(*body_id);
|
||||||
struct LetVisitor<'v> {
|
struct LetVisitor {
|
||||||
span: Span,
|
span: Span,
|
||||||
result: Option<&'v hir::Ty<'v>>,
|
|
||||||
}
|
|
||||||
impl<'v> Visitor<'v> for LetVisitor<'v> {
|
|
||||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
|
||||||
if self.result.is_some() {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
impl<'v> Visitor<'v> for LetVisitor {
|
||||||
|
type Result = ControlFlow<&'v hir::TyKind<'v>>;
|
||||||
|
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
|
||||||
// Find a local statement where the initializer has
|
// Find a local statement where the initializer has
|
||||||
// the same span as the error and the type is specified.
|
// the same span as the error and the type is specified.
|
||||||
if let hir::Stmt {
|
if let hir::Stmt {
|
||||||
@ -2151,13 +2148,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
} = s
|
} = s
|
||||||
&& init_span == &self.span
|
&& init_span == &self.span
|
||||||
{
|
{
|
||||||
self.result = Some(*array_ty);
|
ControlFlow::Break(&array_ty.peel_refs().kind)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut visitor = LetVisitor { span, result: None };
|
LetVisitor { span }.visit_body(body).break_value()
|
||||||
visitor.visit_body(body);
|
|
||||||
visitor.result.map(|r| &r.peel_refs().kind)
|
|
||||||
}
|
}
|
||||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
|
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
|
||||||
Some(&ty.peel_refs().kind)
|
Some(&ty.peel_refs().kind)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use core::ops::ControlFlow;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
@ -43,14 +44,9 @@ fn find_component_for_bound_region<'tcx>(
|
|||||||
arg: &'tcx hir::Ty<'tcx>,
|
arg: &'tcx hir::Ty<'tcx>,
|
||||||
br: &ty::BoundRegionKind,
|
br: &ty::BoundRegionKind,
|
||||||
) -> Option<&'tcx hir::Ty<'tcx>> {
|
) -> Option<&'tcx hir::Ty<'tcx>> {
|
||||||
let mut nested_visitor = FindNestedTypeVisitor {
|
FindNestedTypeVisitor { tcx, bound_region: *br, current_index: ty::INNERMOST }
|
||||||
tcx,
|
.visit_ty(arg)
|
||||||
bound_region: *br,
|
.break_value()
|
||||||
found_type: None,
|
|
||||||
current_index: ty::INNERMOST,
|
|
||||||
};
|
|
||||||
nested_visitor.visit_ty(arg);
|
|
||||||
nested_visitor.found_type
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
|
// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
|
||||||
@ -65,26 +61,24 @@ struct FindNestedTypeVisitor<'tcx> {
|
|||||||
// The bound_region corresponding to the Refree(freeregion)
|
// The bound_region corresponding to the Refree(freeregion)
|
||||||
// associated with the anonymous region we are looking for.
|
// associated with the anonymous region we are looking for.
|
||||||
bound_region: ty::BoundRegionKind,
|
bound_region: ty::BoundRegionKind,
|
||||||
// The type where the anonymous lifetime appears
|
|
||||||
// for e.g., Vec<`&u8`> and <`&u8`>
|
|
||||||
found_type: Option<&'tcx hir::Ty<'tcx>>,
|
|
||||||
current_index: ty::DebruijnIndex,
|
current_index: ty::DebruijnIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
||||||
|
type Result = ControlFlow<&'tcx hir::Ty<'tcx>>;
|
||||||
type NestedFilter = nested_filter::OnlyBodies;
|
type NestedFilter = nested_filter::OnlyBodies;
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> Self::Map {
|
fn nested_visit_map(&mut self) -> Self::Map {
|
||||||
self.tcx.hir()
|
self.tcx.hir()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
|
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||||
match arg.kind {
|
match arg.kind {
|
||||||
hir::TyKind::BareFn(_) => {
|
hir::TyKind::BareFn(_) => {
|
||||||
self.current_index.shift_in(1);
|
self.current_index.shift_in(1);
|
||||||
intravisit::walk_ty(self, arg);
|
intravisit::walk_ty(self, arg);
|
||||||
self.current_index.shift_out(1);
|
self.current_index.shift_out(1);
|
||||||
return;
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::TyKind::TraitObject(bounds, ..) => {
|
hir::TyKind::TraitObject(bounds, ..) => {
|
||||||
@ -105,8 +99,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||||||
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
|
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
|
||||||
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||||
if id == def_id {
|
if id == def_id {
|
||||||
self.found_type = Some(arg);
|
return ControlFlow::Break(arg);
|
||||||
return; // we can stop visiting now
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +116,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||||||
);
|
);
|
||||||
debug!("LateBound id={:?} def_id={:?}", id, def_id);
|
debug!("LateBound id={:?} def_id={:?}", id, def_id);
|
||||||
if debruijn_index == self.current_index && id == def_id {
|
if debruijn_index == self.current_index && id == def_id {
|
||||||
self.found_type = Some(arg);
|
return ControlFlow::Break(arg);
|
||||||
return; // we can stop visiting now
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,23 +137,30 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
// Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
|
// Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
|
||||||
hir::TyKind::Path(_) => {
|
hir::TyKind::Path(_) => {
|
||||||
let subvisitor = &mut TyPathVisitor {
|
// Prefer using the lifetime in type arguments rather than lifetime arguments.
|
||||||
|
intravisit::walk_ty(self, arg)?;
|
||||||
|
|
||||||
|
// Call `walk_ty` as `visit_ty` is empty.
|
||||||
|
return if intravisit::walk_ty(
|
||||||
|
&mut TyPathVisitor {
|
||||||
tcx: self.tcx,
|
tcx: self.tcx,
|
||||||
found_it: false,
|
|
||||||
bound_region: self.bound_region,
|
bound_region: self.bound_region,
|
||||||
current_index: self.current_index,
|
current_index: self.current_index,
|
||||||
|
},
|
||||||
|
arg,
|
||||||
|
)
|
||||||
|
.is_break()
|
||||||
|
{
|
||||||
|
ControlFlow::Break(arg)
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
};
|
};
|
||||||
intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
|
|
||||||
// this will visit only outermost type
|
|
||||||
if subvisitor.found_it {
|
|
||||||
self.found_type = Some(arg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
|
// walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
|
||||||
// go on to visit `&Foo`
|
// go on to visit `&Foo`
|
||||||
intravisit::walk_ty(self, arg);
|
intravisit::walk_ty(self, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,26 +172,25 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||||||
// specific part of the type in the error message.
|
// specific part of the type in the error message.
|
||||||
struct TyPathVisitor<'tcx> {
|
struct TyPathVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
found_it: bool,
|
|
||||||
bound_region: ty::BoundRegionKind,
|
bound_region: ty::BoundRegionKind,
|
||||||
current_index: ty::DebruijnIndex,
|
current_index: ty::DebruijnIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
||||||
|
type Result = ControlFlow<()>;
|
||||||
type NestedFilter = nested_filter::OnlyBodies;
|
type NestedFilter = nested_filter::OnlyBodies;
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> Map<'tcx> {
|
fn nested_visit_map(&mut self) -> Map<'tcx> {
|
||||||
self.tcx.hir()
|
self.tcx.hir()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
|
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
|
||||||
match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) {
|
match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) {
|
||||||
// the lifetime of the TyPath!
|
// the lifetime of the TyPath!
|
||||||
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
|
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
|
||||||
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||||
if id == def_id {
|
if id == def_id {
|
||||||
self.found_it = true;
|
return ControlFlow::Break(());
|
||||||
return; // we can stop visiting now
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,8 +199,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||||||
debug!("id={:?}", id);
|
debug!("id={:?}", id);
|
||||||
debug!("def_id={:?}", def_id);
|
debug!("def_id={:?}", def_id);
|
||||||
if debruijn_index == self.current_index && id == def_id {
|
if debruijn_index == self.current_index && id == def_id {
|
||||||
self.found_it = true;
|
return ControlFlow::Break(());
|
||||||
return; // we can stop visiting now
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,9 +217,10 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||||||
debug!("no arg found");
|
debug!("no arg found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
|
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||||
// ignore nested types
|
// ignore nested types
|
||||||
//
|
//
|
||||||
// If you have a type like `Foo<'a, &Ty>` we
|
// If you have a type like `Foo<'a, &Ty>` we
|
||||||
@ -231,5 +229,6 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||||||
// Making `visit_ty` empty will ignore the `&Ty` embedded
|
// Making `visit_ty` empty will ignore the `&Ty` embedded
|
||||||
// inside, it will get reached by the outer visitor.
|
// inside, it will get reached by the outer visitor.
|
||||||
debug!("`Ty` corresponding to a struct is {:?}", arg);
|
debug!("`Ty` corresponding to a struct is {:?}", arg);
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::infer::error_reporting::hir::Path;
|
use crate::infer::error_reporting::hir::Path;
|
||||||
|
use core::ops::ControlFlow;
|
||||||
use hir::def::CtorKind;
|
use hir::def::CtorKind;
|
||||||
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
||||||
use hir::{Local, QPath};
|
use hir::{Local, QPath};
|
||||||
@ -563,33 +564,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
cause: &ObligationCause<'_>,
|
cause: &ObligationCause<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Option<TypeErrorAdditionalDiags> {
|
) -> Option<TypeErrorAdditionalDiags> {
|
||||||
let hir = self.tcx.hir();
|
|
||||||
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) {
|
|
||||||
let body = hir.body(body_id);
|
|
||||||
|
|
||||||
/// Find the if expression with given span
|
/// Find the if expression with given span
|
||||||
struct IfVisitor {
|
struct IfVisitor {
|
||||||
pub result: bool,
|
|
||||||
pub found_if: bool,
|
pub found_if: bool,
|
||||||
pub err_span: Span,
|
pub err_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for IfVisitor {
|
impl<'v> Visitor<'v> for IfVisitor {
|
||||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
type Result = ControlFlow<()>;
|
||||||
if self.result {
|
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
|
||||||
return;
|
|
||||||
}
|
|
||||||
match ex.kind {
|
match ex.kind {
|
||||||
hir::ExprKind::If(cond, _, _) => {
|
hir::ExprKind::If(cond, _, _) => {
|
||||||
self.found_if = true;
|
self.found_if = true;
|
||||||
walk_expr(self, cond);
|
walk_expr(self, cond)?;
|
||||||
self.found_if = false;
|
self.found_if = false;
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
_ => walk_expr(self, ex),
|
_ => walk_expr(self, ex),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
|
||||||
if let hir::StmtKind::Local(hir::Local {
|
if let hir::StmtKind::Local(hir::Local {
|
||||||
span,
|
span,
|
||||||
pat: hir::Pat { .. },
|
pat: hir::Pat { .. },
|
||||||
@ -600,25 +595,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||||||
&& self.found_if
|
&& self.found_if
|
||||||
&& span.eq(&self.err_span)
|
&& span.eq(&self.err_span)
|
||||||
{
|
{
|
||||||
self.result = true;
|
ControlFlow::Break(())
|
||||||
}
|
} else {
|
||||||
walk_stmt(self, ex);
|
walk_stmt(self, ex)
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
|
||||||
hir::intravisit::walk_body(self, body);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
|
fn visit_body(&mut self, body: &'v hir::Body<'v>) -> Self::Result {
|
||||||
visitor.visit_body(body);
|
hir::intravisit::walk_body(self, body)
|
||||||
if visitor.result {
|
|
||||||
return Some(TypeErrorAdditionalDiags::AddLetForLetChains {
|
|
||||||
span: span.shrink_to_lo(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
|
self.tcx.hir().maybe_body_owned_by(cause.body_id).and_then(|body_id| {
|
||||||
|
let body = self.tcx.hir().body(body_id);
|
||||||
|
IfVisitor { err_span: span, found_if: false }
|
||||||
|
.visit_body(body)
|
||||||
|
.is_break()
|
||||||
|
.then(|| TypeErrorAdditionalDiags::AddLetForLetChains { span: span.shrink_to_lo() })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For "one type is more general than the other" errors on closures, suggest changing the lifetime
|
/// For "one type is more general than the other" errors on closures, suggest changing the lifetime
|
||||||
|
@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
// Anonymous `impl Trait`
|
// Anonymous `impl Trait`
|
||||||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||||
// Named `type Foo = impl Bar;`
|
// Named `type Foo = impl Bar;`
|
||||||
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
|
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => {
|
||||||
if in_assoc_ty {
|
if in_assoc_ty {
|
||||||
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
|
self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#![allow(rustc::untranslatable_diagnostic)]
|
#![allow(rustc::untranslatable_diagnostic)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
#![feature(extend_one)]
|
#![feature(extend_one)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
@ -379,13 +379,15 @@ impl LateLintPass<'_> for Diagnostics {
|
|||||||
_ => return, // occurs for fns passed as args
|
_ => return, // occurs for fns passed as args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::MethodCall(segment, _recv, args, _span) => {
|
ExprKind::MethodCall(_segment, _recv, args, _span) => {
|
||||||
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
let Some((span, def_id, fn_gen_args)) = typeck_results_of_method_fn(cx, expr)
|
||||||
let fn_gen_args = cx.typeck_results().node_args(expr.hir_id);
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let mut call_tys: Vec<_> =
|
let mut call_tys: Vec<_> =
|
||||||
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
|
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
|
||||||
call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
|
call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
|
||||||
(segment.ident.span, def_id, fn_gen_args, call_tys)
|
(span, def_id, fn_gen_args, call_tys)
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ use rustc_span::symbol::Symbol;
|
|||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `unused_must_use` lint detects unused result of a type flagged as
|
/// The `unused_must_use` lint detects unused result of a type flagged as
|
||||||
@ -753,21 +754,18 @@ trait UnusedDelimLint {
|
|||||||
// fn f(){(print!(á
|
// fn f(){(print!(á
|
||||||
// ```
|
// ```
|
||||||
use rustc_ast::visit::{walk_expr, Visitor};
|
use rustc_ast::visit::{walk_expr, Visitor};
|
||||||
struct ErrExprVisitor {
|
struct ErrExprVisitor;
|
||||||
has_error: bool,
|
|
||||||
}
|
|
||||||
impl<'ast> Visitor<'ast> for ErrExprVisitor {
|
impl<'ast> Visitor<'ast> for ErrExprVisitor {
|
||||||
fn visit_expr(&mut self, expr: &'ast ast::Expr) {
|
type Result = ControlFlow<()>;
|
||||||
|
fn visit_expr(&mut self, expr: &'ast ast::Expr) -> ControlFlow<()> {
|
||||||
if let ExprKind::Err(_) = expr.kind {
|
if let ExprKind::Err(_) = expr.kind {
|
||||||
self.has_error = true;
|
ControlFlow::Break(())
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
walk_expr(self, expr)
|
walk_expr(self, expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut visitor = ErrExprVisitor { has_error: false };
|
}
|
||||||
visitor.visit_expr(value);
|
if ErrExprVisitor.visit_expr(value).is_break() {
|
||||||
if visitor.has_error {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let spans = match value.kind {
|
let spans = match value.kind {
|
||||||
|
@ -451,14 +451,30 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||||||
Options.ObjectFilenameForDebug = OutputObjFile;
|
Options.ObjectFilenameForDebug = OutputObjFile;
|
||||||
}
|
}
|
||||||
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
|
if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) {
|
||||||
|
#if LLVM_VERSION_GE(19, 0)
|
||||||
|
Options.MCOptions.CompressDebugSections = DebugCompressionType::Zlib;
|
||||||
|
#else
|
||||||
Options.CompressDebugSections = DebugCompressionType::Zlib;
|
Options.CompressDebugSections = DebugCompressionType::Zlib;
|
||||||
|
#endif
|
||||||
} else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
|
} else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) {
|
||||||
|
#if LLVM_VERSION_GE(19, 0)
|
||||||
|
Options.MCOptions.CompressDebugSections = DebugCompressionType::Zstd;
|
||||||
|
#else
|
||||||
Options.CompressDebugSections = DebugCompressionType::Zstd;
|
Options.CompressDebugSections = DebugCompressionType::Zstd;
|
||||||
|
#endif
|
||||||
} else if (!strcmp("none", DebugInfoCompression)) {
|
} else if (!strcmp("none", DebugInfoCompression)) {
|
||||||
|
#if LLVM_VERSION_GE(19, 0)
|
||||||
|
Options.MCOptions.CompressDebugSections = DebugCompressionType::None;
|
||||||
|
#else
|
||||||
Options.CompressDebugSections = DebugCompressionType::None;
|
Options.CompressDebugSections = DebugCompressionType::None;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LLVM_VERSION_GE(19, 0)
|
||||||
|
Options.MCOptions.X86RelaxRelocations = RelaxELFRelocations;
|
||||||
|
#else
|
||||||
Options.RelaxELFRelocations = RelaxELFRelocations;
|
Options.RelaxELFRelocations = RelaxELFRelocations;
|
||||||
|
#endif
|
||||||
Options.UseInitArray = UseInitArray;
|
Options.UseInitArray = UseInitArray;
|
||||||
|
|
||||||
#if LLVM_VERSION_LT(17, 0)
|
#if LLVM_VERSION_LT(17, 0)
|
||||||
|
@ -1549,6 +1549,31 @@ LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
|||||||
Name));
|
Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" LLVMValueRef
|
||||||
|
LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
|
||||||
|
LLVMBasicBlockRef DefaultDest,
|
||||||
|
LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
|
||||||
|
LLVMValueRef *Args, unsigned NumArgs,
|
||||||
|
OperandBundleDef **OpBundles, unsigned NumOpBundles,
|
||||||
|
const char *Name) {
|
||||||
|
Value *Callee = unwrap(Fn);
|
||||||
|
FunctionType *FTy = unwrap<FunctionType>(Ty);
|
||||||
|
|
||||||
|
// FIXME: Is there a way around this?
|
||||||
|
std::vector<BasicBlock*> IndirectDestsUnwrapped;
|
||||||
|
IndirectDestsUnwrapped.reserve(NumIndirectDests);
|
||||||
|
for (unsigned i = 0; i < NumIndirectDests; ++i) {
|
||||||
|
IndirectDestsUnwrapped.push_back(unwrap(IndirectDests[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrap(unwrap(B)->CreateCallBr(
|
||||||
|
FTy, Callee, unwrap(DefaultDest),
|
||||||
|
ArrayRef<BasicBlock*>(IndirectDestsUnwrapped),
|
||||||
|
ArrayRef<Value*>(unwrap(Args), NumArgs),
|
||||||
|
ArrayRef<OperandBundleDef>(*OpBundles, NumOpBundles),
|
||||||
|
Name));
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
|
extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
|
||||||
LLVMBasicBlockRef BB) {
|
LLVMBasicBlockRef BB) {
|
||||||
auto Point = unwrap(BB)->getFirstInsertionPt();
|
auto Point = unwrap(BB)->getFirstInsertionPt();
|
||||||
|
@ -356,7 +356,7 @@ provide! { tcx, def_id, other, cdata,
|
|||||||
cdata.get_stability_implications(tcx).iter().copied().collect()
|
cdata.get_stability_implications(tcx).iter().copied().collect()
|
||||||
}
|
}
|
||||||
stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) }
|
stripped_cfg_items => { cdata.get_stripped_cfg_items(cdata.cnum, tcx) }
|
||||||
intrinsic => { cdata.get_intrinsic(def_id.index) }
|
intrinsic_raw => { cdata.get_intrinsic(def_id.index) }
|
||||||
defined_lang_items => { cdata.get_lang_items(tcx) }
|
defined_lang_items => { cdata.get_lang_items(tcx) }
|
||||||
diagnostic_items => { cdata.get_diagnostic_items() }
|
diagnostic_items => { cdata.get_diagnostic_items() }
|
||||||
missing_lang_items => { cdata.get_missing_lang_items(tcx) }
|
missing_lang_items => { cdata.get_missing_lang_items(tcx) }
|
||||||
|
@ -1716,13 +1716,13 @@ mod size_asserts {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use rustc_data_structures::static_assert_size;
|
use rustc_data_structures::static_assert_size;
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
static_assert_size!(BasicBlockData<'_>, 136);
|
static_assert_size!(BasicBlockData<'_>, 144);
|
||||||
static_assert_size!(LocalDecl<'_>, 40);
|
static_assert_size!(LocalDecl<'_>, 40);
|
||||||
static_assert_size!(SourceScopeData<'_>, 72);
|
static_assert_size!(SourceScopeData<'_>, 72);
|
||||||
static_assert_size!(Statement<'_>, 32);
|
static_assert_size!(Statement<'_>, 32);
|
||||||
static_assert_size!(StatementKind<'_>, 16);
|
static_assert_size!(StatementKind<'_>, 16);
|
||||||
static_assert_size!(Terminator<'_>, 104);
|
static_assert_size!(Terminator<'_>, 112);
|
||||||
static_assert_size!(TerminatorKind<'_>, 88);
|
static_assert_size!(TerminatorKind<'_>, 96);
|
||||||
static_assert_size!(VarDebugInfo<'_>, 88);
|
static_assert_size!(VarDebugInfo<'_>, 88);
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ pub struct MirPatch<'tcx> {
|
|||||||
resume_block: Option<BasicBlock>,
|
resume_block: Option<BasicBlock>,
|
||||||
// Only for unreachable in cleanup path.
|
// Only for unreachable in cleanup path.
|
||||||
unreachable_cleanup_block: Option<BasicBlock>,
|
unreachable_cleanup_block: Option<BasicBlock>,
|
||||||
|
// Only for unreachable not in cleanup path.
|
||||||
|
unreachable_no_cleanup_block: Option<BasicBlock>,
|
||||||
// Cached block for UnwindTerminate (with reason)
|
// Cached block for UnwindTerminate (with reason)
|
||||||
terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
|
terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
|
||||||
body_span: Span,
|
body_span: Span,
|
||||||
@ -27,6 +29,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||||||
next_local: body.local_decls.len(),
|
next_local: body.local_decls.len(),
|
||||||
resume_block: None,
|
resume_block: None,
|
||||||
unreachable_cleanup_block: None,
|
unreachable_cleanup_block: None,
|
||||||
|
unreachable_no_cleanup_block: None,
|
||||||
terminate_block: None,
|
terminate_block: None,
|
||||||
body_span: body.span,
|
body_span: body.span,
|
||||||
};
|
};
|
||||||
@ -43,9 +46,12 @@ impl<'tcx> MirPatch<'tcx> {
|
|||||||
// Check if we already have an unreachable block
|
// Check if we already have an unreachable block
|
||||||
if matches!(block.terminator().kind, TerminatorKind::Unreachable)
|
if matches!(block.terminator().kind, TerminatorKind::Unreachable)
|
||||||
&& block.statements.is_empty()
|
&& block.statements.is_empty()
|
||||||
&& block.is_cleanup
|
|
||||||
{
|
{
|
||||||
|
if block.is_cleanup {
|
||||||
result.unreachable_cleanup_block = Some(bb);
|
result.unreachable_cleanup_block = Some(bb);
|
||||||
|
} else {
|
||||||
|
result.unreachable_no_cleanup_block = Some(bb);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +101,23 @@ impl<'tcx> MirPatch<'tcx> {
|
|||||||
bb
|
bb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unreachable_no_cleanup_block(&mut self) -> BasicBlock {
|
||||||
|
if let Some(bb) = self.unreachable_no_cleanup_block {
|
||||||
|
return bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bb = self.new_block(BasicBlockData {
|
||||||
|
statements: vec![],
|
||||||
|
terminator: Some(Terminator {
|
||||||
|
source_info: SourceInfo::outermost(self.body_span),
|
||||||
|
kind: TerminatorKind::Unreachable,
|
||||||
|
}),
|
||||||
|
is_cleanup: false,
|
||||||
|
});
|
||||||
|
self.unreachable_no_cleanup_block = Some(bb);
|
||||||
|
bb
|
||||||
|
}
|
||||||
|
|
||||||
pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
|
pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
|
||||||
if let Some((cached_bb, cached_reason)) = self.terminate_block
|
if let Some((cached_bb, cached_reason)) = self.terminate_block
|
||||||
&& reason == cached_reason
|
&& reason == cached_reason
|
||||||
|
@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use crate::mir::interpret::ConstAllocation;
|
use crate::mir::interpret::ConstAllocation;
|
||||||
|
|
||||||
use super::graphviz::write_mir_fn_graphviz;
|
use super::graphviz::write_mir_fn_graphviz;
|
||||||
use rustc_ast::InlineAsmTemplatePiece;
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{
|
||||||
alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer,
|
alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, GlobalAlloc, Pointer,
|
||||||
Provenance,
|
Provenance,
|
||||||
@ -830,6 +830,9 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
InlineAsmOperand::SymStatic { def_id } => {
|
InlineAsmOperand::SymStatic { def_id } => {
|
||||||
write!(fmt, "sym_static {def_id:?}")?;
|
write!(fmt, "sym_static {def_id:?}")?;
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::Label { target_index } => {
|
||||||
|
write!(fmt, "label {target_index}")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(fmt, ", options({options:?}))")
|
write!(fmt, ", options({options:?}))")
|
||||||
@ -868,16 +871,19 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
vec!["real".into(), "unwind".into()]
|
vec!["real".into(), "unwind".into()]
|
||||||
}
|
}
|
||||||
FalseUnwind { unwind: _, .. } => vec!["real".into()],
|
FalseUnwind { unwind: _, .. } => vec!["real".into()],
|
||||||
InlineAsm { destination: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
InlineAsm { options, ref targets, unwind, .. } => {
|
||||||
vec!["return".into(), "unwind".into()]
|
let mut vec = Vec::with_capacity(targets.len() + 1);
|
||||||
|
if !options.contains(InlineAsmOptions::NORETURN) {
|
||||||
|
vec.push("return".into());
|
||||||
}
|
}
|
||||||
InlineAsm { destination: Some(_), unwind: _, .. } => {
|
vec.resize(targets.len(), "label".into());
|
||||||
vec!["return".into()]
|
|
||||||
|
if let UnwindAction::Cleanup(_) = unwind {
|
||||||
|
vec.push("unwind".into());
|
||||||
}
|
}
|
||||||
InlineAsm { destination: None, unwind: UnwindAction::Cleanup(_), .. } => {
|
|
||||||
vec!["unwind".into()]
|
vec
|
||||||
}
|
}
|
||||||
InlineAsm { destination: None, unwind: _, .. } => vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,9 +793,10 @@ pub enum TerminatorKind<'tcx> {
|
|||||||
/// used to map assembler errors back to the line in the source code.
|
/// used to map assembler errors back to the line in the source code.
|
||||||
line_spans: &'tcx [Span],
|
line_spans: &'tcx [Span],
|
||||||
|
|
||||||
/// Destination block after the inline assembly returns, unless it is
|
/// Valid targets for the inline assembly.
|
||||||
/// diverging (InlineAsmOptions::NORETURN).
|
/// The first element is the fallthrough destination, unless
|
||||||
destination: Option<BasicBlock>,
|
/// InlineAsmOptions::NORETURN is set.
|
||||||
|
targets: Vec<BasicBlock>,
|
||||||
|
|
||||||
/// Action to be taken if the inline assembly unwinds. This is present
|
/// Action to be taken if the inline assembly unwinds. This is present
|
||||||
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
|
/// if and only if InlineAsmOptions::MAY_UNWIND is set.
|
||||||
@ -918,6 +919,10 @@ pub enum InlineAsmOperand<'tcx> {
|
|||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
},
|
},
|
||||||
|
Label {
|
||||||
|
/// This represents the index into the `targets` array in `TerminatorKind::InlineAsm`.
|
||||||
|
target_index: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type for MIR `Assert` terminator error messages.
|
/// Type for MIR `Assert` terminator error messages.
|
||||||
|
@ -74,6 +74,17 @@ impl SwitchTargets {
|
|||||||
pub fn target_for_value(&self, value: u128) -> BasicBlock {
|
pub fn target_for_value(&self, value: u128) -> BasicBlock {
|
||||||
self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
|
self.iter().find_map(|(v, t)| (v == value).then_some(t)).unwrap_or_else(|| self.otherwise())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new target to the switch. But You cannot add an already present value.
|
||||||
|
#[inline]
|
||||||
|
pub fn add_target(&mut self, value: u128, bb: BasicBlock) {
|
||||||
|
let value = Pu128(value);
|
||||||
|
if self.values.contains(&value) {
|
||||||
|
bug!("target value {:?} already present", value);
|
||||||
|
}
|
||||||
|
self.values.push(value);
|
||||||
|
self.targets.insert(self.targets.len() - 1, bb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SwitchTargetsIter<'a> {
|
pub struct SwitchTargetsIter<'a> {
|
||||||
@ -336,8 +347,7 @@ pub struct Terminator<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
|
pub type Successors<'a> = impl DoubleEndedIterator<Item = BasicBlock> + 'a;
|
||||||
pub type SuccessorsMut<'a> =
|
pub type SuccessorsMut<'a> = impl DoubleEndedIterator<Item = &'a mut BasicBlock> + 'a;
|
||||||
iter::Chain<std::option::IntoIter<&'a mut BasicBlock>, slice::IterMut<'a, BasicBlock>>;
|
|
||||||
|
|
||||||
impl<'tcx> Terminator<'tcx> {
|
impl<'tcx> Terminator<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -371,40 +381,36 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
pub fn successors(&self) -> Successors<'_> {
|
pub fn successors(&self) -> Successors<'_> {
|
||||||
use self::TerminatorKind::*;
|
use self::TerminatorKind::*;
|
||||||
match *self {
|
match *self {
|
||||||
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
|
Call { target: Some(ref t), unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| Yield { resume: t, drop: Some(ref u), .. }
|
| Yield { resume: ref t, drop: Some(u), .. }
|
||||||
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
| Drop { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
| Assert { target: ref t, unwind: UnwindAction::Cleanup(u), .. }
|
||||||
| FalseUnwind { real_target: t, unwind: UnwindAction::Cleanup(ref u) }
|
| FalseUnwind { real_target: ref t, unwind: UnwindAction::Cleanup(u) } => {
|
||||||
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
|
slice::from_ref(t).into_iter().copied().chain(Some(u))
|
||||||
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
|
||||||
}
|
}
|
||||||
Goto { target: t }
|
Goto { target: ref t }
|
||||||
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
| Call { target: None, unwind: UnwindAction::Cleanup(ref t), .. }
|
||||||
| Call { target: Some(t), unwind: _, .. }
|
| Call { target: Some(ref t), unwind: _, .. }
|
||||||
| Yield { resume: t, drop: None, .. }
|
| Yield { resume: ref t, drop: None, .. }
|
||||||
| Drop { target: t, unwind: _, .. }
|
| Drop { target: ref t, unwind: _, .. }
|
||||||
| Assert { target: t, unwind: _, .. }
|
| Assert { target: ref t, unwind: _, .. }
|
||||||
| FalseUnwind { real_target: t, unwind: _ }
|
| FalseUnwind { real_target: ref t, unwind: _ } => {
|
||||||
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
slice::from_ref(t).into_iter().copied().chain(None)
|
||||||
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
|
||||||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
|
||||||
}
|
}
|
||||||
UnwindResume
|
UnwindResume
|
||||||
| UnwindTerminate(_)
|
| UnwindTerminate(_)
|
||||||
| CoroutineDrop
|
| CoroutineDrop
|
||||||
| Return
|
| Return
|
||||||
| Unreachable
|
| Unreachable
|
||||||
| Call { target: None, unwind: _, .. }
|
| Call { target: None, unwind: _, .. } => (&[]).into_iter().copied().chain(None),
|
||||||
| InlineAsm { destination: None, unwind: _, .. } => {
|
InlineAsm { ref targets, unwind: UnwindAction::Cleanup(u), .. } => {
|
||||||
None.into_iter().chain((&[]).into_iter().copied())
|
targets.iter().copied().chain(Some(u))
|
||||||
}
|
}
|
||||||
SwitchInt { ref targets, .. } => {
|
InlineAsm { ref targets, unwind: _, .. } => targets.iter().copied().chain(None),
|
||||||
None.into_iter().chain(targets.targets.iter().copied())
|
SwitchInt { ref targets, .. } => targets.targets.iter().copied().chain(None),
|
||||||
|
FalseEdge { ref real_target, imaginary_target } => {
|
||||||
|
slice::from_ref(real_target).into_iter().copied().chain(Some(imaginary_target))
|
||||||
}
|
}
|
||||||
FalseEdge { real_target, ref imaginary_target } => Some(real_target)
|
|
||||||
.into_iter()
|
|
||||||
.chain(slice::from_ref(imaginary_target).into_iter().copied()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,33 +422,31 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
| Yield { resume: ref mut t, drop: Some(ref mut u), .. }
|
||||||
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
| Drop { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||||
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
| Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. }
|
||||||
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) }
|
| FalseUnwind { real_target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u) } => {
|
||||||
| InlineAsm {
|
slice::from_mut(t).into_iter().chain(Some(u))
|
||||||
destination: Some(ref mut t),
|
}
|
||||||
unwind: UnwindAction::Cleanup(ref mut u),
|
|
||||||
..
|
|
||||||
} => Some(t).into_iter().chain(slice::from_mut(u)),
|
|
||||||
Goto { target: ref mut t }
|
Goto { target: ref mut t }
|
||||||
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
| Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
||||||
| Call { target: Some(ref mut t), unwind: _, .. }
|
| Call { target: Some(ref mut t), unwind: _, .. }
|
||||||
| Yield { resume: ref mut t, drop: None, .. }
|
| Yield { resume: ref mut t, drop: None, .. }
|
||||||
| Drop { target: ref mut t, unwind: _, .. }
|
| Drop { target: ref mut t, unwind: _, .. }
|
||||||
| Assert { target: ref mut t, unwind: _, .. }
|
| Assert { target: ref mut t, unwind: _, .. }
|
||||||
| FalseUnwind { real_target: ref mut t, unwind: _ }
|
| FalseUnwind { real_target: ref mut t, unwind: _ } => {
|
||||||
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(ref mut t), .. }
|
slice::from_mut(t).into_iter().chain(None)
|
||||||
| InlineAsm { destination: Some(ref mut t), unwind: _, .. } => {
|
|
||||||
Some(t).into_iter().chain(&mut [])
|
|
||||||
}
|
}
|
||||||
UnwindResume
|
UnwindResume
|
||||||
| UnwindTerminate(_)
|
| UnwindTerminate(_)
|
||||||
| CoroutineDrop
|
| CoroutineDrop
|
||||||
| Return
|
| Return
|
||||||
| Unreachable
|
| Unreachable
|
||||||
| Call { target: None, unwind: _, .. }
|
| Call { target: None, unwind: _, .. } => (&mut []).into_iter().chain(None),
|
||||||
| InlineAsm { destination: None, unwind: _, .. } => None.into_iter().chain(&mut []),
|
InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => {
|
||||||
SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets),
|
targets.iter_mut().chain(Some(u))
|
||||||
|
}
|
||||||
|
InlineAsm { ref mut targets, unwind: _, .. } => targets.iter_mut().chain(None),
|
||||||
|
SwitchInt { ref mut targets, .. } => targets.targets.iter_mut().chain(None),
|
||||||
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||||
Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
|
slice::from_mut(real_target).into_iter().chain(Some(imaginary_target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,7 +518,7 @@ pub enum TerminatorEdges<'mir, 'tcx> {
|
|||||||
Double(BasicBlock, BasicBlock),
|
Double(BasicBlock, BasicBlock),
|
||||||
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
|
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
|
||||||
AssignOnReturn {
|
AssignOnReturn {
|
||||||
return_: Option<BasicBlock>,
|
return_: &'mir [BasicBlock],
|
||||||
/// The cleanup block, if it exists.
|
/// The cleanup block, if it exists.
|
||||||
cleanup: Option<BasicBlock>,
|
cleanup: Option<BasicBlock>,
|
||||||
place: CallReturnPlaces<'mir, 'tcx>,
|
place: CallReturnPlaces<'mir, 'tcx>,
|
||||||
@ -578,31 +582,37 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||||||
TerminatorEdges::Double(real_target, imaginary_target)
|
TerminatorEdges::Double(real_target, imaginary_target)
|
||||||
}
|
}
|
||||||
|
|
||||||
Yield { resume: target, drop, resume_arg, value: _ } => {
|
Yield { resume: ref target, drop, resume_arg, value: _ } => {
|
||||||
TerminatorEdges::AssignOnReturn {
|
TerminatorEdges::AssignOnReturn {
|
||||||
return_: Some(target),
|
return_: slice::from_ref(target),
|
||||||
cleanup: drop,
|
cleanup: drop,
|
||||||
place: CallReturnPlaces::Yield(resume_arg),
|
place: CallReturnPlaces::Yield(resume_arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
|
Call {
|
||||||
TerminatorEdges::AssignOnReturn {
|
unwind,
|
||||||
return_: target,
|
destination,
|
||||||
|
ref target,
|
||||||
|
func: _,
|
||||||
|
args: _,
|
||||||
|
fn_span: _,
|
||||||
|
call_source: _,
|
||||||
|
} => TerminatorEdges::AssignOnReturn {
|
||||||
|
return_: target.as_ref().map(slice::from_ref).unwrap_or_default(),
|
||||||
cleanup: unwind.cleanup_block(),
|
cleanup: unwind.cleanup_block(),
|
||||||
place: CallReturnPlaces::Call(destination),
|
place: CallReturnPlaces::Call(destination),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
InlineAsm {
|
InlineAsm {
|
||||||
template: _,
|
template: _,
|
||||||
ref operands,
|
ref operands,
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination,
|
ref targets,
|
||||||
unwind,
|
unwind,
|
||||||
} => TerminatorEdges::AssignOnReturn {
|
} => TerminatorEdges::AssignOnReturn {
|
||||||
return_: destination,
|
return_: targets,
|
||||||
cleanup: unwind.cleanup_block(),
|
cleanup: unwind.cleanup_block(),
|
||||||
place: CallReturnPlaces::InlineAsm(operands),
|
place: CallReturnPlaces::InlineAsm(operands),
|
||||||
},
|
},
|
||||||
|
@ -565,7 +565,7 @@ macro_rules! make_mir_visitor {
|
|||||||
operands,
|
operands,
|
||||||
options: _,
|
options: _,
|
||||||
line_spans: _,
|
line_spans: _,
|
||||||
destination: _,
|
targets: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
for op in operands {
|
for op in operands {
|
||||||
@ -595,7 +595,8 @@ macro_rules! make_mir_visitor {
|
|||||||
self.visit_constant(value, location);
|
self.visit_constant(value, location);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Out { place: None, .. }
|
InlineAsmOperand::Out { place: None, .. }
|
||||||
| InlineAsmOperand::SymStatic { def_id: _ } => {}
|
| InlineAsmOperand::SymStatic { def_id: _ }
|
||||||
|
| InlineAsmOperand::Label { target_index: _ } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -762,6 +762,7 @@ rustc_queries! {
|
|||||||
desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
|
desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
|
||||||
cache_on_disk_if { def_id.is_local() }
|
cache_on_disk_if { def_id.is_local() }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
|
cycle_delay_bug
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps from thee `DefId` of a type to its (inferred) outlives.
|
/// Maps from thee `DefId` of a type to its (inferred) outlives.
|
||||||
@ -959,10 +960,6 @@ rustc_queries! {
|
|||||||
ensure_forwards_result_if_red
|
ensure_forwards_result_if_red
|
||||||
}
|
}
|
||||||
|
|
||||||
query collect_mod_item_types(key: LocalModDefId) {
|
|
||||||
desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Caches `CoerceUnsized` kinds for impls on custom types.
|
/// Caches `CoerceUnsized` kinds for impls on custom types.
|
||||||
query coerce_unsized_info(key: DefId) -> Result<ty::adjustment::CoerceUnsizedInfo, ErrorGuaranteed> {
|
query coerce_unsized_info(key: DefId) -> Result<ty::adjustment::CoerceUnsizedInfo, ErrorGuaranteed> {
|
||||||
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
|
desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
|
||||||
@ -1745,7 +1742,7 @@ rustc_queries! {
|
|||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
/// Whether the function is an intrinsic
|
/// Whether the function is an intrinsic
|
||||||
query intrinsic(def_id: DefId) -> Option<rustc_middle::ty::IntrinsicDef> {
|
query intrinsic_raw(def_id: DefId) -> Option<rustc_middle::ty::IntrinsicDef> {
|
||||||
desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) }
|
desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
@ -565,6 +565,9 @@ pub enum InlineAsmOperand<'tcx> {
|
|||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
},
|
},
|
||||||
|
Label {
|
||||||
|
block: BlockId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
|
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
|
||||||
|
@ -162,6 +162,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
|||||||
| Const { value: _, span: _ }
|
| Const { value: _, span: _ }
|
||||||
| SymFn { value: _, span: _ }
|
| SymFn { value: _, span: _ }
|
||||||
| SymStatic { def_id: _ } => {}
|
| SymStatic { def_id: _ } => {}
|
||||||
|
Label { block } => visitor.visit_block(&visitor.thir()[*block]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user