Merge from rustc
This commit is contained in:
commit
940cd59e39
820 changed files with 14552 additions and 6036 deletions
22
.github/workflows/ci.yml
vendored
22
.github/workflows/ci.yml
vendored
|
|
@ -417,30 +417,16 @@ jobs:
|
|||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json"
|
||||
DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-mingw-1
|
||||
- name: i686-mingw
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
SCRIPT: make ci-mingw
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-mingw-2
|
||||
- name: x86_64-mingw
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-mingw-1
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-mingw-2
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
SCRIPT: make ci-mingw
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
|
|
|
|||
43
Cargo.lock
43
Cargo.lock
|
|
@ -360,7 +360,7 @@ dependencies = [
|
|||
name = "cargo-miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.15.3",
|
||||
"cargo_metadata",
|
||||
"directories",
|
||||
"rustc-build-sysroot",
|
||||
"rustc-workspace-hack",
|
||||
|
|
@ -381,22 +381,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.14.0"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07"
|
||||
checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
|
||||
dependencies = [
|
||||
"camino",
|
||||
"cargo-platform",
|
||||
|
|
@ -631,7 +618,7 @@ name = "clippy_lints"
|
|||
version = "0.1.72"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.15.3",
|
||||
"cargo_metadata",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
"if_chain",
|
||||
|
|
@ -710,9 +697,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.92"
|
||||
version = "0.1.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64518f1ae689f74db058bbfb3238dfe6eb53f59f4ae712f1ff4348628522e190"
|
||||
checksum = "76630810d973ecea3dbf611e1b7aecfb1012751ef1ff8de3998f89014a166781"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -4348,35 +4335,33 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 1.0.102",
|
||||
"syn 2.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.5.2"
|
||||
version = "1.5.3"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"anyhow",
|
||||
"bytecount",
|
||||
"cargo_metadata 0.14.0",
|
||||
"clap 3.2.20",
|
||||
"derive-new",
|
||||
"cargo_metadata",
|
||||
"clap 4.2.1",
|
||||
"diff",
|
||||
"dirs",
|
||||
"env_logger 0.9.0",
|
||||
"env_logger 0.10.0",
|
||||
"getopts",
|
||||
"ignore",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"regex",
|
||||
"rustc-workspace-hack",
|
||||
"rustfmt-config_proc_macro",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"term",
|
||||
"thiserror",
|
||||
"toml 0.5.7",
|
||||
"toml 0.7.4",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
"unicode_categories",
|
||||
|
|
@ -4956,7 +4941,7 @@ name = "tidy"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.15.3",
|
||||
"cargo_metadata",
|
||||
"ignore",
|
||||
"lazy_static",
|
||||
"miropt-test-tools",
|
||||
|
|
@ -5192,7 +5177,7 @@ checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2"
|
|||
dependencies = [
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.15.3",
|
||||
"cargo_metadata",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"crossbeam-channel",
|
||||
|
|
|
|||
|
|
@ -1295,6 +1295,7 @@ impl Expr {
|
|||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
||||
ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
|
||||
ExprKind::Become(..) => ExprPrecedence::Become,
|
||||
ExprKind::Err => ExprPrecedence::Err,
|
||||
}
|
||||
}
|
||||
|
|
@ -1515,6 +1516,11 @@ pub enum ExprKind {
|
|||
/// with an optional value to be returned.
|
||||
Yeet(Option<P<Expr>>),
|
||||
|
||||
/// A tail call return, with the value to be returned.
|
||||
///
|
||||
/// While `.0` must be a function call, we check this later, after parsing.
|
||||
Become(P<Expr>),
|
||||
|
||||
/// Bytes included via `include_bytes!`
|
||||
/// Added for optimization purposes to avoid the need to escape
|
||||
/// large binary blobs - should always behave like [`ExprKind::Lit`]
|
||||
|
|
|
|||
|
|
@ -1457,6 +1457,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
ExprKind::Yeet(expr) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Become(expr) => vis.visit_expr(expr),
|
||||
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
|
||||
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
|
||||
ExprKind::OffsetOf(container, fields) => {
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ pub enum ExprPrecedence {
|
|||
Ret,
|
||||
Yield,
|
||||
Yeet,
|
||||
Become,
|
||||
|
||||
Range,
|
||||
|
||||
|
|
@ -298,7 +299,8 @@ impl ExprPrecedence {
|
|||
| ExprPrecedence::Continue
|
||||
| ExprPrecedence::Ret
|
||||
| ExprPrecedence::Yield
|
||||
| ExprPrecedence::Yeet => PREC_JUMP,
|
||||
| ExprPrecedence::Yeet
|
||||
| ExprPrecedence::Become => PREC_JUMP,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
|
|
|
|||
|
|
@ -908,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
ExprKind::Yeet(optional_expression) => {
|
||||
walk_list!(visitor, visit_expr, optional_expression);
|
||||
}
|
||||
ExprKind::Become(expr) => visitor.visit_expr(expr),
|
||||
ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
|
||||
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
|
||||
|
|
|
|||
|
|
@ -275,6 +275,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Ret(e)
|
||||
}
|
||||
ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
|
||||
ExprKind::Become(sub_expr) => {
|
||||
let sub_expr = self.lower_expr(sub_expr);
|
||||
|
||||
// FIXME(explicit_tail_calls): Use `hir::ExprKind::Become` once we implemented it
|
||||
hir::ExprKind::Ret(Some(sub_expr))
|
||||
}
|
||||
ExprKind::InlineAsm(asm) => {
|
||||
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
|||
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
|
|
|
|||
|
|
@ -537,6 +537,11 @@ impl<'a> State<'a> {
|
|||
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(result, parser::PREC_JUMP);
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
self.word("asm!");
|
||||
|
|
|
|||
|
|
@ -72,8 +72,11 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||
let kind = match self.kind {
|
||||
mir::BorrowKind::Shared => "",
|
||||
mir::BorrowKind::Shallow => "shallow ",
|
||||
mir::BorrowKind::Unique => "uniq ",
|
||||
mir::BorrowKind::Mut { .. } => "mut ",
|
||||
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::ClosureCapture } => "uniq ",
|
||||
// FIXME: differentiate `TwoPhaseBorrow`
|
||||
mir::BorrowKind::Mut {
|
||||
kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow,
|
||||
} => "mut ",
|
||||
};
|
||||
write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
move_from_span: Span,
|
||||
move_from_desc: &str,
|
||||
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
|
||||
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc,)
|
||||
struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc)
|
||||
}
|
||||
|
||||
/// Signal an error due to an attempt to move out of the interior
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ use rustc_infer::traits::ObligationCause;
|
|||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, Operand, Place,
|
||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
|
||||
use rustc_middle::util::CallKind;
|
||||
|
|
@ -678,7 +679,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
// Find out if the predicates show that the type is a Fn or FnMut
|
||||
let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder()
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = pred.kind().skip_binder()
|
||||
&& pred.self_ty() == ty
|
||||
{
|
||||
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
|
||||
|
|
@ -704,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.subst_iter_copied(tcx, substs)
|
||||
.find_map(find_fn_kind_from_did),
|
||||
.find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))),
|
||||
ty::Closure(_, substs) => match substs.as_closure().kind() {
|
||||
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
|
||||
ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
|
||||
|
|
@ -775,7 +776,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let predicates: Result<Vec<_>, _> = errors
|
||||
.into_iter()
|
||||
.map(|err| match err.obligation.predicate.kind().skip_binder() {
|
||||
PredicateKind::Clause(ty::Clause::Trait(predicate)) => {
|
||||
PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
|
||||
match predicate.self_ty().kind() {
|
||||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
|
|
@ -926,7 +927,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// FIXME: supply non-"" `opt_via` when appropriate
|
||||
let first_borrow_desc;
|
||||
let mut err = match (gen_borrow_kind, issued_borrow.kind) {
|
||||
(BorrowKind::Shared, BorrowKind::Mut { .. }) => {
|
||||
(
|
||||
BorrowKind::Shared,
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||
) => {
|
||||
first_borrow_desc = "mutable ";
|
||||
self.cannot_reborrow_already_borrowed(
|
||||
span,
|
||||
|
|
@ -940,7 +944,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
None,
|
||||
)
|
||||
}
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
|
||||
(
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||
BorrowKind::Shared,
|
||||
) => {
|
||||
first_borrow_desc = "immutable ";
|
||||
let mut err = self.cannot_reborrow_already_borrowed(
|
||||
span,
|
||||
|
|
@ -962,7 +969,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
|
||||
(
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
|
||||
) => {
|
||||
first_borrow_desc = "first ";
|
||||
let mut err = self.cannot_mutably_borrow_multiply(
|
||||
span,
|
||||
|
|
@ -985,12 +995,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
(BorrowKind::Unique, BorrowKind::Unique) => {
|
||||
(
|
||||
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
|
||||
BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture },
|
||||
) => {
|
||||
first_borrow_desc = "first ";
|
||||
self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Shallow) => {
|
||||
if let Some(immutable_section_description) =
|
||||
self.classify_immutable_section(issued_borrow.assigned_place)
|
||||
{
|
||||
|
|
@ -1004,7 +1017,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
&mut err,
|
||||
Some(BorrowKind::Unique),
|
||||
Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
|
|
@ -1038,7 +1051,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
(BorrowKind::Unique, _) => {
|
||||
(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, _) => {
|
||||
first_borrow_desc = "first ";
|
||||
self.cannot_uniquely_borrow_by_one_closure(
|
||||
span,
|
||||
|
|
@ -1052,7 +1065,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Shared, BorrowKind::Unique) => {
|
||||
(BorrowKind::Shared, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
|
||||
first_borrow_desc = "first ";
|
||||
self.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
|
|
@ -1067,7 +1080,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Unique) => {
|
||||
(BorrowKind::Mut { .. }, BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }) => {
|
||||
first_borrow_desc = "first ";
|
||||
self.cannot_reborrow_already_uniquely_borrowed(
|
||||
span,
|
||||
|
|
@ -1085,10 +1098,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
(BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
|
||||
| (
|
||||
BorrowKind::Shallow,
|
||||
BorrowKind::Mut { .. }
|
||||
| BorrowKind::Unique
|
||||
| BorrowKind::Shared
|
||||
| BorrowKind::Shallow,
|
||||
BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow,
|
||||
) => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
@ -2579,7 +2589,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut Diagnostic) {
|
||||
let tcx = self.infcx.tcx;
|
||||
if let (
|
||||
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
|
||||
Some(Terminator {
|
||||
kind: TerminatorKind::Call { call_source: CallSource::OverloadedOperator, .. },
|
||||
..
|
||||
}),
|
||||
Some((method_did, method_substs)),
|
||||
) = (
|
||||
&self.body[loan.reserve_location.block].terminator,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor;
|
|||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::{
|
||||
Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
|
||||
Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
|
||||
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::PointerCast;
|
||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
|
|
@ -494,7 +494,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} else if self.was_captured_by_trait_object(borrow) {
|
||||
LaterUseKind::TraitCapture
|
||||
} else if location.statement_index == block.statements.len() {
|
||||
if let TerminatorKind::Call { func, from_hir_call: true, .. } =
|
||||
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
|
||||
&block.terminator().kind
|
||||
{
|
||||
// Just point to the function, to reduce the chance of overlapping spans.
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@ use rustc_index::IndexSlice;
|
|||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
|
||||
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
|
|
@ -414,7 +415,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if !is_terminator {
|
||||
continue;
|
||||
} else if let Some(Terminator {
|
||||
kind: TerminatorKind::Call { func, from_hir_call: false, .. },
|
||||
kind:
|
||||
TerminatorKind::Call {
|
||||
func,
|
||||
call_source: CallSource::OverloadedOperator,
|
||||
..
|
||||
},
|
||||
..
|
||||
}) = &bbd.terminator
|
||||
{
|
||||
|
|
@ -622,8 +628,7 @@ impl UseSpans<'_> {
|
|||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Shallow
|
||||
| rustc_middle::mir::BorrowKind::Unique => {
|
||||
| rustc_middle::mir::BorrowKind::Shallow => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
|
|
@ -839,7 +844,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
debug!("move_spans: target_temp = {:?}", target_temp);
|
||||
|
||||
if let Some(Terminator {
|
||||
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
|
||||
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
|
||||
}) = &self.body[location.block].terminator
|
||||
{
|
||||
let Some((method_did, method_substs)) =
|
||||
|
|
@ -859,7 +864,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
method_did,
|
||||
method_substs,
|
||||
*fn_span,
|
||||
*from_hir_call,
|
||||
call_source.from_hir_call(),
|
||||
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }),
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
let place = self.describe_any_place(access_place.as_ref());
|
||||
crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
|
||||
|
|
@ -300,7 +300,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
_,
|
||||
mir::Rvalue::Ref(
|
||||
_,
|
||||
mir::BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
|
||||
_,
|
||||
),
|
||||
)),
|
||||
|
|
|
|||
|
|
@ -939,8 +939,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||
{
|
||||
predicates.iter().any(|pred| {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) if data.self_ty() == ty => {}
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(data)) if data.projection_ty.self_ty() == ty => {}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty() == ty => {}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if data.projection_ty.self_ty() == ty => {}
|
||||
_ => return false,
|
||||
}
|
||||
tcx.any_free_region_meets(pred, |r| {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
destination,
|
||||
target: _,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
call_source: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
self.consume_operand(location, func);
|
||||
|
|
@ -255,7 +255,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
}
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => {
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
(Deep, Reservation(wk))
|
||||
|
|
@ -273,7 +273,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
Mutability::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
kind: mir::MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
|
|
@ -376,14 +376,11 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
(Read(_), BorrowKind::Shallow | BorrowKind::Shared)
|
||||
| (
|
||||
Read(ReadKind::Borrow(BorrowKind::Shallow)),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. },
|
||||
) => {
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
||||
// Reads don't invalidate shared or shallow borrows
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
|
||||
(Read(_), BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(&this.dominators, borrow, location) {
|
||||
// If the borrow isn't active yet, reads don't invalidate it
|
||||
|
|
@ -425,7 +422,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
self.access_place(
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ use rustc_infer::infer::{
|
|||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_middle::mir::{
|
||||
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
|
||||
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
|
||||
traversal, Body, ClearCrossCrate, Local, Location, MutBorrowKind, Mutability,
|
||||
NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, VarDebugInfoContents,
|
||||
};
|
||||
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||
|
|
@ -710,7 +710,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
|||
destination,
|
||||
target: _,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
call_source: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
self.consume_operand(loc, (func, span), flow_state);
|
||||
|
|
@ -1071,10 +1071,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Shallow)
|
||||
| (
|
||||
Read(ReadKind::Borrow(BorrowKind::Shallow)),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. },
|
||||
) => Control::Continue,
|
||||
| (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
|
||||
Control::Continue
|
||||
}
|
||||
|
||||
(Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
|
||||
// This used to be a future compatibility warning (to be
|
||||
|
|
@ -1087,7 +1086,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Control::Continue
|
||||
}
|
||||
|
||||
(Read(kind), BorrowKind::Unique | BorrowKind::Mut { .. }) => {
|
||||
(Read(kind), BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators(), borrow, location) {
|
||||
assert!(allow_two_phase_borrow(borrow.kind));
|
||||
|
|
@ -1194,7 +1193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
(Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk)))
|
||||
}
|
||||
BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))),
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => {
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
(Deep, Reservation(wk))
|
||||
|
|
@ -1231,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
Mutability::Mut => (
|
||||
Deep,
|
||||
Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
kind: MutBorrowKind::Default,
|
||||
})),
|
||||
),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
|
|
@ -1565,7 +1564,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// only mutable borrows should be 2-phase
|
||||
assert!(match borrow.kind {
|
||||
BorrowKind::Shared | BorrowKind::Shallow => false,
|
||||
BorrowKind::Unique | BorrowKind::Mut { .. } => true,
|
||||
BorrowKind::Mut { .. } => true,
|
||||
});
|
||||
|
||||
self.access_place(
|
||||
|
|
@ -1959,16 +1958,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let the_place_err;
|
||||
|
||||
match kind {
|
||||
Reservation(WriteKind::MutableBorrow(
|
||||
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
|
||||
))
|
||||
| Write(WriteKind::MutableBorrow(
|
||||
borrow_kind @ (BorrowKind::Unique | BorrowKind::Mut { .. }),
|
||||
)) => {
|
||||
let is_local_mutation_allowed = match borrow_kind {
|
||||
BorrowKind::Unique => LocalMutationIsAllowed::Yes,
|
||||
BorrowKind::Mut { .. } => is_local_mutation_allowed,
|
||||
BorrowKind::Shared | BorrowKind::Shallow => unreachable!(),
|
||||
Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind }))
|
||||
| Write(WriteKind::MutableBorrow(BorrowKind::Mut { kind: mut_borrow_kind })) => {
|
||||
let is_local_mutation_allowed = match mut_borrow_kind {
|
||||
// `ClosureCapture` is used for mutable variable with a immutable binding.
|
||||
// This is only behaviour difference between `ClosureCapture` and mutable borrows.
|
||||
MutBorrowKind::ClosureCapture => LocalMutationIsAllowed::Yes,
|
||||
MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow => {
|
||||
is_local_mutation_allowed
|
||||
}
|
||||
};
|
||||
match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
|
||||
Ok(root_place) => {
|
||||
|
|
@ -2031,12 +2029,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
Read(
|
||||
ReadKind::Borrow(
|
||||
BorrowKind::Unique
|
||||
| BorrowKind::Mut { .. }
|
||||
| BorrowKind::Shared
|
||||
| BorrowKind::Shallow,
|
||||
)
|
||||
ReadKind::Borrow(BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Shallow)
|
||||
| ReadKind::Copy,
|
||||
) => {
|
||||
// Access authorized
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ use crate::ArtificialField;
|
|||
use crate::Overlap;
|
||||
use crate::{AccessDepth, Deep, Shallow};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::mir::{
|
||||
Body, BorrowKind, Local, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,
|
||||
};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use std::cmp::max;
|
||||
use std::iter;
|
||||
|
|
@ -35,7 +37,7 @@ pub fn places_conflict<'tcx>(
|
|||
tcx,
|
||||
body,
|
||||
borrow_place,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: true },
|
||||
BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow },
|
||||
access_place.as_ref(),
|
||||
AccessDepth::Deep,
|
||||
bias,
|
||||
|
|
|
|||
|
|
@ -330,8 +330,9 @@ fn check_opaque_type_well_formed<'tcx>(
|
|||
// Require the hidden type to be well-formed with only the generics of the opaque type.
|
||||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
// hidden type is well formed even without those bounds.
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(definition_ty.into())));
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
definition_ty.into(),
|
||||
)));
|
||||
ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
|
|
|||
|
|
@ -89,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
self.prove_predicate(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
}))),
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: ty::BoundConstness::NotConst,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
},
|
||||
))),
|
||||
locations,
|
||||
category,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
)?;
|
||||
|
||||
ocx.infcx.add_item_bounds_for_hidden_type(
|
||||
opaque_type_key,
|
||||
opaque_type_key.def_id.to_def_id(),
|
||||
opaque_type_key.substs,
|
||||
cause,
|
||||
param_env,
|
||||
hidden_ty.ty,
|
||||
|
|
@ -1370,7 +1371,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
// FIXME: check the values
|
||||
}
|
||||
TerminatorKind::Call { func, args, destination, from_hir_call, target, .. } => {
|
||||
TerminatorKind::Call { func, args, destination, call_source, target, .. } => {
|
||||
self.check_operand(func, term_location);
|
||||
for arg in args {
|
||||
self.check_operand(arg, term_location);
|
||||
|
|
@ -1420,7 +1421,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// See #91068 for an example.
|
||||
self.prove_predicates(
|
||||
sig.inputs_and_output.iter().map(|ty| {
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
ty.into(),
|
||||
)))
|
||||
}),
|
||||
|
|
@ -1446,7 +1447,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
.add_element(region_vid, term_location);
|
||||
}
|
||||
|
||||
self.check_call_inputs(body, term, &sig, args, term_location, *from_hir_call);
|
||||
self.check_call_inputs(body, term, &sig, args, term_location, *call_source);
|
||||
}
|
||||
TerminatorKind::Assert { cond, msg, .. } => {
|
||||
self.check_operand(cond, term_location);
|
||||
|
|
@ -1573,7 +1574,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
sig: &ty::FnSig<'tcx>,
|
||||
args: &[Operand<'tcx>],
|
||||
term_location: Location,
|
||||
from_hir_call: bool,
|
||||
call_source: CallSource,
|
||||
) {
|
||||
debug!("check_call_inputs({:?}, {:?})", sig, args);
|
||||
if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) {
|
||||
|
|
@ -1591,7 +1592,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let op_arg_ty = op_arg.ty(body, self.tcx());
|
||||
|
||||
let op_arg_ty = self.normalize(op_arg_ty, term_location);
|
||||
let category = if from_hir_call {
|
||||
let category = if call_source.from_hir_call() {
|
||||
ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
|
||||
} else {
|
||||
ConstraintCategory::Boring
|
||||
|
|
@ -1852,7 +1853,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
let array_ty = rvalue.ty(body.local_decls(), tcx);
|
||||
self.prove_predicate(
|
||||
ty::PredicateKind::Clause(ty::Clause::WellFormed(array_ty.into())),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())),
|
||||
Locations::Single(location),
|
||||
ConstraintCategory::Boring,
|
||||
);
|
||||
|
|
@ -2025,10 +2026,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::Cast,
|
||||
);
|
||||
|
||||
let outlives_predicate =
|
||||
tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::Clause::TypeOutlives(ty::OutlivesPredicate(self_ty, *region)),
|
||||
)));
|
||||
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
|
||||
ty::OutlivesPredicate(self_ty, *region),
|
||||
)),
|
||||
));
|
||||
self.prove_predicate(
|
||||
outlives_predicate,
|
||||
location.to_locations(),
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::While(_, _, _)
|
||||
| ExprKind::Yeet(_)
|
||||
| ExprKind::Become(_)
|
||||
| ExprKind::Yield(_) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::errors;
|
|||
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
|
||||
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, attr};
|
||||
use rustc_ast::{self as ast, attr, GenericParamKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_expand::base::*;
|
||||
|
|
@ -122,11 +122,7 @@ pub fn expand_test_or_bench(
|
|||
let ast::ItemKind::Fn(fn_) = &item.kind else {
|
||||
not_testable_error(cx, attr_sp, Some(&item));
|
||||
return if is_stmt {
|
||||
vec![Annotatable::Stmt(P(ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: item.span,
|
||||
kind: ast::StmtKind::Item(item),
|
||||
}))]
|
||||
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
|
||||
} else {
|
||||
vec![Annotatable::Item(item)]
|
||||
};
|
||||
|
|
@ -138,7 +134,11 @@ pub fn expand_test_or_bench(
|
|||
if (!is_bench && !has_test_signature(cx, &item))
|
||||
|| (is_bench && !has_bench_signature(cx, &item))
|
||||
{
|
||||
return vec![Annotatable::Item(item)];
|
||||
return if is_stmt {
|
||||
vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
|
||||
} else {
|
||||
vec![Annotatable::Item(item)]
|
||||
};
|
||||
}
|
||||
|
||||
let sp = cx.with_def_site_ctxt(item.span);
|
||||
|
|
@ -550,24 +550,21 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
match (has_output, has_should_panic_attr) {
|
||||
(true, true) => {
|
||||
sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
|
||||
false
|
||||
}
|
||||
(true, false) => {
|
||||
if !generics.params.is_empty() {
|
||||
sd.span_err(
|
||||
i.span,
|
||||
"functions used as tests must have signature fn() -> ()",
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
(false, _) => true,
|
||||
if has_should_panic_attr && has_output {
|
||||
sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
|
||||
return false;
|
||||
}
|
||||
|
||||
if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime))
|
||||
{
|
||||
sd.span_err(
|
||||
i.span,
|
||||
"functions used as tests can not have any non-lifetime generic parameters",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
// should be unreachable because `is_test_fn_item` should catch all non-fn items
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
target,
|
||||
fn_span,
|
||||
unwind: _,
|
||||
from_hir_call: _,
|
||||
call_source: _,
|
||||
} => {
|
||||
fx.tcx.prof.generic_activity("codegen call").run(|| {
|
||||
crate::abi::codegen_terminator_call(
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
|
||||
match bin_op {
|
||||
BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
|
||||
BinOp::Add | BinOp::Sub => None,
|
||||
BinOp::Mul => {
|
||||
BinOp::Add | BinOp::AddUnchecked | BinOp::Sub | BinOp::SubUnchecked => None,
|
||||
BinOp::Mul | BinOp::MulUnchecked => {
|
||||
let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
let ret_val = fx.lib_call(
|
||||
"__multi3",
|
||||
|
|
@ -69,7 +69,7 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
}
|
||||
}
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
|
||||
BinOp::Shl | BinOp::Shr => None,
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,9 +131,10 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
fx.lib_call(name, param_types, vec![], &args);
|
||||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
||||
BinOp::Div | BinOp::Rem => unreachable!(),
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
|
||||
BinOp::Shl | BinOp::Shr => unreachable!(),
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -472,25 +472,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
|
||||
}
|
||||
|
||||
sym::unchecked_add
|
||||
| sym::unchecked_sub
|
||||
| sym::unchecked_mul
|
||||
| sym::exact_div
|
||||
| sym::unchecked_shl
|
||||
| sym::unchecked_shr => {
|
||||
sym::exact_div => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
||||
// FIXME trap on overflow
|
||||
let bin_op = match intrinsic {
|
||||
sym::unchecked_add => BinOp::Add,
|
||||
sym::unchecked_sub => BinOp::Sub,
|
||||
sym::unchecked_mul => BinOp::Mul,
|
||||
sym::exact_div => BinOp::Div,
|
||||
sym::unchecked_shl => BinOp::Shl,
|
||||
sym::unchecked_shr => BinOp::Shr,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
|
||||
// FIXME trap on inexact
|
||||
let res = crate::num::codegen_int_binop(fx, BinOp::Div, x, y);
|
||||
ret.write_cvalue(fx, res);
|
||||
}
|
||||
sym::saturating_add | sym::saturating_sub => {
|
||||
|
|
|
|||
|
|
@ -128,10 +128,11 @@ pub(crate) fn codegen_int_binop<'tcx>(
|
|||
let rhs = in_rhs.load_scalar(fx);
|
||||
|
||||
let b = fx.bcx.ins();
|
||||
// FIXME trap on overflow for the Unchecked versions
|
||||
let val = match bin_op {
|
||||
BinOp::Add => b.iadd(lhs, rhs),
|
||||
BinOp::Sub => b.isub(lhs, rhs),
|
||||
BinOp::Mul => b.imul(lhs, rhs),
|
||||
BinOp::Add | BinOp::AddUnchecked => b.iadd(lhs, rhs),
|
||||
BinOp::Sub | BinOp::SubUnchecked => b.isub(lhs, rhs),
|
||||
BinOp::Mul | BinOp::MulUnchecked => b.imul(lhs, rhs),
|
||||
BinOp::Div => {
|
||||
if signed {
|
||||
b.sdiv(lhs, rhs)
|
||||
|
|
@ -149,16 +150,19 @@ pub(crate) fn codegen_int_binop<'tcx>(
|
|||
BinOp::BitXor => b.bxor(lhs, rhs),
|
||||
BinOp::BitAnd => b.band(lhs, rhs),
|
||||
BinOp::BitOr => b.bor(lhs, rhs),
|
||||
BinOp::Shl => b.ishl(lhs, rhs),
|
||||
BinOp::Shr => {
|
||||
BinOp::Shl | BinOp::ShlUnchecked => b.ishl(lhs, rhs),
|
||||
BinOp::Shr | BinOp::ShrUnchecked => {
|
||||
if signed {
|
||||
b.sshr(lhs, rhs)
|
||||
} else {
|
||||
b.ushr(lhs, rhs)
|
||||
}
|
||||
}
|
||||
BinOp::Offset => unreachable!("Offset is not an integer operation"),
|
||||
// Compare binops handles by `codegen_binop`.
|
||||
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty),
|
||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
|
||||
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
|
||||
}
|
||||
};
|
||||
|
||||
CValue::by_val(val, in_lhs.layout())
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ jobs:
|
|||
matrix:
|
||||
libgccjit_version:
|
||||
- { gcc: "libgccjit.so", artifacts_branch: "master" }
|
||||
commands: [
|
||||
"--test-successful-rustc --nb-parts 2 --current-part 0",
|
||||
"--test-successful-rustc --nb-parts 2 --current-part 1",
|
||||
cargo_runner: [
|
||||
"sde -future -rtm_mode full --",
|
||||
"",
|
||||
]
|
||||
|
||||
steps:
|
||||
|
|
@ -36,6 +36,20 @@ jobs:
|
|||
- name: Install packages
|
||||
run: sudo apt-get install ninja-build ripgrep
|
||||
|
||||
- name: Install Intel Software Development Emulator
|
||||
if: ${{ matrix.cargo_runner }}
|
||||
run: |
|
||||
mkdir intel-sde
|
||||
cd intel-sde
|
||||
dir=sde-external-9.14.0-2022-10-25-lin
|
||||
file=$dir.tar.xz
|
||||
wget https://downloadmirror.intel.com/751535/$file
|
||||
tar xvf $file
|
||||
sudo mkdir /usr/share/intel-sde
|
||||
sudo cp -r $dir/* /usr/share/intel-sde
|
||||
sudo ln -s /usr/share/intel-sde/sde /usr/bin/sde
|
||||
sudo ln -s /usr/share/intel-sde/sde64 /usr/bin/sde64
|
||||
|
||||
- name: Download artifact
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
|
|
@ -91,6 +105,10 @@ jobs:
|
|||
./prepare_build.sh
|
||||
./build.sh --release --release-sysroot
|
||||
cargo test
|
||||
|
||||
- name: Clean
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
./clean_all.sh
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
@ -107,10 +125,18 @@ jobs:
|
|||
args: --release
|
||||
|
||||
- name: Run tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
|
||||
|
||||
- name: Run stdarch tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
cd build_sysroot/sysroot_src/library/stdarch/
|
||||
CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test
|
||||
|
||||
- name: Run stdarch tests
|
||||
if: ${{ matrix.cargo_runner }}
|
||||
run: |
|
||||
cd build_sysroot/sysroot_src/library/stdarch/
|
||||
STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a
|
||||
|
|
|
|||
2
compiler/rustc_codegen_gcc/.gitignore
vendored
2
compiler/rustc_codegen_gcc/.gitignore
vendored
|
|
@ -23,3 +23,5 @@ benchmarks
|
|||
tools/llvm-project
|
||||
tools/llvmint
|
||||
tools/llvmint-2
|
||||
# The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics.
|
||||
llvm
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gccjit"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984"
|
||||
dependencies = [
|
||||
"gccjit_sys",
|
||||
]
|
||||
|
|
@ -43,7 +43,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gccjit_sys"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#fe242b7eb26980e6c78859d51c8d4cc1e43381a3"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ Using git-subtree with `rustc` requires a patched git to make it work.
|
|||
The PR that is needed is [here](https://github.com/gitgitgadget/git/pull/493).
|
||||
Use the following instructions to install it:
|
||||
|
||||
```
|
||||
```bash
|
||||
git clone git@github.com:tqc/git.git
|
||||
cd git
|
||||
git checkout tqc/subtree
|
||||
|
|
@ -204,6 +204,21 @@ make
|
|||
cp git-subtree ~/bin
|
||||
```
|
||||
|
||||
Then, do a sync with this command:
|
||||
|
||||
```bash
|
||||
PATH="$HOME/bin:$PATH" ~/bin/git-subtree push -P compiler/rustc_codegen_gcc/ ../rustc_codegen_gcc/ sync_branch_name
|
||||
cd ../rustc_codegen_gcc
|
||||
git checkout master
|
||||
git pull
|
||||
git checkout sync_branch_name
|
||||
git merge master
|
||||
```
|
||||
|
||||
TODO: write a script that does the above.
|
||||
|
||||
https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.20madness/near/258877725
|
||||
|
||||
### How to use [mem-trace](https://github.com/antoyo/mem-trace)
|
||||
|
||||
`rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ compiler_builtins = "0.1"
|
|||
alloc = { path = "./sysroot_src/library/alloc" }
|
||||
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
|
||||
test = { path = "./sysroot_src/library/test" }
|
||||
proc_macro = { path = "./sysroot_src/library/proc_macro" }
|
||||
|
||||
[patch.crates-io]
|
||||
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ git config user.name || git config user.name "None"
|
|||
|
||||
git commit -m "Initial commit" -q
|
||||
for file in $(ls ../../patches/ | grep -v patcha); do
|
||||
echo "[GIT] apply" $file
|
||||
git apply ../../patches/$file
|
||||
git add -A
|
||||
git commit --no-gpg-sign -m "Patch $file"
|
||||
echo "[GIT] apply" $file
|
||||
git apply ../../patches/$file
|
||||
git add -A
|
||||
git commit --no-gpg-sign -m "Patch $file"
|
||||
done
|
||||
popd
|
||||
|
||||
|
|
|
|||
|
|
@ -451,6 +451,9 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
|||
drop_in_place(to_drop);
|
||||
}
|
||||
|
||||
#[lang = "unpin"]
|
||||
pub auto trait Unpin {}
|
||||
|
||||
#[lang = "deref"]
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
|
|
@ -488,10 +491,23 @@ pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A);
|
|||
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
|
||||
|
||||
impl<T> Box<T> {
|
||||
pub fn new(val: T) -> Box<T> {
|
||||
unsafe {
|
||||
let size = intrinsics::size_of::<T>();
|
||||
let ptr = libc::malloc(size);
|
||||
intrinsics::copy(&val as *const T as *const u8, ptr, size);
|
||||
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A: Allocator> Drop for Box<T, A> {
|
||||
fn drop(&mut self) {
|
||||
// inner value is dropped by compiler
|
||||
libc::free(self.pointer.0 as *mut u8);
|
||||
// inner value is dropped by compiler.
|
||||
unsafe {
|
||||
libc::free(self.0.pointer.0 as *mut u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,9 @@ fn main() {
|
|||
world as Box<dyn SomeTrait>;
|
||||
|
||||
assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
|
||||
assert_eq!(intrinsics::bitreverse(0xddccu16), 0x33bbu16);
|
||||
assert_eq!(intrinsics::bitreverse(0xffee_ddccu32), 0x33bb77ffu32);
|
||||
assert_eq!(intrinsics::bitreverse(0x1234_5678_ffee_ddccu64), 0x33bb77ff1e6a2c48u64);
|
||||
|
||||
assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
|
||||
assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ fn main() {
|
|||
|
||||
assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
|
||||
assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
|
||||
assert_eq!(0x1234_5678_ffee_ddcc_1234_5678_ffee_ddccu128.reverse_bits(), 0x33bb77ff1e6a2c4833bb77ff1e6a2c48u128);
|
||||
|
||||
let _d = 0i128.checked_div(2i128);
|
||||
let _d = 0u128.checked_div(2u128);
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ tests/ui/issues/issue-40883.rs
|
|||
tests/ui/issues/issue-43853.rs
|
||||
tests/ui/issues/issue-47364.rs
|
||||
tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
|
||||
tests/ui/rfc-2091-track-caller/std-panic-locations.rs
|
||||
tests/ui/rfcs/rfc1857-drop-order.rs
|
||||
tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs
|
||||
tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs
|
||||
tests/ui/simd/issue-17170.rs
|
||||
tests/ui/simd/issue-39720.rs
|
||||
tests/ui/simd/issue-89193.rs
|
||||
|
|
@ -66,3 +66,5 @@ tests/ui/generator/panic-safe.rs
|
|||
tests/ui/issues/issue-14875.rs
|
||||
tests/ui/issues/issue-29948.rs
|
||||
tests/ui/panic-while-printing.rs
|
||||
tests/ui/enum-discriminant/get_discr.rs
|
||||
tests/ui/panics/nested_panic_caught.rs
|
||||
|
|
|
|||
|
|
@ -1,49 +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/library/core/tests/array.rs b/library/core/tests/array.rs
|
||||
index 4bc44e9..8e3c7a4 100644
|
||||
--- a/library/core/tests/array.rs
|
||||
+++ b/library/core/tests/array.rs
|
||||
@@ -242,6 +242,7 @@ fn iterator_drops() {
|
||||
assert_eq!(i.get(), 5);
|
||||
}
|
||||
|
||||
+/*
|
||||
// This test does not work on targets without panic=unwind support.
|
||||
// To work around this problem, test is marked is should_panic, so it will
|
||||
// be automagically skipped on unsuitable targets, such as
|
||||
@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
|
||||
assert_eq!(COUNTER.load(Relaxed), 0);
|
||||
panic!("test succeeded")
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
fn empty_array_is_always_default() {
|
||||
@@ -304,6 +304,7 @@ fn array_map() {
|
||||
assert_eq!(b, [1, 2, 3]);
|
||||
}
|
||||
|
||||
+/*
|
||||
// See note on above test for why `should_panic` is used.
|
||||
#[test]
|
||||
#[should_panic(expected = "test succeeded")]
|
||||
@@ -332,6 +333,7 @@ fn array_map_drop_safety() {
|
||||
assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
|
||||
panic!("test succeeded")
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
fn cell_allows_array_cycle() {
|
||||
-- 2.21.0 (Apple Git-122)
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-03-02"
|
||||
channel = "nightly-2023-06-19"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -518,7 +518,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
use gccjit::FnAttribute;
|
||||
use gccjit::Function;
|
||||
use rustc_attr::InstructionSetAttr;
|
||||
#[cfg(feature="master")]
|
||||
use rustc_attr::InlineAttr;
|
||||
use rustc_codegen_ssa::target_features::tied_target_features;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty;
|
||||
#[cfg(feature="master")]
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
|
@ -67,6 +71,24 @@ fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get GCC attribute for the provided inline heuristic.
|
||||
#[cfg(feature="master")]
|
||||
#[inline]
|
||||
fn inline_attr<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, inline: InlineAttr) -> Option<FnAttribute<'gcc>> {
|
||||
match inline {
|
||||
InlineAttr::Hint => Some(FnAttribute::Inline),
|
||||
InlineAttr::Always => Some(FnAttribute::AlwaysInline),
|
||||
InlineAttr::Never => {
|
||||
if cx.sess().target.arch != "amdgpu" {
|
||||
Some(FnAttribute::NoInline)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
InlineAttr::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Composite function which sets GCC attributes for function depending on its AST (`#[attribute]`)
|
||||
/// attributes.
|
||||
pub fn from_fn_attrs<'gcc, 'tcx>(
|
||||
|
|
@ -77,6 +99,23 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
|
|||
) {
|
||||
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
|
||||
|
||||
#[cfg(feature="master")]
|
||||
{
|
||||
let inline =
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
InlineAttr::Never
|
||||
}
|
||||
else if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) {
|
||||
InlineAttr::Hint
|
||||
}
|
||||
else {
|
||||
codegen_fn_attrs.inline
|
||||
};
|
||||
if let Some(attr) = inline_attr(cx, inline) {
|
||||
func.add_attribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
let function_features =
|
||||
codegen_fn_attrs.target_features.iter().map(|features| features.as_str()).collect::<Vec<&str>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -181,6 +181,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
debug_assert_eq!(casted_args.len(), args.len());
|
||||
|
||||
Cow::Owned(casted_args)
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +209,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
let func_name = format!("{:?}", func_ptr);
|
||||
|
||||
let casted_args: Vec<_> = param_types
|
||||
let mut casted_args: Vec<_> = param_types
|
||||
.into_iter()
|
||||
.zip(args.iter())
|
||||
.enumerate()
|
||||
|
|
@ -237,6 +239,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// NOTE: to take into account variadic functions.
|
||||
for i in casted_args.len()..args.len() {
|
||||
casted_args.push(args[i]);
|
||||
}
|
||||
|
||||
Cow::Owned(casted_args)
|
||||
}
|
||||
|
||||
|
|
@ -280,8 +287,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr");
|
||||
fn function_ptr_call(&mut self, typ: Type<'gcc>, mut func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
|
||||
let gcc_func =
|
||||
match func_ptr.get_type().dyncast_function_ptr_type() {
|
||||
Some(func) => func,
|
||||
None => {
|
||||
// NOTE: due to opaque pointers now being used, we need to cast here.
|
||||
let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr");
|
||||
func_ptr = self.context.new_cast(None, func_ptr, typ);
|
||||
new_func_type
|
||||
},
|
||||
};
|
||||
let func_name = format!("{:?}", func_ptr);
|
||||
let previous_arg_count = args.len();
|
||||
let orig_args = args;
|
||||
|
|
@ -424,16 +440,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
self.llbb().end_with_void_return(None)
|
||||
}
|
||||
|
||||
fn ret(&mut self, value: RValue<'gcc>) {
|
||||
let value =
|
||||
if self.structs_as_pointer.borrow().contains(&value) {
|
||||
// NOTE: hack to workaround a limitation of the rustc API: see comment on
|
||||
// CodegenCx.structs_as_pointer
|
||||
value.dereference(None).to_rvalue()
|
||||
}
|
||||
else {
|
||||
value
|
||||
};
|
||||
fn ret(&mut self, mut value: RValue<'gcc>) {
|
||||
if self.structs_as_pointer.borrow().contains(&value) {
|
||||
// NOTE: hack to workaround a limitation of the rustc API: see comment on
|
||||
// CodegenCx.structs_as_pointer
|
||||
value = value.dereference(None).to_rvalue();
|
||||
}
|
||||
let expected_return_type = self.current_func().get_return_type();
|
||||
if !expected_return_type.is_compatible_with(value.get_type()) {
|
||||
// NOTE: due to opaque pointers now being used, we need to cast here.
|
||||
value = self.context.new_cast(None, value, expected_return_type);
|
||||
}
|
||||
self.llbb().end_with_return(None, value);
|
||||
}
|
||||
|
||||
|
|
@ -719,17 +736,25 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
unimplemented!();
|
||||
}
|
||||
|
||||
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
|
||||
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
|
||||
let block = self.llbb();
|
||||
let function = block.get_function();
|
||||
// NOTE: instead of returning the dereference here, we have to assign it to a variable in
|
||||
// the current basic block. Otherwise, it could be used in another basic block, causing a
|
||||
// dereference after a drop, for instance.
|
||||
// TODO(antoyo): handle align of the load instruction.
|
||||
let ptr = self.context.new_cast(None, ptr, pointee_ty.make_pointer());
|
||||
// FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
|
||||
// Ideally, we shouldn't need to do this check.
|
||||
let aligned_type =
|
||||
if pointee_ty == self.cx.u128_type || pointee_ty == self.cx.i128_type {
|
||||
pointee_ty
|
||||
}
|
||||
else {
|
||||
pointee_ty.get_aligned(align.bytes())
|
||||
};
|
||||
let ptr = self.context.new_cast(None, ptr, aligned_type.make_pointer());
|
||||
let deref = ptr.dereference(None).to_rvalue();
|
||||
unsafe { RETURN_VALUE_COUNT += 1 };
|
||||
let loaded_value = function.new_local(None, pointee_ty, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
|
||||
let loaded_value = function.new_local(None, aligned_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
|
||||
block.add_assignment(None, loaded_value, deref);
|
||||
loaded_value.to_rvalue()
|
||||
}
|
||||
|
|
@ -909,7 +934,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
self.context.new_bitcast(None, result, ptr_type)
|
||||
}
|
||||
|
||||
fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
|
||||
fn inbounds_gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
|
||||
// NOTE: due to opaque pointers now being used, we need to cast here.
|
||||
let ptr = self.context.new_cast(None, ptr, typ.make_pointer());
|
||||
// NOTE: array indexing is always considered in bounds in GCC (TODO(antoyo): to be verified).
|
||||
let mut indices = indices.into_iter();
|
||||
let index = indices.next().expect("first index in inbounds_gep");
|
||||
|
|
@ -938,6 +965,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
element.get_address(None)
|
||||
}
|
||||
else if let Some(struct_type) = value_type.is_struct() {
|
||||
// NOTE: due to opaque pointers now being used, we need to bitcast here.
|
||||
let ptr = self.bitcast_if_needed(ptr, value_type.make_pointer());
|
||||
ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None)
|
||||
}
|
||||
else {
|
||||
|
|
@ -1356,7 +1385,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
fn call(
|
||||
&mut self,
|
||||
_typ: Type<'gcc>,
|
||||
typ: Type<'gcc>,
|
||||
_fn_attrs: Option<&CodegenFnAttrs>,
|
||||
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
|
||||
func: RValue<'gcc>,
|
||||
|
|
@ -1370,7 +1399,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
else {
|
||||
// If it's a not function that was defined, it's a function pointer.
|
||||
self.function_ptr_call(func, args, funclet)
|
||||
self.function_ptr_call(typ, func, args, funclet)
|
||||
};
|
||||
if let Some(_fn_abi) = fn_abi {
|
||||
// TODO(bjorn3): Apply function attributes
|
||||
|
|
@ -1843,7 +1872,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
#[cfg(feature="master")]
|
||||
let (cond, element_type) = {
|
||||
let then_val_vector_type = then_val.get_type().dyncast_vector().expect("vector type");
|
||||
// TODO(antoyo): dyncast_vector should not require a call to unqualified.
|
||||
let then_val_vector_type = then_val.get_type().unqualified().dyncast_vector().expect("vector type");
|
||||
let then_val_element_type = then_val_vector_type.get_element_type();
|
||||
let then_val_element_size = then_val_element_type.get_size();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#[cfg(feature = "master")]
|
||||
use gccjit::FnAttribute;
|
||||
use gccjit::{FnAttribute, VarAttribute, Visibility};
|
||||
use gccjit::{Function, GlobalKind, LValue, RValue, ToRValue};
|
||||
use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods};
|
||||
use rustc_middle::span_bug;
|
||||
|
|
@ -234,7 +234,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
);
|
||||
|
||||
if !self.tcx.is_reachable_non_generic(def_id) {
|
||||
// TODO(antoyo): set visibility.
|
||||
#[cfg(feature = "master")]
|
||||
global.add_attribute(VarAttribute::Visibility(Visibility::Hidden));
|
||||
}
|
||||
|
||||
global
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll
|
|||
pub fn mangle_name(name: &str) -> String {
|
||||
name.replace(|char: char| {
|
||||
if !char.is_alphanumeric() && char != '_' {
|
||||
debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
|
||||
debug_assert!("$.*".contains(char), "Unsupported char in function name {}: {}", name, char);
|
||||
true
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -2967,10 +2967,6 @@ match name {
|
|||
"llvm.nvvm.clz.ll" => "__nvvm_clz_ll",
|
||||
"llvm.nvvm.cos.approx.f" => "__nvvm_cos_approx_f",
|
||||
"llvm.nvvm.cos.approx.ftz.f" => "__nvvm_cos_approx_ftz_f",
|
||||
"llvm.nvvm.cp.async.ca.shared.global.16" => "__nvvm_cp_async_ca_shared_global_16",
|
||||
"llvm.nvvm.cp.async.ca.shared.global.4" => "__nvvm_cp_async_ca_shared_global_4",
|
||||
"llvm.nvvm.cp.async.ca.shared.global.8" => "__nvvm_cp_async_ca_shared_global_8",
|
||||
"llvm.nvvm.cp.async.cg.shared.global.16" => "__nvvm_cp_async_cg_shared_global_16",
|
||||
"llvm.nvvm.cp.async.commit.group" => "__nvvm_cp_async_commit_group",
|
||||
"llvm.nvvm.cp.async.mbarrier.arrive" => "__nvvm_cp_async_mbarrier_arrive",
|
||||
"llvm.nvvm.cp.async.mbarrier.arrive.noinc" => "__nvvm_cp_async_mbarrier_arrive_noinc",
|
||||
|
|
@ -3086,18 +3082,8 @@ match name {
|
|||
"llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16",
|
||||
"llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2",
|
||||
"llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f",
|
||||
"llvm.nvvm.fma.rn.ftz.f16" => "__nvvm_fma_rn_ftz_f16",
|
||||
"llvm.nvvm.fma.rn.ftz.f16x2" => "__nvvm_fma_rn_ftz_f16x2",
|
||||
"llvm.nvvm.fma.rn.ftz.relu.f16" => "__nvvm_fma_rn_ftz_relu_f16",
|
||||
"llvm.nvvm.fma.rn.ftz.relu.f16x2" => "__nvvm_fma_rn_ftz_relu_f16x2",
|
||||
"llvm.nvvm.fma.rn.ftz.sat.f16" => "__nvvm_fma_rn_ftz_sat_f16",
|
||||
"llvm.nvvm.fma.rn.ftz.sat.f16x2" => "__nvvm_fma_rn_ftz_sat_f16x2",
|
||||
"llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16",
|
||||
"llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2",
|
||||
"llvm.nvvm.fma.rn.relu.f16" => "__nvvm_fma_rn_relu_f16",
|
||||
"llvm.nvvm.fma.rn.relu.f16x2" => "__nvvm_fma_rn_relu_f16x2",
|
||||
"llvm.nvvm.fma.rn.sat.f16" => "__nvvm_fma_rn_sat_f16",
|
||||
"llvm.nvvm.fma.rn.sat.f16x2" => "__nvvm_fma_rn_sat_f16x2",
|
||||
"llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d",
|
||||
"llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f",
|
||||
"llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f",
|
||||
|
|
@ -3111,32 +3097,18 @@ match name {
|
|||
"llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16",
|
||||
"llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2",
|
||||
"llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f",
|
||||
"llvm.nvvm.fmax.ftz.f16" => "__nvvm_fmax_ftz_f16",
|
||||
"llvm.nvvm.fmax.ftz.f16x2" => "__nvvm_fmax_ftz_f16x2",
|
||||
"llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f",
|
||||
"llvm.nvvm.fmax.ftz.nan.f16" => "__nvvm_fmax_ftz_nan_f16",
|
||||
"llvm.nvvm.fmax.ftz.nan.f16x2" => "__nvvm_fmax_ftz_nan_f16x2",
|
||||
"llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f",
|
||||
"llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmax.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f",
|
||||
"llvm.nvvm.fmax.ftz.xorsign.abs.f16" => "__nvvm_fmax_ftz_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmax.ftz.xorsign.abs.f16x2" => "__nvvm_fmax_ftz_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16",
|
||||
"llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2",
|
||||
"llvm.nvvm.fmax.nan.f" => "__nvvm_fmax_nan_f",
|
||||
"llvm.nvvm.fmax.nan.f16" => "__nvvm_fmax_nan_f16",
|
||||
"llvm.nvvm.fmax.nan.f16x2" => "__nvvm_fmax_nan_f16x2",
|
||||
"llvm.nvvm.fmax.nan.xorsign.abs.bf16" => "__nvvm_fmax_nan_xorsign_abs_bf16",
|
||||
"llvm.nvvm.fmax.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_nan_xorsign_abs_bf16x2",
|
||||
"llvm.nvvm.fmax.nan.xorsign.abs.f" => "__nvvm_fmax_nan_xorsign_abs_f",
|
||||
"llvm.nvvm.fmax.nan.xorsign.abs.f16" => "__nvvm_fmax_nan_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmax.nan.xorsign.abs.f16x2" => "__nvvm_fmax_nan_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmax.xorsign.abs.bf16" => "__nvvm_fmax_xorsign_abs_bf16",
|
||||
"llvm.nvvm.fmax.xorsign.abs.bf16x2" => "__nvvm_fmax_xorsign_abs_bf16x2",
|
||||
"llvm.nvvm.fmax.xorsign.abs.f" => "__nvvm_fmax_xorsign_abs_f",
|
||||
"llvm.nvvm.fmax.xorsign.abs.f16" => "__nvvm_fmax_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmax.xorsign.abs.f16x2" => "__nvvm_fmax_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmin.bf16" => "__nvvm_fmin_bf16",
|
||||
"llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2",
|
||||
"llvm.nvvm.fmin.d" => "__nvvm_fmin_d",
|
||||
|
|
@ -3144,32 +3116,18 @@ match name {
|
|||
"llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16",
|
||||
"llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2",
|
||||
"llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f",
|
||||
"llvm.nvvm.fmin.ftz.f16" => "__nvvm_fmin_ftz_f16",
|
||||
"llvm.nvvm.fmin.ftz.f16x2" => "__nvvm_fmin_ftz_f16x2",
|
||||
"llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f",
|
||||
"llvm.nvvm.fmin.ftz.nan.f16" => "__nvvm_fmin_ftz_nan_f16",
|
||||
"llvm.nvvm.fmin.ftz.nan.f16x2" => "__nvvm_fmin_ftz_nan_f16x2",
|
||||
"llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f",
|
||||
"llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmin.ftz.nan.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f",
|
||||
"llvm.nvvm.fmin.ftz.xorsign.abs.f16" => "__nvvm_fmin_ftz_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmin.ftz.xorsign.abs.f16x2" => "__nvvm_fmin_ftz_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16",
|
||||
"llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2",
|
||||
"llvm.nvvm.fmin.nan.f" => "__nvvm_fmin_nan_f",
|
||||
"llvm.nvvm.fmin.nan.f16" => "__nvvm_fmin_nan_f16",
|
||||
"llvm.nvvm.fmin.nan.f16x2" => "__nvvm_fmin_nan_f16x2",
|
||||
"llvm.nvvm.fmin.nan.xorsign.abs.bf16" => "__nvvm_fmin_nan_xorsign_abs_bf16",
|
||||
"llvm.nvvm.fmin.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_nan_xorsign_abs_bf16x2",
|
||||
"llvm.nvvm.fmin.nan.xorsign.abs.f" => "__nvvm_fmin_nan_xorsign_abs_f",
|
||||
"llvm.nvvm.fmin.nan.xorsign.abs.f16" => "__nvvm_fmin_nan_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmin.nan.xorsign.abs.f16x2" => "__nvvm_fmin_nan_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fmin.xorsign.abs.bf16" => "__nvvm_fmin_xorsign_abs_bf16",
|
||||
"llvm.nvvm.fmin.xorsign.abs.bf16x2" => "__nvvm_fmin_xorsign_abs_bf16x2",
|
||||
"llvm.nvvm.fmin.xorsign.abs.f" => "__nvvm_fmin_xorsign_abs_f",
|
||||
"llvm.nvvm.fmin.xorsign.abs.f16" => "__nvvm_fmin_xorsign_abs_f16",
|
||||
"llvm.nvvm.fmin.xorsign.abs.f16x2" => "__nvvm_fmin_xorsign_abs_f16x2",
|
||||
"llvm.nvvm.fns" => "__nvvm_fns",
|
||||
"llvm.nvvm.h2f" => "__nvvm_h2f",
|
||||
"llvm.nvvm.i2d.rm" => "__nvvm_i2d_rm",
|
||||
|
|
@ -7895,6 +7853,10 @@ match name {
|
|||
"llvm.x86.subborrow.u64" => "__builtin_ia32_subborrow_u64",
|
||||
"llvm.x86.tbm.bextri.u32" => "__builtin_ia32_bextri_u32",
|
||||
"llvm.x86.tbm.bextri.u64" => "__builtin_ia32_bextri_u64",
|
||||
"llvm.x86.tcmmimfp16ps" => "__builtin_ia32_tcmmimfp16ps",
|
||||
"llvm.x86.tcmmimfp16ps.internal" => "__builtin_ia32_tcmmimfp16ps_internal",
|
||||
"llvm.x86.tcmmrlfp16ps" => "__builtin_ia32_tcmmrlfp16ps",
|
||||
"llvm.x86.tcmmrlfp16ps.internal" => "__builtin_ia32_tcmmrlfp16ps_internal",
|
||||
"llvm.x86.tdpbf16ps" => "__builtin_ia32_tdpbf16ps",
|
||||
"llvm.x86.tdpbf16ps.internal" => "__builtin_ia32_tdpbf16ps_internal",
|
||||
"llvm.x86.tdpbssd" => "__builtin_ia32_tdpbssd",
|
||||
|
|
|
|||
|
|
@ -313,6 +313,13 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc
|
|||
let new_args = args.to_vec();
|
||||
args = vec![new_args[1], new_args[0], new_args[2], new_args[3], new_args[4]].into();
|
||||
},
|
||||
"__builtin_ia32_vpshrdv_v8di" | "__builtin_ia32_vpshrdv_v4di" | "__builtin_ia32_vpshrdv_v2di" |
|
||||
"__builtin_ia32_vpshrdv_v16si" | "__builtin_ia32_vpshrdv_v8si" | "__builtin_ia32_vpshrdv_v4si" |
|
||||
"__builtin_ia32_vpshrdv_v32hi" | "__builtin_ia32_vpshrdv_v16hi" | "__builtin_ia32_vpshrdv_v8hi" => {
|
||||
// The first two arguments are reversed, compared to LLVM.
|
||||
let new_args = args.to_vec();
|
||||
args = vec![new_args[1], new_args[0], new_args[2]].into();
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -551,141 +551,52 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let context = &self.cx.context;
|
||||
let result =
|
||||
match width {
|
||||
8 => {
|
||||
8 | 16 | 32 | 64 => {
|
||||
let mask = ((1u128 << width) - 1) as u64;
|
||||
let (m0, m1, m2) = if width > 16 {
|
||||
(
|
||||
context.new_rvalue_from_long(typ, (0x5555555555555555u64 & mask) as i64),
|
||||
context.new_rvalue_from_long(typ, (0x3333333333333333u64 & mask) as i64),
|
||||
context.new_rvalue_from_long(typ, (0x0f0f0f0f0f0f0f0fu64 & mask) as i64),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
context.new_rvalue_from_int(typ, (0x5555u64 & mask) as i32),
|
||||
context.new_rvalue_from_int(typ, (0x3333u64 & mask) as i32),
|
||||
context.new_rvalue_from_int(typ, (0x0f0fu64 & mask) as i32),
|
||||
)
|
||||
};
|
||||
let one = context.new_rvalue_from_int(typ, 1);
|
||||
let two = context.new_rvalue_from_int(typ, 2);
|
||||
let four = context.new_rvalue_from_int(typ, 4);
|
||||
|
||||
// First step.
|
||||
let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0));
|
||||
let left = self.lshr(left, context.new_rvalue_from_int(typ, 4));
|
||||
let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F));
|
||||
let right = self.shl(right, context.new_rvalue_from_int(typ, 4));
|
||||
let left = self.lshr(value, one);
|
||||
let left = self.and(left, m0);
|
||||
let right = self.and(value, m0);
|
||||
let right = self.shl(right, one);
|
||||
let step1 = self.or(left, right);
|
||||
|
||||
// Second step.
|
||||
let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC));
|
||||
let left = self.lshr(left, context.new_rvalue_from_int(typ, 2));
|
||||
let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33));
|
||||
let right = self.shl(right, context.new_rvalue_from_int(typ, 2));
|
||||
let left = self.lshr(step1, two);
|
||||
let left = self.and(left, m1);
|
||||
let right = self.and(step1, m1);
|
||||
let right = self.shl(right, two);
|
||||
let step2 = self.or(left, right);
|
||||
|
||||
// Third step.
|
||||
let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA));
|
||||
let left = self.lshr(left, context.new_rvalue_from_int(typ, 1));
|
||||
let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55));
|
||||
let right = self.shl(right, context.new_rvalue_from_int(typ, 1));
|
||||
let step3 = self.or(left, right);
|
||||
|
||||
step3
|
||||
},
|
||||
16 => {
|
||||
// First step.
|
||||
let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555));
|
||||
let left = self.shl(left, context.new_rvalue_from_int(typ, 1));
|
||||
let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA));
|
||||
let right = self.lshr(right, context.new_rvalue_from_int(typ, 1));
|
||||
let step1 = self.or(left, right);
|
||||
|
||||
// Second step.
|
||||
let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333));
|
||||
let left = self.shl(left, context.new_rvalue_from_int(typ, 2));
|
||||
let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC));
|
||||
let right = self.lshr(right, context.new_rvalue_from_int(typ, 2));
|
||||
let step2 = self.or(left, right);
|
||||
|
||||
// Third step.
|
||||
let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F));
|
||||
let left = self.shl(left, context.new_rvalue_from_int(typ, 4));
|
||||
let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0));
|
||||
let right = self.lshr(right, context.new_rvalue_from_int(typ, 4));
|
||||
let left = self.lshr(step2, four);
|
||||
let left = self.and(left, m2);
|
||||
let right = self.and(step2, m2);
|
||||
let right = self.shl(right, four);
|
||||
let step3 = self.or(left, right);
|
||||
|
||||
// Fourth step.
|
||||
let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF));
|
||||
let left = self.shl(left, context.new_rvalue_from_int(typ, 8));
|
||||
let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00));
|
||||
let right = self.lshr(right, context.new_rvalue_from_int(typ, 8));
|
||||
let step4 = self.or(left, right);
|
||||
|
||||
step4
|
||||
},
|
||||
32 => {
|
||||
// TODO(antoyo): Refactor with other implementations.
|
||||
// First step.
|
||||
let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 1));
|
||||
let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA));
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 1));
|
||||
let step1 = self.or(left, right);
|
||||
|
||||
// Second step.
|
||||
let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 2));
|
||||
let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC));
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 2));
|
||||
let step2 = self.or(left, right);
|
||||
|
||||
// Third step.
|
||||
let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 4));
|
||||
let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0));
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 4));
|
||||
let step3 = self.or(left, right);
|
||||
|
||||
// Fourth step.
|
||||
let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 8));
|
||||
let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00));
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 8));
|
||||
let step4 = self.or(left, right);
|
||||
|
||||
// Fifth step.
|
||||
let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 16));
|
||||
let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000));
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 16));
|
||||
let step5 = self.or(left, right);
|
||||
|
||||
step5
|
||||
},
|
||||
64 => {
|
||||
// First step.
|
||||
let left = self.shl(value, context.new_rvalue_from_long(typ, 32));
|
||||
let right = self.lshr(value, context.new_rvalue_from_long(typ, 32));
|
||||
let step1 = self.or(left, right);
|
||||
|
||||
// Second step.
|
||||
let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF));
|
||||
let left = self.shl(left, context.new_rvalue_from_long(typ, 15));
|
||||
let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead?
|
||||
let right = self.lshr(right, context.new_rvalue_from_long(typ, 17));
|
||||
let step2 = self.or(left, right);
|
||||
|
||||
// Third step.
|
||||
let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10));
|
||||
let left = self.xor(step2, left);
|
||||
let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F));
|
||||
|
||||
let left = self.shl(temp, context.new_rvalue_from_long(typ, 10));
|
||||
let left = self.or(temp, left);
|
||||
let step3 = self.xor(left, step2);
|
||||
|
||||
// Fourth step.
|
||||
let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4));
|
||||
let left = self.xor(step3, left);
|
||||
let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421));
|
||||
|
||||
let left = self.shl(temp, context.new_rvalue_from_long(typ, 4));
|
||||
let left = self.or(temp, left);
|
||||
let step4 = self.xor(left, step3);
|
||||
|
||||
// Fifth step.
|
||||
let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2));
|
||||
let left = self.xor(step4, left);
|
||||
let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842));
|
||||
|
||||
let left = self.shl(temp, context.new_rvalue_from_long(typ, 2));
|
||||
let left = self.or(temp, left);
|
||||
let step5 = self.xor(left, step4);
|
||||
|
||||
step5
|
||||
if width == 8 {
|
||||
step3
|
||||
} else {
|
||||
self.gcc_bswap(step3, width)
|
||||
}
|
||||
},
|
||||
128 => {
|
||||
// TODO(antoyo): find a more efficient implementation?
|
||||
|
|
|
|||
|
|
@ -165,10 +165,15 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
InvalidMonomorphizationReturnIntegerType { span, name, ret_ty, out_ty }
|
||||
);
|
||||
|
||||
let arg1 = args[0].immediate();
|
||||
// NOTE: we get different vector types for the same vector type and libgccjit doesn't
|
||||
// compare them as equal, so bitcast.
|
||||
// FIXME(antoyo): allow comparing vector types as equal in libgccjit.
|
||||
let arg2 = bx.context.new_bitcast(None, args[1].immediate(), arg1.get_type());
|
||||
return Ok(compare_simd_types(
|
||||
bx,
|
||||
args[0].immediate(),
|
||||
args[1].immediate(),
|
||||
arg1,
|
||||
arg2,
|
||||
in_elem,
|
||||
llret_ty,
|
||||
cmp_op,
|
||||
|
|
@ -341,7 +346,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
// endian and MSB-first for big endian.
|
||||
|
||||
let vector = args[0].immediate();
|
||||
let vector_type = vector.get_type().dyncast_vector().expect("vector type");
|
||||
// TODO(antoyo): dyncast_vector should not require a call to unqualified.
|
||||
let vector_type = vector.get_type().unqualified().dyncast_vector().expect("vector type");
|
||||
let elem_type = vector_type.get_element_type();
|
||||
|
||||
let expected_int_bits = in_len.max(8);
|
||||
|
|
@ -848,7 +854,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
(true, true) => {
|
||||
// Algorithm from: https://codereview.stackexchange.com/questions/115869/saturated-signed-addition
|
||||
// TODO(antoyo): improve using conditional operators if possible.
|
||||
let arg_type = lhs.get_type();
|
||||
// TODO(antoyo): dyncast_vector should not require a call to unqualified.
|
||||
let arg_type = lhs.get_type().unqualified();
|
||||
// TODO(antoyo): convert lhs and rhs to unsigned.
|
||||
let sum = lhs + rhs;
|
||||
let vector_type = arg_type.dyncast_vector().expect("vector type");
|
||||
|
|
@ -878,7 +885,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
res & cmp
|
||||
},
|
||||
(true, false) => {
|
||||
let arg_type = lhs.get_type();
|
||||
// TODO(antoyo): dyncast_vector should not require a call to unqualified.
|
||||
let arg_type = lhs.get_type().unqualified();
|
||||
// TODO(antoyo): this uses the same algorithm from saturating add, but add the
|
||||
// negative of the right operand. Find a proper subtraction algorithm.
|
||||
let rhs = bx.context.new_unary_op(None, UnaryOp::Minus, arg_type, rhs);
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
}
|
||||
|
||||
fn init(&self, sess: &Session) {
|
||||
#[cfg(feature="master")]
|
||||
gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
|
||||
if sess.lto() != Lto::No {
|
||||
sess.emit_warning(LTONotSupported {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -383,8 +383,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
unimplemented!();
|
||||
}
|
||||
|
||||
fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
|
||||
// FIXME(antoyo): return correct type.
|
||||
self.type_void()
|
||||
fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
|
||||
let (return_type, param_types, variadic, _) = fn_abi.gcc_type(self);
|
||||
self.context.new_function_pointer_type(None, return_type, ¶m_types, variadic)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,12 +214,14 @@ function setup_rustc() {
|
|||
rm config.toml || true
|
||||
|
||||
cat > config.toml <<EOF
|
||||
changelog-seen = 2
|
||||
|
||||
[rust]
|
||||
codegen-backends = []
|
||||
deny-warnings = false
|
||||
|
||||
[build]
|
||||
cargo = "$(which cargo)"
|
||||
cargo = "$(rustup which cargo)"
|
||||
local-rebuild = true
|
||||
rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc"
|
||||
|
||||
|
|
@ -237,7 +239,7 @@ EOF
|
|||
function asm_tests() {
|
||||
setup_rustc
|
||||
|
||||
echo "[TEST] rustc test suite"
|
||||
echo "[TEST] rustc asm test suite"
|
||||
RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
|
||||
COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 tests/assembly/asm --rustc-args "$RUSTC_ARGS"
|
||||
}
|
||||
|
|
@ -338,6 +340,8 @@ function test_rustc() {
|
|||
for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" tests/ui); do
|
||||
rm $test
|
||||
done
|
||||
rm tests/ui/consts/const_cmp_type_id.rs
|
||||
rm tests/ui/consts/issue-73976-monomorphic.rs
|
||||
|
||||
git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import os
|
|||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
from os import walk
|
||||
|
||||
|
||||
def run_command(command, cwd=None):
|
||||
|
|
@ -180,7 +179,7 @@ def update_intrinsics(llvm_path, llvmint, llvmint2):
|
|||
intrinsics[arch].sort(key=lambda x: (x[0], x[2]))
|
||||
out.write(' // {}\n'.format(arch))
|
||||
for entry in intrinsics[arch]:
|
||||
if entry[2] == True: # if it is a duplicate
|
||||
if entry[2] is True: # if it is a duplicate
|
||||
out.write(' // [DUPLICATE]: "{}" => "{}",\n'.format(entry[0], entry[1]))
|
||||
elif "_round_mask" in entry[1]:
|
||||
out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(entry[0], entry[1]))
|
||||
|
|
|
|||
|
|
@ -1031,7 +1031,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
|||
build_field_di_node(
|
||||
cx,
|
||||
closure_or_generator_di_node,
|
||||
capture_name,
|
||||
capture_name.as_str(),
|
||||
cx.size_and_align_of(up_var_ty),
|
||||
layout.fields.offset(index),
|
||||
DIFlags::FlagZero,
|
||||
|
|
|
|||
|
|
@ -676,8 +676,7 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let (generator_layout, state_specific_upvar_names) =
|
||||
cx.tcx.generator_layout_and_saved_local_names(generator_def_id);
|
||||
let generator_layout = cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap();
|
||||
|
||||
let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(generator_def_id);
|
||||
let variant_range = generator_substs.variant_range(generator_def_id, cx.tcx);
|
||||
|
|
@ -714,7 +713,6 @@ fn build_union_fields_for_direct_tag_generator<'ll, 'tcx>(
|
|||
generator_type_and_layout,
|
||||
generator_type_di_node,
|
||||
generator_layout,
|
||||
&state_specific_upvar_names,
|
||||
&common_upvar_names,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_hir::def::CtorKind;
|
|||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::{
|
||||
bug,
|
||||
mir::{GeneratorLayout, GeneratorSavedLocal},
|
||||
mir::GeneratorLayout,
|
||||
ty::{
|
||||
self,
|
||||
layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout},
|
||||
|
|
@ -323,8 +323,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
generator_type_and_layout: TyAndLayout<'tcx>,
|
||||
generator_type_di_node: &'ll DIType,
|
||||
generator_layout: &GeneratorLayout<'tcx>,
|
||||
state_specific_upvar_names: &IndexSlice<GeneratorSavedLocal, Option<Symbol>>,
|
||||
common_upvar_names: &[String],
|
||||
common_upvar_names: &IndexSlice<FieldIdx, Symbol>,
|
||||
) -> &'ll DIType {
|
||||
let variant_name = GeneratorSubsts::variant_name(variant_index);
|
||||
let unique_type_id = UniqueTypeId::for_enum_variant_struct_type(
|
||||
|
|
@ -357,7 +356,7 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
.map(|field_index| {
|
||||
let generator_saved_local = generator_layout.variant_fields[variant_index]
|
||||
[FieldIdx::from_usize(field_index)];
|
||||
let field_name_maybe = state_specific_upvar_names[generator_saved_local];
|
||||
let field_name_maybe = generator_layout.field_names[generator_saved_local];
|
||||
let field_name = field_name_maybe
|
||||
.as_ref()
|
||||
.map(|s| Cow::from(s.as_str()))
|
||||
|
|
@ -380,12 +379,13 @@ pub fn build_generator_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
// Fields that are common to all states
|
||||
let common_fields: SmallVec<_> = generator_substs
|
||||
.prefix_tys()
|
||||
.zip(common_upvar_names)
|
||||
.enumerate()
|
||||
.map(|(index, upvar_ty)| {
|
||||
.map(|(index, (upvar_ty, upvar_name))| {
|
||||
build_field_di_node(
|
||||
cx,
|
||||
variant_struct_type_di_node,
|
||||
&common_upvar_names[index],
|
||||
upvar_name.as_str(),
|
||||
cx.size_and_align_of(upvar_ty),
|
||||
generator_type_and_layout.fields.offset(index),
|
||||
DIFlags::FlagZero,
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
|
|||
DIFlags::FlagZero,
|
||||
),
|
||||
|cx, generator_type_di_node| {
|
||||
let (generator_layout, state_specific_upvar_names) =
|
||||
cx.tcx.generator_layout_and_saved_local_names(generator_def_id);
|
||||
let generator_layout =
|
||||
cx.tcx.optimized_mir(generator_def_id).generator_layout().unwrap();
|
||||
|
||||
let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = generator_type_and_layout.variants else {
|
||||
bug!(
|
||||
|
|
@ -195,7 +195,6 @@ pub(super) fn build_generator_di_node<'ll, 'tcx>(
|
|||
generator_type_and_layout,
|
||||
generator_type_di_node,
|
||||
generator_layout,
|
||||
&state_specific_upvar_names,
|
||||
&common_upvar_names,
|
||||
),
|
||||
source_info,
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ use jobserver::{Acquired, Client};
|
|||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::profiling::TimingGuard;
|
||||
use rustc_data_structures::profiling::VerboseTimingGuard;
|
||||
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::emitter::Emitter;
|
||||
use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
|
||||
|
|
@ -322,7 +320,6 @@ pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportInfo
|
|||
#[derive(Clone)]
|
||||
pub struct CodegenContext<B: WriteBackendMethods> {
|
||||
// Resources needed when running LTO
|
||||
pub backend: B,
|
||||
pub prof: SelfProfilerRef,
|
||||
pub lto: Lto,
|
||||
pub save_temps: bool,
|
||||
|
|
@ -340,14 +337,10 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub msvc_imps_needed: bool,
|
||||
pub is_pe_coff: bool,
|
||||
pub target_can_use_split_dwarf: bool,
|
||||
pub target_pointer_width: u32,
|
||||
pub target_arch: String,
|
||||
pub debuginfo: config::DebugInfo,
|
||||
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
|
||||
pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
|
||||
|
||||
/// Number of cgus excluding the allocator/metadata modules
|
||||
pub total_cgus: usize,
|
||||
/// Handler to use for diagnostics produced during codegen.
|
||||
pub diag_emitter: SharedEmitter,
|
||||
/// LLVM optimizations for which we want to print remarks.
|
||||
|
|
@ -443,7 +436,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
target_cpu: String,
|
||||
metadata: EncodedMetadata,
|
||||
metadata_module: Option<CompiledModule>,
|
||||
total_cgus: usize,
|
||||
) -> OngoingCodegen<B> {
|
||||
let (coordinator_send, coordinator_receive) = channel();
|
||||
let sess = tcx.sess;
|
||||
|
|
@ -471,7 +463,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
shared_emitter,
|
||||
codegen_worker_send,
|
||||
coordinator_receive,
|
||||
total_cgus,
|
||||
sess.jobserver.clone(),
|
||||
Arc::new(regular_config),
|
||||
Arc::new(metadata_config),
|
||||
|
|
@ -687,7 +678,7 @@ fn produce_final_output_artifacts(
|
|||
// These are used in linking steps and will be cleaned up afterward.
|
||||
}
|
||||
|
||||
pub enum WorkItem<B: WriteBackendMethods> {
|
||||
pub(crate) enum WorkItem<B: WriteBackendMethods> {
|
||||
/// Optimize a newly codegened, totally unoptimized module.
|
||||
Optimize(ModuleCodegen<B::Module>),
|
||||
/// Copy the post-LTO artifacts from the incremental cache to the output
|
||||
|
|
@ -705,20 +696,6 @@ impl<B: WriteBackendMethods> WorkItem<B> {
|
|||
}
|
||||
}
|
||||
|
||||
fn start_profiling<'a>(&self, cgcx: &'a CodegenContext<B>) -> TimingGuard<'a> {
|
||||
match *self {
|
||||
WorkItem::Optimize(ref m) => {
|
||||
cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name)
|
||||
}
|
||||
WorkItem::CopyPostLtoArtifacts(ref m) => cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("codegen_copy_artifacts_from_incr_cache", &*m.name),
|
||||
WorkItem::LTO(ref m) => {
|
||||
cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a short description of this work item suitable for use as a thread name.
|
||||
fn short_description(&self) -> String {
|
||||
// `pthread_setname()` on *nix is limited to 15 characters and longer names are ignored.
|
||||
|
|
@ -747,7 +724,8 @@ impl<B: WriteBackendMethods> WorkItem<B> {
|
|||
}
|
||||
}
|
||||
|
||||
enum WorkItemResult<B: WriteBackendMethods> {
|
||||
/// A result produced by the backend.
|
||||
pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
|
||||
Compiled(CompiledModule),
|
||||
NeedsLink(ModuleCodegen<B::Module>),
|
||||
NeedsFatLTO(FatLTOInput<B>),
|
||||
|
|
@ -759,21 +737,6 @@ pub enum FatLTOInput<B: WriteBackendMethods> {
|
|||
InMemory(ModuleCodegen<B::Module>),
|
||||
}
|
||||
|
||||
fn execute_work_item<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
work_item: WorkItem<B>,
|
||||
) -> Result<WorkItemResult<B>, FatalError> {
|
||||
let module_config = cgcx.config(work_item.module_kind());
|
||||
|
||||
match work_item {
|
||||
WorkItem::Optimize(module) => execute_optimize_work_item(cgcx, module, module_config),
|
||||
WorkItem::CopyPostLtoArtifacts(module) => {
|
||||
Ok(execute_copy_from_cache_work_item(cgcx, module, module_config))
|
||||
}
|
||||
WorkItem::LTO(module) => execute_lto_work_item(cgcx, module, module_config),
|
||||
}
|
||||
}
|
||||
|
||||
/// Actual LTO type we end up choosing based on multiple factors.
|
||||
pub enum ComputedLtoType {
|
||||
No,
|
||||
|
|
@ -954,38 +917,41 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Message<B: WriteBackendMethods> {
|
||||
/// Messages sent to the coordinator.
|
||||
pub(crate) enum Message<B: WriteBackendMethods> {
|
||||
/// A jobserver token has become available. Sent from the jobserver helper
|
||||
/// thread.
|
||||
Token(io::Result<Acquired>),
|
||||
NeedsFatLTO {
|
||||
result: FatLTOInput<B>,
|
||||
worker_id: usize,
|
||||
},
|
||||
NeedsThinLTO {
|
||||
name: String,
|
||||
thin_buffer: B::ThinBuffer,
|
||||
worker_id: usize,
|
||||
},
|
||||
NeedsLink {
|
||||
module: ModuleCodegen<B::Module>,
|
||||
worker_id: usize,
|
||||
},
|
||||
Done {
|
||||
result: Result<CompiledModule, Option<WorkerFatalError>>,
|
||||
worker_id: usize,
|
||||
},
|
||||
CodegenDone {
|
||||
llvm_work_item: WorkItem<B>,
|
||||
cost: u64,
|
||||
},
|
||||
|
||||
/// The backend has finished processing a work item for a codegen unit.
|
||||
/// Sent from a backend worker thread.
|
||||
WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize },
|
||||
|
||||
/// The frontend has finished generating something (backend IR or a
|
||||
/// post-LTO artifact) for a codegen unit, and it should be passed to the
|
||||
/// backend. Sent from the main thread.
|
||||
CodegenDone { llvm_work_item: WorkItem<B>, cost: u64 },
|
||||
|
||||
/// Similar to `CodegenDone`, but for reusing a pre-LTO artifact
|
||||
/// Sent from the main thread.
|
||||
AddImportOnlyModule {
|
||||
module_data: SerializedModule<B::ModuleBuffer>,
|
||||
work_product: WorkProduct,
|
||||
},
|
||||
|
||||
/// The frontend has finished generating everything for all codegen units.
|
||||
/// Sent from the main thread.
|
||||
CodegenComplete,
|
||||
CodegenItem,
|
||||
|
||||
/// Some normal-ish compiler error occurred, and codegen should be wound
|
||||
/// down. Sent from the main thread.
|
||||
CodegenAborted,
|
||||
}
|
||||
|
||||
/// A message sent from the coordinator thread to the main thread telling it to
|
||||
/// process another codegen unit.
|
||||
pub struct CguMessage;
|
||||
|
||||
type DiagnosticArgName<'source> = Cow<'source, str>;
|
||||
|
||||
struct Diagnostic {
|
||||
|
|
@ -1007,9 +973,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
tcx: TyCtxt<'_>,
|
||||
crate_info: &CrateInfo,
|
||||
shared_emitter: SharedEmitter,
|
||||
codegen_worker_send: Sender<Message<B>>,
|
||||
codegen_worker_send: Sender<CguMessage>,
|
||||
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
||||
total_cgus: usize,
|
||||
jobserver: Client,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
metadata_config: Arc<ModuleConfig>,
|
||||
|
|
@ -1077,7 +1042,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
};
|
||||
let backend_features = tcx.global_backend_features(());
|
||||
let cgcx = CodegenContext::<B> {
|
||||
backend: backend.clone(),
|
||||
crate_types: sess.crate_types().to_vec(),
|
||||
each_linked_rlib_for_lto,
|
||||
lto: sess.lto(),
|
||||
|
|
@ -1098,13 +1062,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features),
|
||||
total_cgus,
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
is_pe_coff: tcx.sess.target.is_like_windows,
|
||||
target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
|
||||
target_pointer_width: tcx.sess.target.pointer_width,
|
||||
target_arch: tcx.sess.target.arch.to_string(),
|
||||
debuginfo: tcx.sess.opts.debuginfo,
|
||||
split_debuginfo: tcx.sess.split_debuginfo(),
|
||||
split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind,
|
||||
};
|
||||
|
|
@ -1266,10 +1227,19 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let mut needs_thin_lto = Vec::new();
|
||||
let mut lto_import_only_modules = Vec::new();
|
||||
let mut started_lto = false;
|
||||
let mut codegen_aborted = false;
|
||||
|
||||
// This flag tracks whether all items have gone through codegens
|
||||
let mut codegen_done = false;
|
||||
/// Possible state transitions:
|
||||
/// - Ongoing -> Completed
|
||||
/// - Ongoing -> Aborted
|
||||
/// - Completed -> Aborted
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum CodegenState {
|
||||
Ongoing,
|
||||
Completed,
|
||||
Aborted,
|
||||
}
|
||||
use CodegenState::*;
|
||||
let mut codegen_state = Ongoing;
|
||||
|
||||
// This is the queue of LLVM work items that still need processing.
|
||||
let mut work_items = Vec::<(WorkItem<B>, u64)>::new();
|
||||
|
|
@ -1289,10 +1259,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// wait for all existing work to finish, so many of the conditions here
|
||||
// only apply if codegen hasn't been aborted as they represent pending
|
||||
// work to be done.
|
||||
while !codegen_done
|
||||
while codegen_state == Ongoing
|
||||
|| running > 0
|
||||
|| main_thread_worker_state == MainThreadWorkerState::LLVMing
|
||||
|| (!codegen_aborted
|
||||
|| (codegen_state == Completed
|
||||
&& !(work_items.is_empty()
|
||||
&& needs_fat_lto.is_empty()
|
||||
&& needs_thin_lto.is_empty()
|
||||
|
|
@ -1302,7 +1272,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// While there are still CGUs to be codegened, the coordinator has
|
||||
// to decide how to utilize the compiler processes implicit Token:
|
||||
// For codegenning more CGU or for running them through LLVM.
|
||||
if !codegen_done {
|
||||
if codegen_state == Ongoing {
|
||||
if main_thread_worker_state == MainThreadWorkerState::Idle {
|
||||
// Compute the number of workers that will be running once we've taken as many
|
||||
// items from the work queue as we can, plus one for the main thread. It's not
|
||||
|
|
@ -1315,9 +1285,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let anticipated_running = running + additional_running + 1;
|
||||
|
||||
if !queue_full_enough(work_items.len(), anticipated_running) {
|
||||
// The queue is not full enough, codegen more items:
|
||||
if codegen_worker_send.send(Message::CodegenItem).is_err() {
|
||||
panic!("Could not send Message::CodegenItem to main thread")
|
||||
// The queue is not full enough, process more codegen units:
|
||||
if codegen_worker_send.send(CguMessage).is_err() {
|
||||
panic!("Could not send CguMessage to main thread")
|
||||
}
|
||||
main_thread_worker_state = MainThreadWorkerState::Codegenning;
|
||||
} else {
|
||||
|
|
@ -1339,10 +1309,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
spawn_work(cgcx, item);
|
||||
}
|
||||
}
|
||||
} else if codegen_aborted {
|
||||
// don't queue up any more work if codegen was aborted, we're
|
||||
// just waiting for our existing children to finish
|
||||
} else {
|
||||
} else if codegen_state == Completed {
|
||||
// If we've finished everything related to normal codegen
|
||||
// then it must be the case that we've got some LTO work to do.
|
||||
// Perform the serial work here of figuring out what we're
|
||||
|
|
@ -1409,11 +1376,15 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// Already making good use of that token
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Don't queue up any more work if codegen was aborted, we're
|
||||
// just waiting for our existing children to finish.
|
||||
assert!(codegen_state == Aborted);
|
||||
}
|
||||
|
||||
// Spin up what work we can, only doing this while we've got available
|
||||
// parallelism slots and work left to spawn.
|
||||
while !codegen_aborted && !work_items.is_empty() && running < tokens.len() {
|
||||
while codegen_state != Aborted && !work_items.is_empty() && running < tokens.len() {
|
||||
let (item, _) = work_items.pop().unwrap();
|
||||
|
||||
maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time);
|
||||
|
|
@ -1465,8 +1436,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
Err(e) => {
|
||||
let msg = &format!("failed to acquire jobserver token: {}", e);
|
||||
shared_emitter.fatal(msg);
|
||||
codegen_done = true;
|
||||
codegen_aborted = true;
|
||||
codegen_state = Aborted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1494,7 +1464,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
}
|
||||
|
||||
Message::CodegenComplete => {
|
||||
codegen_done = true;
|
||||
if codegen_state != Aborted {
|
||||
codegen_state = Completed;
|
||||
}
|
||||
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
|
||||
main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||
}
|
||||
|
|
@ -1506,58 +1478,59 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// then conditions above will ensure no more work is spawned but
|
||||
// we'll keep executing this loop until `running` hits 0.
|
||||
Message::CodegenAborted => {
|
||||
codegen_done = true;
|
||||
codegen_aborted = true;
|
||||
codegen_state = Aborted;
|
||||
}
|
||||
Message::Done { result: Ok(compiled_module), worker_id } => {
|
||||
|
||||
Message::WorkItem { result, worker_id } => {
|
||||
free_worker(worker_id);
|
||||
match compiled_module.kind {
|
||||
ModuleKind::Regular => {
|
||||
compiled_modules.push(compiled_module);
|
||||
|
||||
match result {
|
||||
Ok(WorkItemResult::Compiled(compiled_module)) => {
|
||||
match compiled_module.kind {
|
||||
ModuleKind::Regular => {
|
||||
compiled_modules.push(compiled_module);
|
||||
}
|
||||
ModuleKind::Allocator => {
|
||||
assert!(compiled_allocator_module.is_none());
|
||||
compiled_allocator_module = Some(compiled_module);
|
||||
}
|
||||
ModuleKind::Metadata => bug!("Should be handled separately"),
|
||||
}
|
||||
}
|
||||
ModuleKind::Allocator => {
|
||||
assert!(compiled_allocator_module.is_none());
|
||||
compiled_allocator_module = Some(compiled_module);
|
||||
Ok(WorkItemResult::NeedsLink(module)) => {
|
||||
needs_link.push(module);
|
||||
}
|
||||
Ok(WorkItemResult::NeedsFatLTO(fat_lto_input)) => {
|
||||
assert!(!started_lto);
|
||||
needs_fat_lto.push(fat_lto_input);
|
||||
}
|
||||
Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) => {
|
||||
assert!(!started_lto);
|
||||
needs_thin_lto.push((name, thin_buffer));
|
||||
}
|
||||
Err(Some(WorkerFatalError)) => {
|
||||
// Like `CodegenAborted`, wait for remaining work to finish.
|
||||
codegen_state = Aborted;
|
||||
}
|
||||
Err(None) => {
|
||||
// If the thread failed that means it panicked, so
|
||||
// we abort immediately.
|
||||
bug!("worker thread panicked");
|
||||
}
|
||||
ModuleKind::Metadata => bug!("Should be handled separately"),
|
||||
}
|
||||
}
|
||||
Message::NeedsLink { module, worker_id } => {
|
||||
free_worker(worker_id);
|
||||
needs_link.push(module);
|
||||
}
|
||||
Message::NeedsFatLTO { result, worker_id } => {
|
||||
assert!(!started_lto);
|
||||
free_worker(worker_id);
|
||||
needs_fat_lto.push(result);
|
||||
}
|
||||
Message::NeedsThinLTO { name, thin_buffer, worker_id } => {
|
||||
assert!(!started_lto);
|
||||
free_worker(worker_id);
|
||||
needs_thin_lto.push((name, thin_buffer));
|
||||
}
|
||||
|
||||
Message::AddImportOnlyModule { module_data, work_product } => {
|
||||
assert!(!started_lto);
|
||||
assert!(!codegen_done);
|
||||
assert_eq!(codegen_state, Ongoing);
|
||||
assert_eq!(main_thread_worker_state, MainThreadWorkerState::Codegenning);
|
||||
lto_import_only_modules.push((module_data, work_product));
|
||||
main_thread_worker_state = MainThreadWorkerState::Idle;
|
||||
}
|
||||
// If the thread failed that means it panicked, so we abort immediately.
|
||||
Message::Done { result: Err(None), worker_id: _ } => {
|
||||
bug!("worker thread panicked");
|
||||
}
|
||||
Message::Done { result: Err(Some(WorkerFatalError)), worker_id } => {
|
||||
// Similar to CodegenAborted, wait for remaining work to finish.
|
||||
free_worker(worker_id);
|
||||
codegen_done = true;
|
||||
codegen_aborted = true;
|
||||
}
|
||||
Message::CodegenItem => bug!("the coordinator should not receive codegen requests"),
|
||||
}
|
||||
}
|
||||
|
||||
if codegen_aborted {
|
||||
if codegen_state == Aborted {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
|
|
@ -1672,22 +1645,11 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
|
|||
fn drop(&mut self) {
|
||||
let worker_id = self.worker_id;
|
||||
let msg = match self.result.take() {
|
||||
Some(Ok(WorkItemResult::Compiled(m))) => {
|
||||
Message::Done::<B> { result: Ok(m), worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsLink(m))) => {
|
||||
Message::NeedsLink::<B> { module: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
|
||||
Message::NeedsFatLTO::<B> { result: m, worker_id }
|
||||
}
|
||||
Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
|
||||
Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
|
||||
}
|
||||
Some(Ok(result)) => Message::WorkItem::<B> { result: Ok(result), worker_id },
|
||||
Some(Err(FatalError)) => {
|
||||
Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
|
||||
Message::WorkItem::<B> { result: Err(Some(WorkerFatalError)), worker_id }
|
||||
}
|
||||
None => Message::Done::<B> { result: Err(None), worker_id },
|
||||
None => Message::WorkItem::<B> { result: Err(None), worker_id },
|
||||
};
|
||||
drop(self.coordinator_send.send(Box::new(msg)));
|
||||
}
|
||||
|
|
@ -1706,8 +1668,27 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
|
|||
// as a diagnostic was already sent off to the main thread - just
|
||||
// surface that there was an error in this worker.
|
||||
bomb.result = {
|
||||
let _prof_timer = work.start_profiling(&cgcx);
|
||||
Some(execute_work_item(&cgcx, work))
|
||||
let module_config = cgcx.config(work.module_kind());
|
||||
|
||||
Some(match work {
|
||||
WorkItem::Optimize(m) => {
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("codegen_module_optimize", &*m.name);
|
||||
execute_optimize_work_item(&cgcx, m, module_config)
|
||||
}
|
||||
WorkItem::CopyPostLtoArtifacts(m) => {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||
"codegen_copy_artifacts_from_incr_cache",
|
||||
&*m.name,
|
||||
);
|
||||
Ok(execute_copy_from_cache_work_item(&cgcx, m, module_config))
|
||||
}
|
||||
WorkItem::LTO(m) => {
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("codegen_module_perform_lto", m.name());
|
||||
execute_lto_work_item(&cgcx, m, module_config)
|
||||
}
|
||||
})
|
||||
};
|
||||
})
|
||||
.expect("failed to spawn thread");
|
||||
|
|
@ -1891,7 +1872,7 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
|||
pub metadata: EncodedMetadata,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub crate_info: CrateInfo,
|
||||
pub codegen_worker_receive: Receiver<Message<B>>,
|
||||
pub codegen_worker_receive: Receiver<CguMessage>,
|
||||
pub shared_emitter_main: SharedEmitterMain,
|
||||
pub output_filenames: Arc<OutputFilenames>,
|
||||
pub coordinator: Coordinator<B>,
|
||||
|
|
@ -1965,10 +1946,9 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
|
||||
pub fn wait_for_signal_to_codegen_item(&self) {
|
||||
match self.codegen_worker_receive.recv() {
|
||||
Ok(Message::CodegenItem) => {
|
||||
// Nothing to do
|
||||
Ok(CguMessage) => {
|
||||
// Ok to proceed.
|
||||
}
|
||||
Ok(_) => panic!("unexpected message"),
|
||||
Err(_) => {
|
||||
// One of the LLVM threads must have panicked, fall through so
|
||||
// error handling can be reached.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::mir::place::PlaceRef;
|
|||
use crate::traits::*;
|
||||
use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
|
||||
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS};
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
|
|
@ -580,7 +580,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
) -> OngoingCodegen<B> {
|
||||
// Skip crate items and just output metadata in -Z no-codegen mode.
|
||||
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
|
||||
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1);
|
||||
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None);
|
||||
|
||||
ongoing_codegen.codegen_finished(tcx);
|
||||
|
||||
|
|
@ -631,14 +631,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
})
|
||||
});
|
||||
|
||||
let ongoing_codegen = start_async_codegen(
|
||||
backend.clone(),
|
||||
tcx,
|
||||
target_cpu,
|
||||
metadata,
|
||||
metadata_module,
|
||||
codegen_units.len(),
|
||||
);
|
||||
let ongoing_codegen =
|
||||
start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module);
|
||||
|
||||
// Codegen an allocator shim, if necessary.
|
||||
if let Some(kind) = allocator_kind_for_codegen(tcx) {
|
||||
|
|
@ -921,7 +915,21 @@ impl CrateInfo {
|
|||
missing_weak_lang_items
|
||||
.iter()
|
||||
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
|
||||
)
|
||||
);
|
||||
if tcx.allocator_kind(()).is_some() {
|
||||
// At least one crate needs a global allocator. This crate may be placed
|
||||
// after the crate that defines it in the linker order, in which case some
|
||||
// linkers return an error. By adding the global allocator shim methods to
|
||||
// the linked_symbols list, linking the generated symbols.o will ensure that
|
||||
// circular dependencies involving the global allocator don't lead to linker
|
||||
// errors.
|
||||
linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
|
||||
(
|
||||
format!("{prefix}{}", global_fn_name(method.name).as_str()),
|
||||
SymbolExportKind::Text,
|
||||
)
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// all shifts). For 32- and 64-bit types, this matches the semantics
|
||||
// of Java. (See related discussion on #1877 and #10183.)
|
||||
|
||||
pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
lhs: Bx::Value,
|
||||
rhs: Bx::Value,
|
||||
|
|
@ -143,7 +143,7 @@ pub fn build_unchecked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
bx.shl(lhs, rhs)
|
||||
}
|
||||
|
||||
pub fn build_unchecked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
lhs_t: Ty<'tcx>,
|
||||
lhs: Bx::Value,
|
||||
|
|
|
|||
|
|
@ -1280,7 +1280,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
destination,
|
||||
target,
|
||||
unwind,
|
||||
from_hir_call: _,
|
||||
call_source: _,
|
||||
fn_span,
|
||||
} => self.codegen_call_terminator(
|
||||
helper,
|
||||
|
|
|
|||
|
|
@ -211,52 +211,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
args[1].val.unaligned_volatile_store(bx, dst);
|
||||
return;
|
||||
}
|
||||
| sym::unchecked_shl
|
||||
| sym::unchecked_shr
|
||||
| sym::unchecked_add
|
||||
| sym::unchecked_sub
|
||||
| sym::unchecked_mul
|
||||
| sym::exact_div => {
|
||||
sym::exact_div => {
|
||||
let ty = arg_tys[0];
|
||||
match int_type_width_signed(ty, bx.tcx()) {
|
||||
Some((_width, signed)) => match name {
|
||||
sym::exact_div => {
|
||||
if signed {
|
||||
bx.exactsdiv(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
Some((_width, signed)) => {
|
||||
if signed {
|
||||
bx.exactsdiv(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
|
||||
sym::unchecked_shr => {
|
||||
if signed {
|
||||
bx.ashr(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.lshr(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_add => {
|
||||
if signed {
|
||||
bx.unchecked_sadd(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.unchecked_uadd(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_sub => {
|
||||
if signed {
|
||||
bx.unchecked_ssub(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.unchecked_usub(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_mul => {
|
||||
if signed {
|
||||
bx.unchecked_smul(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.unchecked_umul(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
_ => bug!(),
|
||||
},
|
||||
None => {
|
||||
bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
|
||||
|
|
|
|||
|
|
@ -798,6 +798,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.add(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::AddUnchecked => {
|
||||
if is_signed {
|
||||
bx.unchecked_sadd(lhs, rhs)
|
||||
} else {
|
||||
bx.unchecked_uadd(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::Sub => {
|
||||
if is_float {
|
||||
bx.fsub(lhs, rhs)
|
||||
|
|
@ -805,6 +812,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.sub(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::SubUnchecked => {
|
||||
if is_signed {
|
||||
bx.unchecked_ssub(lhs, rhs)
|
||||
} else {
|
||||
bx.unchecked_usub(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::Mul => {
|
||||
if is_float {
|
||||
bx.fmul(lhs, rhs)
|
||||
|
|
@ -812,6 +826,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.mul(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::MulUnchecked => {
|
||||
if is_signed {
|
||||
bx.unchecked_smul(lhs, rhs)
|
||||
} else {
|
||||
bx.unchecked_umul(lhs, rhs)
|
||||
}
|
||||
}
|
||||
mir::BinOp::Div => {
|
||||
if is_float {
|
||||
bx.fdiv(lhs, rhs)
|
||||
|
|
@ -848,8 +869,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.inbounds_gep(llty, lhs, &[rhs])
|
||||
}
|
||||
}
|
||||
mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
|
||||
mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
|
||||
mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs),
|
||||
mir::BinOp::ShlUnchecked => {
|
||||
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
|
||||
bx.shl(lhs, rhs)
|
||||
}
|
||||
mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs),
|
||||
mir::BinOp::ShrUnchecked => {
|
||||
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
|
||||
if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
|
||||
}
|
||||
mir::BinOp::Ne
|
||||
| mir::BinOp::Lt
|
||||
| mir::BinOp::Gt
|
||||
|
|
|
|||
|
|
@ -210,6 +210,9 @@ const_eval_long_running =
|
|||
.label = the const evaluator is currently interpreting this expression
|
||||
.help = the constant being evaluated
|
||||
|
||||
const_eval_match_eq_non_const = cannot match on `{$ty}` in {const_eval_const_context}s
|
||||
.note = `{$ty}` cannot be compared in compile-time, and therefore cannot be used in `match`es
|
||||
|
||||
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
|
||||
|
||||
const_eval_memory_access_test = memory access failed
|
||||
|
|
|
|||
|
|
@ -271,6 +271,18 @@ pub struct RawBytesNote {
|
|||
pub bytes: String,
|
||||
}
|
||||
|
||||
// FIXME(fee1-dead) do not use stringly typed `ConstContext`
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_match_eq_non_const, code = "E0015")]
|
||||
#[note]
|
||||
pub struct NonConstMatchEq<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub kind: ConstContext,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_for_loop_into_iter_non_const, code = "E0015")]
|
||||
pub struct NonConstForLoopIntoIter<'tcx> {
|
||||
|
|
|
|||
|
|
@ -234,37 +234,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let r = self.read_immediate(&args[1])?;
|
||||
self.exact_div(&l, &r, dest)?;
|
||||
}
|
||||
sym::unchecked_shl
|
||||
| sym::unchecked_shr
|
||||
| sym::unchecked_add
|
||||
| sym::unchecked_sub
|
||||
| sym::unchecked_mul => {
|
||||
let l = self.read_immediate(&args[0])?;
|
||||
let r = self.read_immediate(&args[1])?;
|
||||
let bin_op = match intrinsic_name {
|
||||
sym::unchecked_shl => BinOp::Shl,
|
||||
sym::unchecked_shr => BinOp::Shr,
|
||||
sym::unchecked_add => BinOp::Add,
|
||||
sym::unchecked_sub => BinOp::Sub,
|
||||
sym::unchecked_mul => BinOp::Mul,
|
||||
_ => bug!(),
|
||||
};
|
||||
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
|
||||
if overflowed {
|
||||
let layout = self.layout_of(substs.type_at(0))?;
|
||||
let r_val = r.to_scalar().to_bits(layout.size)?;
|
||||
if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_overflow_shift,
|
||||
val = r_val,
|
||||
name = intrinsic_name
|
||||
);
|
||||
} else {
|
||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
||||
}
|
||||
}
|
||||
self.write_scalar(val, dest)?;
|
||||
}
|
||||
sym::rotate_left | sym::rotate_right => {
|
||||
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
|
||||
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ use rustc_middle::mir;
|
|||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::abi::Abi;
|
||||
|
||||
use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
|
||||
/// and a boolean signifying the potential overflow to the destination.
|
||||
|
|
@ -139,8 +142,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
let throw_ub_on_overflow = match bin_op {
|
||||
AddUnchecked => Some(sym::unchecked_add),
|
||||
SubUnchecked => Some(sym::unchecked_sub),
|
||||
MulUnchecked => Some(sym::unchecked_mul),
|
||||
ShlUnchecked => Some(sym::unchecked_shl),
|
||||
ShrUnchecked => Some(sym::unchecked_shr),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Shift ops can have an RHS with a different numeric type.
|
||||
if bin_op == Shl || bin_op == Shr {
|
||||
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
||||
let size = u128::from(left_layout.size.bits());
|
||||
// Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its
|
||||
// zero-extended form). This matches the codegen backend:
|
||||
|
|
@ -155,6 +167,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// integers are maximally 128bits wide, so negative shifts *always* overflow and we have
|
||||
// consistent results for the same value represented at different bit widths.
|
||||
assert!(size <= 128);
|
||||
let original_r = r;
|
||||
let overflow = r >= size;
|
||||
// The shift offset is implicitly masked to the type size, to make sure this operation
|
||||
// is always defined. This is the one MIR operator that does *not* directly map to a
|
||||
|
|
@ -166,19 +179,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let result = if left_layout.abi.is_signed() {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let result = match bin_op {
|
||||
Shl => l.checked_shl(r).unwrap(),
|
||||
Shr => l.checked_shr(r).unwrap(),
|
||||
Shl | ShlUnchecked => l.checked_shl(r).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(r).unwrap(),
|
||||
_ => bug!(),
|
||||
};
|
||||
result as u128
|
||||
} else {
|
||||
match bin_op {
|
||||
Shl => l.checked_shl(r).unwrap(),
|
||||
Shr => l.checked_shr(r).unwrap(),
|
||||
Shl | ShlUnchecked => l.checked_shl(r).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(r).unwrap(),
|
||||
_ => bug!(),
|
||||
}
|
||||
};
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
|
||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_overflow_shift,
|
||||
val = original_r,
|
||||
name = intrinsic_name
|
||||
);
|
||||
}
|
||||
|
||||
return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty));
|
||||
}
|
||||
|
||||
|
|
@ -216,9 +238,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Rem if r == 0 => throw_ub!(RemainderByZero),
|
||||
Div => Some(i128::overflowing_div),
|
||||
Rem => Some(i128::overflowing_rem),
|
||||
Add => Some(i128::overflowing_add),
|
||||
Sub => Some(i128::overflowing_sub),
|
||||
Mul => Some(i128::overflowing_mul),
|
||||
Add | AddUnchecked => Some(i128::overflowing_add),
|
||||
Sub | SubUnchecked => Some(i128::overflowing_sub),
|
||||
Mul | MulUnchecked => Some(i128::overflowing_mul),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(op) = op {
|
||||
|
|
@ -242,11 +264,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// If that truncation loses any information, we have an overflow.
|
||||
let result = result as u128;
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((
|
||||
Scalar::from_uint(truncated, size),
|
||||
oflo || self.sign_extend(truncated, left_layout) != result,
|
||||
left_layout.ty,
|
||||
));
|
||||
let overflow = oflo || self.sign_extend(truncated, left_layout) != result;
|
||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
||||
}
|
||||
return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,12 +285,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
|
||||
BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
|
||||
|
||||
Add | Sub | Mul | Rem | Div => {
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => {
|
||||
assert!(!left_layout.abi.is_signed());
|
||||
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
|
||||
Add => u128::overflowing_add,
|
||||
Sub => u128::overflowing_sub,
|
||||
Mul => u128::overflowing_mul,
|
||||
Add | AddUnchecked => u128::overflowing_add,
|
||||
Sub | SubUnchecked => u128::overflowing_sub,
|
||||
Mul | MulUnchecked => u128::overflowing_mul,
|
||||
Div if r == 0 => throw_ub!(DivisionByZero),
|
||||
Rem if r == 0 => throw_ub!(RemainderByZero),
|
||||
Div => u128::overflowing_div,
|
||||
|
|
@ -279,11 +301,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Truncate to target type.
|
||||
// If that truncation loses any information, we have an overflow.
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((
|
||||
Scalar::from_uint(truncated, size),
|
||||
oflo || truncated != result,
|
||||
left_layout.ty,
|
||||
));
|
||||
let overflow = oflo || truncated != result;
|
||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
||||
}
|
||||
return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
|
||||
}
|
||||
|
||||
_ => span_bug!(
|
||||
|
|
|
|||
|
|
@ -9,27 +9,7 @@ use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
|||
use rustc_middle::ty::layout::LayoutOf;
|
||||
|
||||
use super::{ImmTy, InterpCx, Machine};
|
||||
|
||||
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
|
||||
/// same type as the result.
|
||||
#[inline]
|
||||
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
match op {
|
||||
Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Offset | Shl | Shr => true,
|
||||
Eq | Ne | Lt | Le | Gt | Ge => false,
|
||||
}
|
||||
}
|
||||
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
|
||||
/// same type as the LHS.
|
||||
#[inline]
|
||||
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
match op {
|
||||
Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
|
||||
Offset | Shl | Shr => false,
|
||||
}
|
||||
}
|
||||
use crate::util;
|
||||
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Returns `true` as long as there are more things to do.
|
||||
|
|
@ -179,9 +159,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
BinaryOp(bin_op, box (ref left, ref right)) => {
|
||||
let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
|
||||
let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout);
|
||||
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
|
||||
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
||||
self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
|
||||
}
|
||||
|
|
@ -189,7 +169,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
|
||||
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
|
||||
let left = self.read_immediate(&self.eval_operand(left, None)?)?;
|
||||
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
||||
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
destination,
|
||||
target,
|
||||
unwind,
|
||||
from_hir_call: _,
|
||||
call_source: _,
|
||||
fn_span: _,
|
||||
} => {
|
||||
let old_stack = self.frame_idx();
|
||||
|
|
|
|||
|
|
@ -412,7 +412,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
BorrowKind::Shallow => {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
||||
}
|
||||
BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow),
|
||||
BorrowKind::Mut { .. } => {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
}
|
||||
|
|
@ -457,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => {
|
||||
Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
let is_allowed = match ty.kind() {
|
||||
// Inside a `static mut`, `&mut [...]` is allowed.
|
||||
|
|
@ -478,11 +477,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
};
|
||||
|
||||
if !is_allowed {
|
||||
if let BorrowKind::Mut { .. } = kind {
|
||||
self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
|
||||
} else {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -702,7 +697,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
self.super_terminator(terminator, location);
|
||||
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
|
||||
TerminatorKind::Call { func, args, fn_span, call_source, .. } => {
|
||||
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
||||
let caller = self.def_id();
|
||||
|
||||
|
|
@ -755,7 +750,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
call_source: *call_source,
|
||||
feature: Some(sym::const_trait_impl),
|
||||
});
|
||||
return;
|
||||
|
|
@ -797,7 +792,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
call_source: *call_source,
|
||||
feature: None,
|
||||
});
|
||||
|
||||
|
|
@ -823,7 +818,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
call_source: *call_source,
|
||||
feature: None,
|
||||
});
|
||||
return;
|
||||
|
|
@ -866,7 +861,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
call_source: *call_source,
|
||||
feature: None,
|
||||
});
|
||||
return;
|
||||
|
|
@ -926,7 +921,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
callee,
|
||||
substs,
|
||||
span: *fn_span,
|
||||
from_hir_call: *from_hir_call,
|
||||
call_source: *call_source,
|
||||
feature: None,
|
||||
});
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::{self, CallSource};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
|
||||
|
|
@ -100,7 +100,7 @@ pub struct FnCallNonConst<'tcx> {
|
|||
pub callee: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
pub span: Span,
|
||||
pub from_hir_call: bool,
|
||||
pub call_source: CallSource,
|
||||
pub feature: Option<Symbol>,
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
ccx: &ConstCx<'_, 'tcx>,
|
||||
_: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
|
||||
let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self;
|
||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||
|
||||
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
||||
|
|
@ -157,7 +157,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
|
||||
let call_kind =
|
||||
call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None);
|
||||
|
||||
debug!(?call_kind);
|
||||
|
||||
|
|
@ -219,48 +220,59 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
err
|
||||
}
|
||||
CallKind::Operator { trait_id, self_ty, .. } => {
|
||||
let mut sugg = None;
|
||||
let mut err = if let CallSource::MatchCmp = call_source {
|
||||
tcx.sess.create_err(errors::NonConstMatchEq {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
ty: self_ty,
|
||||
})
|
||||
} else {
|
||||
let mut sugg = None;
|
||||
|
||||
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
|
||||
match (substs[0].unpack(), substs[1].unpack()) {
|
||||
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
|
||||
if self_ty == rhs_ty
|
||||
&& self_ty.is_ref()
|
||||
&& self_ty.peel_refs().is_primitive() =>
|
||||
{
|
||||
let mut num_refs = 0;
|
||||
let mut tmp_ty = self_ty;
|
||||
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
|
||||
num_refs += 1;
|
||||
tmp_ty = *inner_ty;
|
||||
}
|
||||
let deref = "*".repeat(num_refs);
|
||||
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
|
||||
match (substs[0].unpack(), substs[1].unpack()) {
|
||||
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
|
||||
if self_ty == rhs_ty
|
||||
&& self_ty.is_ref()
|
||||
&& self_ty.peel_refs().is_primitive() =>
|
||||
{
|
||||
let mut num_refs = 0;
|
||||
let mut tmp_ty = self_ty;
|
||||
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
|
||||
num_refs += 1;
|
||||
tmp_ty = *inner_ty;
|
||||
}
|
||||
let deref = "*".repeat(num_refs);
|
||||
|
||||
if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
if let Some(eq_idx) = call_str.find("==") {
|
||||
if let Some(rhs_idx) =
|
||||
call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
|
||||
{
|
||||
let rhs_pos =
|
||||
span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
||||
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
||||
sugg = Some(errors::ConsiderDereferencing {
|
||||
deref,
|
||||
span: span.shrink_to_lo(),
|
||||
rhs_span,
|
||||
});
|
||||
if let Ok(call_str) =
|
||||
ccx.tcx.sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
if let Some(eq_idx) = call_str.find("==") {
|
||||
if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
|
||||
.find(|c: char| !c.is_whitespace())
|
||||
{
|
||||
let rhs_pos = span.lo()
|
||||
+ BytePos::from_usize(eq_idx + 2 + rhs_idx);
|
||||
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
|
||||
sugg = Some(errors::ConsiderDereferencing {
|
||||
deref,
|
||||
span: span.shrink_to_lo(),
|
||||
rhs_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut err = tcx.sess.create_err(errors::NonConstOperator {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
sugg,
|
||||
});
|
||||
tcx.sess.create_err(errors::NonConstOperator {
|
||||
span,
|
||||
kind: ccx.const_kind(),
|
||||
sugg,
|
||||
})
|
||||
};
|
||||
|
||||
diag_trait(&mut err, self_ty, trait_id);
|
||||
err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ where
|
|||
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
|
||||
match kind {
|
||||
mir::BorrowKind::Mut { .. } => true,
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
|
||||
mir::BorrowKind::Shared | mir::BorrowKind::Shallow => {
|
||||
self.shared_borrow_allows_mutation(place)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,7 +454,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
match kind {
|
||||
// Reject these borrow types just to be safe.
|
||||
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
|
||||
BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
|
||||
BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
BorrowKind::Shared => {
|
||||
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
|
||||
|
|
@ -463,7 +465,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
BorrowKind::Mut { .. } => {
|
||||
// FIXME: consider changing this to only promote &mut [] for default borrows,
|
||||
// also forbidding two phase borrows
|
||||
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
|
||||
// In theory, any zero-sized value could be borrowed
|
||||
|
|
@ -569,13 +573,18 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
| BinOp::Gt
|
||||
| BinOp::Offset
|
||||
| BinOp::Add
|
||||
| BinOp::AddUnchecked
|
||||
| BinOp::Sub
|
||||
| BinOp::SubUnchecked
|
||||
| BinOp::Mul
|
||||
| BinOp::MulUnchecked
|
||||
| BinOp::BitXor
|
||||
| BinOp::BitAnd
|
||||
| BinOp::BitOr
|
||||
| BinOp::Shl
|
||||
| BinOp::Shr => {}
|
||||
| BinOp::ShlUnchecked
|
||||
| BinOp::Shr
|
||||
| BinOp::ShrUnchecked => {}
|
||||
}
|
||||
|
||||
self.validate_operand(lhs)?;
|
||||
|
|
@ -792,7 +801,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
};
|
||||
|
||||
match terminator.kind {
|
||||
TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => {
|
||||
TerminatorKind::Call {
|
||||
mut func, mut args, call_source: desugar, fn_span, ..
|
||||
} => {
|
||||
self.visit_operand(&mut func, loc);
|
||||
for arg in &mut args {
|
||||
self.visit_operand(arg, loc);
|
||||
|
|
@ -808,7 +819,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
unwind: UnwindAction::Continue,
|
||||
destination: Place::from(new_temp),
|
||||
target: Some(new_target),
|
||||
from_hir_call,
|
||||
call_source: desugar,
|
||||
fn_span,
|
||||
},
|
||||
source_info: SourceInfo::outermost(terminator.source_info.span),
|
||||
|
|
|
|||
|
|
@ -498,8 +498,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
macro_rules! check_kinds {
|
||||
($t:expr, $text:literal, $($patterns:tt)*) => {
|
||||
if !matches!(($t).kind(), $($patterns)*) {
|
||||
($t:expr, $text:literal, $typat:pat) => {
|
||||
if !matches!(($t).kind(), $typat) {
|
||||
self.fail(location, format!($text, $t));
|
||||
}
|
||||
};
|
||||
|
|
@ -527,6 +527,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
use BinOp::*;
|
||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||
let b = vals.1.ty(&self.body.local_decls, self.tcx);
|
||||
if crate::util::binop_right_homogeneous(*op) {
|
||||
if let Eq | Lt | Le | Ne | Ge | Gt = op {
|
||||
// The function pointer types can have lifetimes
|
||||
if !self.mir_assign_valid_types(a, b) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"),
|
||||
);
|
||||
}
|
||||
} else if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match op {
|
||||
Offset => {
|
||||
check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
|
||||
|
|
@ -538,7 +557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot compare type {:?}",
|
||||
"Cannot {op:?} compare type {:?}",
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
|
|
@ -548,19 +567,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
| ty::FnPtr(..)
|
||||
)
|
||||
}
|
||||
// The function pointer types can have lifetimes
|
||||
if !self.mir_assign_valid_types(a, b) {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot compare unequal types {:?} and {:?}", a, b),
|
||||
);
|
||||
}
|
||||
}
|
||||
Shl | Shr => {
|
||||
AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
|
||||
| ShrUnchecked => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot shift non-integer type {:?}",
|
||||
"Cannot {op:?} non-integer type {:?}",
|
||||
ty::Uint(..) | ty::Int(..)
|
||||
)
|
||||
}
|
||||
|
|
@ -569,37 +582,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform bitwise op on type {:?}",
|
||||
"Cannot perform bitwise op {op:?} on type {:?}",
|
||||
ty::Uint(..) | ty::Int(..) | ty::Bool
|
||||
)
|
||||
}
|
||||
if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Cannot perform bitwise op on unequal types {:?} and {:?}",
|
||||
a, b
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Add | Sub | Mul | Div | Rem => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform arithmetic on type {:?}",
|
||||
"Cannot perform arithmetic {op:?} on type {:?}",
|
||||
ty::Uint(..) | ty::Int(..) | ty::Float(..)
|
||||
)
|
||||
}
|
||||
if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Cannot perform arithmetic on unequal types {:?} and {:?}",
|
||||
a, b
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use rustc_middle::mir;
|
||||
|
||||
mod alignment;
|
||||
mod check_validity_requirement;
|
||||
mod compare_types;
|
||||
|
|
@ -7,3 +9,27 @@ pub use self::alignment::is_disaligned;
|
|||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::type_name::type_name;
|
||||
|
||||
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
|
||||
/// same type as the result.
|
||||
#[inline]
|
||||
pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
match op {
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
|
||||
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
|
||||
Eq | Ne | Lt | Le | Gt | Ge => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
|
||||
/// same type as the LHS.
|
||||
#[inline]
|
||||
pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
match op {
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
|
||||
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
|
||||
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::sip128::SipHasher128;
|
||||
use rustc_index::bit_set::{self, BitSet};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
|
|
@ -597,6 +597,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, T, CTX> HashStable<CTX> for IndexSlice<I, T>
|
||||
where
|
||||
T: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.len().hash_stable(ctx, hasher);
|
||||
for v in &self.raw {
|
||||
v.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Idx, T, CTX> HashStable<CTX> for IndexVec<I, T>
|
||||
where
|
||||
T: HashStable<CTX>,
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
{
|
||||
UnordItems(self.0.flat_map(f))
|
||||
}
|
||||
|
||||
pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> UnordItems<T, std::iter::Empty<T>> {
|
||||
|
|
@ -161,10 +165,6 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
|
||||
items
|
||||
}
|
||||
|
||||
pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a set collection type that tries very hard to not expose
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
|||
rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_const_eval::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_error_messages::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_errors::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_expand::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_hir_typeck::DEFAULT_LOCALE_RESOURCE,
|
||||
|
|
@ -329,7 +330,7 @@ fn run_compiler(
|
|||
return;
|
||||
}
|
||||
let should_stop =
|
||||
print_crate_info(&***compiler.codegen_backend(), compiler.session(), false);
|
||||
print_crate_info(&**compiler.codegen_backend(), compiler.session(), false);
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
return;
|
||||
|
|
@ -351,7 +352,7 @@ fn run_compiler(
|
|||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
let should_stop = print_crate_info(&***compiler.codegen_backend(), sess, true)
|
||||
let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true)
|
||||
.and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
|
||||
.and_then(|| try_process_rlink(sess, compiler));
|
||||
|
||||
|
|
@ -424,7 +425,7 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
queries.ongoing_codegen()?;
|
||||
let ongoing_codegen = queries.ongoing_codegen()?;
|
||||
|
||||
if sess.opts.unstable_opts.print_type_sizes {
|
||||
sess.code_stats.print_type_sizes();
|
||||
|
|
@ -437,7 +438,7 @@ fn run_compiler(
|
|||
sess.code_stats.print_vtable_sizes(crate_name);
|
||||
}
|
||||
|
||||
let linker = queries.linker()?;
|
||||
let linker = queries.linker(ongoing_codegen)?;
|
||||
Ok(Some(linker))
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -535,7 +535,7 @@ pub fn compile_declarative_macro(
|
|||
.pop()
|
||||
.unwrap();
|
||||
}
|
||||
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
|
||||
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
|
||||
})
|
||||
.collect::<Vec<mbe::TokenTree>>(),
|
||||
_ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
|
||||
|
|
|
|||
|
|
@ -395,6 +395,8 @@ declare_features! (
|
|||
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
(active, exhaustive_patterns, "1.13.0", Some(51085), None),
|
||||
/// Allows explicit tail calls via `become` expression.
|
||||
(incomplete, explicit_tail_calls, "CURRENT_RUSTC_VERSION", Some(112788), None),
|
||||
/// Allows using `efiapi`, `sysv64` and `win64` as calling convention
|
||||
/// for functions with varargs.
|
||||
(active, extended_varargs_abi_support, "1.65.0", Some(100189), None),
|
||||
|
|
@ -440,6 +442,8 @@ declare_features! (
|
|||
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
|
||||
// Allows setting the threshold for the `large_assignments` lint.
|
||||
(active, large_assignments, "1.52.0", Some(83518), None),
|
||||
/// Allow to have type alias types for inter-crate use.
|
||||
(active, lazy_type_alias, "CURRENT_RUSTC_VERSION", Some(112792), None),
|
||||
/// Allows `if/while p && let q = r && ...` chains.
|
||||
(active, let_chains, "1.37.0", Some(53667), None),
|
||||
/// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check.
|
||||
|
|
|
|||
|
|
@ -705,7 +705,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false,
|
||||
rustc_deny_explicit_impl,
|
||||
AttributeType::Normal,
|
||||
template!(List: "implement_via_object = (true|false)"),
|
||||
ErrorFollowing,
|
||||
@only_local: true,
|
||||
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
|
|
|
|||
|
|
@ -3743,6 +3743,29 @@ impl<'hir> Node<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the type for constants, assoc types, type aliases and statics.
|
||||
pub fn ty(self) -> Option<&'hir Ty<'hir>> {
|
||||
match self {
|
||||
Node::Item(it) => match it.kind {
|
||||
ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => {
|
||||
Some(ty)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Node::TraitItem(it) => match it.kind {
|
||||
TraitItemKind::Const(ty, _) => Some(ty),
|
||||
TraitItemKind::Type(_, ty) => ty,
|
||||
_ => None,
|
||||
},
|
||||
Node::ImplItem(it) => match it.kind {
|
||||
ImplItemKind::Const(ty, _) => Some(ty),
|
||||
ImplItemKind::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias_ty(self) -> Option<&'hir Ty<'hir>> {
|
||||
match self {
|
||||
Node::Item(Item { kind: ItemKind::TyAlias(ty, ..), .. }) => Some(ty),
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
|||
// an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
|
||||
let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
|
||||
let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
|
||||
&& tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
|
||||
&& tcx.is_impl_trait_in_trait(alias_ty.def_id)
|
||||
{
|
||||
alias_ty
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -122,9 +122,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
let all_candidate_names: Vec<_> = all_candidates()
|
||||
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
|
||||
.filter_map(
|
||||
|item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
|
||||
)
|
||||
.filter_map(|item| {
|
||||
if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type {
|
||||
Some(item.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let (Some(suggested_name), true) = (
|
||||
|
|
@ -159,9 +163,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.flat_map(|trait_def_id| {
|
||||
self.tcx().associated_items(*trait_def_id).in_definition_order()
|
||||
})
|
||||
.filter_map(
|
||||
|item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
|
||||
)
|
||||
.filter_map(|item| {
|
||||
if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type {
|
||||
Some(item.name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let (Some(suggested_name), true) = (
|
||||
|
|
@ -343,7 +351,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let format_pred = |pred: ty::Predicate<'tcx>| {
|
||||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// `<Foo as Iterator>::Item = String`.
|
||||
let projection_ty = pred.skip_binder().projection_ty;
|
||||
|
|
@ -364,7 +372,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
|
||||
Some((obligation, projection_ty.self_ty()))
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
|
||||
let p = poly_trait_ref.trait_ref;
|
||||
let self_ty = p.self_ty();
|
||||
let path = p.print_only_trait_path();
|
||||
|
|
|
|||
|
|
@ -896,7 +896,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let ty = self.tcx().at(span).type_of(did);
|
||||
|
||||
if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
|
||||
&& ty.skip_binder().has_opaque_types()
|
||||
&& (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias)
|
||||
{
|
||||
// Type aliases referring to types that contain opaque types (but aren't just directly
|
||||
// referencing a single opaque type) get encoded as a type alias that normalization will
|
||||
|
|
@ -945,12 +945,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
let mut trait_bounds = vec![];
|
||||
let mut projection_bounds = vec![];
|
||||
for (clause, span) in bounds.predicates() {
|
||||
let pred: ty::Predicate<'tcx> = clause.to_predicate(tcx);
|
||||
for (clause, span) in bounds.clauses() {
|
||||
let pred: ty::Predicate<'tcx> = clause.as_predicate();
|
||||
let bound_pred = pred.kind();
|
||||
match bound_pred.skip_binder() {
|
||||
ty::PredicateKind::Clause(clause) => match clause {
|
||||
ty::Clause::Trait(trait_pred) => {
|
||||
ty::ClauseKind::Trait(trait_pred) => {
|
||||
assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
|
||||
trait_bounds.push((
|
||||
bound_pred.rebind(trait_pred.trait_ref),
|
||||
|
|
@ -958,16 +958,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
trait_pred.constness,
|
||||
));
|
||||
}
|
||||
ty::Clause::Projection(proj) => {
|
||||
ty::ClauseKind::Projection(proj) => {
|
||||
projection_bounds.push((bound_pred.rebind(proj), span));
|
||||
}
|
||||
ty::Clause::TypeOutlives(_) => {
|
||||
ty::ClauseKind::TypeOutlives(_) => {
|
||||
// Do nothing, we deal with regions separately
|
||||
}
|
||||
ty::Clause::RegionOutlives(_)
|
||||
| ty::Clause::ConstArgHasType(..)
|
||||
| ty::Clause::WellFormed(_)
|
||||
| ty::Clause::ConstEvaluatable(_) => bug!(),
|
||||
ty::ClauseKind::RegionOutlives(_)
|
||||
| ty::ClauseKind::ConstArgHasType(..)
|
||||
| ty::ClauseKind::WellFormed(_)
|
||||
| ty::ClauseKind::ConstEvaluatable(_) => {
|
||||
bug!()
|
||||
}
|
||||
},
|
||||
ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
|
|
@ -1064,7 +1066,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
associated_types.entry(span).or_default().extend(
|
||||
tcx.associated_items(pred.def_id())
|
||||
|
|
@ -1074,7 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
.map(|item| item.def_id),
|
||||
);
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
|
||||
let pred = bound_predicate.rebind(pred);
|
||||
// A `Self` within the original bound will be substituted with a
|
||||
// `trait_object_dummy_self`, so check for that.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
//! `ty` form from the HIR.
|
||||
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::ty::Binder;
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -24,58 +23,58 @@ use rustc_span::Span;
|
|||
/// include the self type (e.g., `trait_bounds`) but in others we do not
|
||||
#[derive(Default, PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Bounds<'tcx> {
|
||||
pub predicates: Vec<(Binder<'tcx, ty::Clause<'tcx>>, Span)>,
|
||||
pub clauses: Vec<(ty::Clause<'tcx>, Span)>,
|
||||
}
|
||||
|
||||
impl<'tcx> Bounds<'tcx> {
|
||||
pub fn push_region_bound(
|
||||
&mut self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region: ty::PolyTypeOutlivesPredicate<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
self.predicates.push((region.map_bound(|p| ty::Clause::TypeOutlives(p)), span));
|
||||
self.clauses
|
||||
.push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span));
|
||||
}
|
||||
|
||||
pub fn push_trait_bound(
|
||||
&mut self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) {
|
||||
self.predicates.push((
|
||||
trait_ref.map_bound(|trait_ref| {
|
||||
ty::Clause::Trait(ty::TraitPredicate { trait_ref, constness, polarity })
|
||||
}),
|
||||
self.clauses.push((
|
||||
trait_ref
|
||||
.map_bound(|trait_ref| {
|
||||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, constness, polarity })
|
||||
})
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push_projection_bound(
|
||||
&mut self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
projection: ty::PolyProjectionPredicate<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
self.predicates.push((projection.map_bound(|proj| ty::Clause::Projection(proj)), span));
|
||||
self.clauses.push((
|
||||
projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
|
||||
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
|
||||
let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
|
||||
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
|
||||
self.predicates.insert(
|
||||
0,
|
||||
(
|
||||
ty::Binder::dummy(ty::Clause::Trait(trait_ref.without_const().to_predicate(tcx))),
|
||||
span,
|
||||
),
|
||||
);
|
||||
self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
|
||||
}
|
||||
|
||||
pub fn predicates(&self) -> impl Iterator<Item = (Binder<'tcx, ty::Clause<'tcx>>, Span)> + '_ {
|
||||
self.predicates.iter().cloned()
|
||||
pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
|
||||
self.clauses.iter().cloned()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
|
||||
// hidden type is well formed even without those bounds.
|
||||
let predicate =
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(hidden_ty.into())));
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));
|
||||
ocx.register_obligation(Obligation::new(tcx, misc_cause, param_env, predicate));
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
|
@ -563,8 +563,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
|||
check_union(tcx, id.owner_id.def_id);
|
||||
}
|
||||
DefKind::OpaqueTy => {
|
||||
let opaque = tcx.hir().expect_item(id.owner_id.def_id).expect_opaque_ty();
|
||||
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = opaque.origin
|
||||
let origin = tcx.opaque_type_origin(id.owner_id.def_id);
|
||||
if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin
|
||||
&& let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id)
|
||||
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
|
||||
unnormalized_impl_fty.into(),
|
||||
))),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>(
|
|||
debug!("predicate {:?}", predicate);
|
||||
let bound_predicate = predicate.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
|
||||
let entry = types.entry(trait_predicate.self_ty()).or_default();
|
||||
let def_id = trait_predicate.def_id();
|
||||
if Some(def_id) != tcx.lang_items().sized_trait() {
|
||||
|
|
@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>(
|
|||
entry.push(trait_predicate.def_id());
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(projection_pred)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_pred)) => {
|
||||
projections.push(bound_predicate.rebind(projection_pred));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -403,7 +403,30 @@ fn fn_sig_suggestion<'tcx>(
|
|||
.flatten()
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ");
|
||||
let output = sig.output();
|
||||
let mut output = sig.output();
|
||||
|
||||
let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
|
||||
output = if let ty::Alias(_, alias_ty) = *output.kind() {
|
||||
tcx.explicit_item_bounds(alias_ty.def_id)
|
||||
.subst_iter_copied(tcx, alias_ty.substs)
|
||||
.find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty())
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
ident.span,
|
||||
"expected async fn to have `impl Future` output, but it returns {output}"
|
||||
)
|
||||
})
|
||||
} else {
|
||||
span_bug!(
|
||||
ident.span,
|
||||
"expected async fn to have `impl Future` output, but it returns {output}"
|
||||
)
|
||||
};
|
||||
"async "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
|
||||
|
||||
let unsafety = sig.unsafety.prefix_str();
|
||||
|
|
@ -414,7 +437,9 @@ fn fn_sig_suggestion<'tcx>(
|
|||
// lifetimes between the `impl` and the `trait`, but this should be good enough to
|
||||
// fill in a significant portion of the missing code, and other subsequent
|
||||
// suggestions can help the user fix the code.
|
||||
format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
|
||||
format!(
|
||||
"{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}"
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
|
||||
|
|
@ -443,19 +468,16 @@ fn suggestion_signature<'tcx>(
|
|||
);
|
||||
|
||||
match assoc.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
// We skip the binder here because the binder would deanonymize all
|
||||
// late-bound regions, and we don't want method signatures to show up
|
||||
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
|
||||
// regions just fine, showing `fn(&MyType)`.
|
||||
fn_sig_suggestion(
|
||||
tcx,
|
||||
tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(),
|
||||
assoc.ident(tcx),
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
|
||||
assoc,
|
||||
)
|
||||
}
|
||||
ty::AssocKind::Fn => fn_sig_suggestion(
|
||||
tcx,
|
||||
tcx.liberate_late_bound_regions(
|
||||
assoc.def_id,
|
||||
tcx.fn_sig(assoc.def_id).subst(tcx, substs),
|
||||
),
|
||||
assoc.ident(tcx),
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
|
||||
assoc,
|
||||
),
|
||||
ty::AssocKind::Type => {
|
||||
let (generics, where_clauses) = bounds_from_generic_predicates(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
self.tcx(),
|
||||
cause,
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::WellFormed(arg))),
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -419,10 +419,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||
let mut unsatisfied_bounds: Vec<_> = required_bounds
|
||||
.into_iter()
|
||||
.filter(|clause| match clause.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
|
||||
a,
|
||||
b,
|
||||
))) => !region_known_to_outlive(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
ty::OutlivesPredicate(a, b),
|
||||
)) => !region_known_to_outlive(
|
||||
tcx,
|
||||
gat_def_id.def_id,
|
||||
param_env,
|
||||
|
|
@ -430,7 +429,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
|
|||
a,
|
||||
b,
|
||||
),
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
a,
|
||||
b,
|
||||
))) => !ty_known_to_outlive(
|
||||
|
|
@ -574,7 +573,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
|||
);
|
||||
// The predicate we expect to see. (In our example,
|
||||
// `Self: 'me`.)
|
||||
let clause = ty::PredicateKind::Clause(ty::Clause::TypeOutlives(
|
||||
let clause = ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
|
||||
ty::OutlivesPredicate(ty_param, region_param),
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
|
|
@ -623,7 +622,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
|||
},
|
||||
);
|
||||
// The predicate we expect to see.
|
||||
let clause = ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
|
||||
let clause = ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
ty::OutlivesPredicate(region_a_param, region_b_param),
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
|
|
@ -1032,7 +1031,7 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
|
|||
tcx,
|
||||
cause,
|
||||
wfcx.param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(
|
||||
ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
|
||||
))),
|
||||
));
|
||||
|
|
@ -1087,7 +1086,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
|
|||
wfcx.infcx,
|
||||
wfcx.param_env,
|
||||
wfcx.body_def_id,
|
||||
normalized_bound,
|
||||
normalized_bound.as_predicate(),
|
||||
bound_span,
|
||||
)
|
||||
});
|
||||
|
|
@ -1544,8 +1543,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|||
if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind()
|
||||
&& self.seen.insert(unshifted_opaque_ty.def_id)
|
||||
&& let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local()
|
||||
&& let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty()
|
||||
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
|
||||
&& let origin = tcx.opaque_type_origin(opaque_def_id)
|
||||
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = origin
|
||||
&& source == self.fn_def_id
|
||||
{
|
||||
let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
|
||||
|
|
@ -1563,7 +1562,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
|||
self.wfcx.infcx,
|
||||
self.wfcx.param_env,
|
||||
self.wfcx.body_def_id,
|
||||
bound,
|
||||
bound.as_predicate(),
|
||||
bound_span,
|
||||
));
|
||||
// Set the debruijn index back to innermost here, since we already eagerly
|
||||
|
|
@ -1876,7 +1875,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
// We lower empty bounds like `Vec<dyn Copy>:` as
|
||||
// `WellFormed(Vec<dyn Copy>)`, which will later get checked by
|
||||
// regular WF checking
|
||||
if let ty::PredicateKind::Clause(ty::Clause::WellFormed(..)) = pred.kind().skip_binder()
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) =
|
||||
pred.kind().skip_binder()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ fn infringing_fields_error(
|
|||
.or_default()
|
||||
.push(error.obligation.cause.span);
|
||||
}
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use rustc_errors::{error_code, struct_span_err};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::sym;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
mod builtin;
|
||||
|
|
@ -44,7 +43,7 @@ fn enforce_trait_manually_implementable(
|
|||
let impl_header_span = tcx.def_span(impl_def_id);
|
||||
|
||||
// Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
|
||||
if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) {
|
||||
if tcx.trait_def(trait_def_id).deny_explicit_impl {
|
||||
let trait_name = tcx.item_name(trait_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
|
|
|
|||
|
|
@ -991,6 +991,50 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
no_dups.then_some(list)
|
||||
});
|
||||
|
||||
let mut deny_explicit_impl = false;
|
||||
let mut implement_via_object = true;
|
||||
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
|
||||
deny_explicit_impl = true;
|
||||
let mut seen_attr = false;
|
||||
for meta in attr.meta_item_list().iter().flatten() {
|
||||
if let Some(meta) = meta.meta_item()
|
||||
&& meta.name_or_empty() == sym::implement_via_object
|
||||
&& let Some(lit) = meta.name_value_literal()
|
||||
{
|
||||
if seen_attr {
|
||||
tcx.sess.span_err(
|
||||
meta.span,
|
||||
"duplicated `implement_via_object` meta item",
|
||||
);
|
||||
}
|
||||
seen_attr = true;
|
||||
|
||||
match lit.symbol {
|
||||
kw::True => {
|
||||
implement_via_object = true;
|
||||
}
|
||||
kw::False => {
|
||||
implement_via_object = false;
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_err(
|
||||
meta.span,
|
||||
format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tcx.sess.span_err(
|
||||
meta.span(),
|
||||
format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta),
|
||||
);
|
||||
}
|
||||
}
|
||||
if !seen_attr {
|
||||
tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item");
|
||||
}
|
||||
}
|
||||
|
||||
ty::TraitDef {
|
||||
def_id: def_id.to_def_id(),
|
||||
unsafety,
|
||||
|
|
@ -1001,6 +1045,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
skip_array_during_method_dispatch,
|
||||
specialization_kind,
|
||||
must_implement_one_of,
|
||||
implement_via_object,
|
||||
deny_explicit_impl,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use crate::astconv::{AstConv, OnlySelfBounds};
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::ToPredicate;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -20,7 +19,7 @@ fn associated_type_bounds<'tcx>(
|
|||
assoc_item_def_id: LocalDefId,
|
||||
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
span: Span,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
|
||||
let item_ty = tcx.mk_projection(
|
||||
assoc_item_def_id.to_def_id(),
|
||||
InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
|
||||
|
|
@ -34,23 +33,23 @@ fn associated_type_bounds<'tcx>(
|
|||
let trait_def_id = tcx.local_parent(assoc_item_def_id);
|
||||
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
|
||||
|
||||
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => tr.self_ty() == item_ty,
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
|
||||
let bounds_from_parent = trait_predicates
|
||||
.predicates
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|(pred, _)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty,
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
|
||||
proj.projection_ty.self_ty() == item_ty
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => outlives.0 == item_ty,
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
|
||||
outlives.0 == item_ty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
})
|
||||
.map(|(pred, span)| (pred.expect_clause(), span));
|
||||
|
||||
let all_bounds = tcx.arena.alloc_from_iter(
|
||||
bounds
|
||||
.predicates()
|
||||
.map(|(clause, span)| (clause.to_predicate(tcx), span))
|
||||
.chain(bounds_from_parent),
|
||||
);
|
||||
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
|
||||
debug!(
|
||||
"associated_type_bounds({}) = {:?}",
|
||||
tcx.def_path_str(assoc_item_def_id.to_def_id()),
|
||||
|
|
@ -70,7 +69,7 @@ fn opaque_type_bounds<'tcx>(
|
|||
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
item_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||
) -> &'tcx [(ty::Clause<'tcx>, Span)] {
|
||||
ty::print::with_no_queries!({
|
||||
let icx = ItemCtxt::new(tcx, opaque_def_id);
|
||||
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
|
||||
|
|
@ -78,16 +77,14 @@ fn opaque_type_bounds<'tcx>(
|
|||
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
|
||||
debug!(?bounds);
|
||||
|
||||
tcx.arena.alloc_from_iter(
|
||||
bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
|
||||
)
|
||||
tcx.arena.alloc_from_iter(bounds.clauses())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn explicit_item_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: LocalDefId,
|
||||
) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> {
|
||||
) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
|
||||
match tcx.opt_rpitit_info(def_id.to_def_id()) {
|
||||
// RPITIT's bounds are the same as opaque type bounds, but with
|
||||
// a projection self type.
|
||||
|
|
@ -139,11 +136,8 @@ pub(super) fn explicit_item_bounds(
|
|||
pub(super) fn item_bounds(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
|
||||
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
|
||||
tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
|
||||
tcx.mk_predicates_from_iter(util::elaborate(
|
||||
tcx,
|
||||
bounds.iter().map(|&(bound, _span)| bound),
|
||||
))
|
||||
tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
predicates.extend(
|
||||
icx.astconv()
|
||||
.compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
|
||||
.predicates()
|
||||
.map(|(clause, span)| (clause.to_predicate(tcx), span)),
|
||||
.clauses()
|
||||
.map(|(clause, span)| (clause.as_predicate(), span)),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -176,9 +176,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
param.span,
|
||||
);
|
||||
trace!(?bounds);
|
||||
predicates.extend(
|
||||
bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
|
||||
);
|
||||
predicates
|
||||
.extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
|
||||
trace!(?predicates);
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
|
|
@ -190,7 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
let ct = tcx.mk_const(param_const, ct_ty);
|
||||
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::Clause::ConstArgHasType(ct, ct_ty),
|
||||
ty::ClauseKind::ConstArgHasType(ct, ct_ty),
|
||||
))
|
||||
.to_predicate(tcx);
|
||||
predicates.insert((predicate, param.span));
|
||||
|
|
@ -222,7 +221,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
} else {
|
||||
let span = bound_pred.bounded_ty.span;
|
||||
let predicate = ty::Binder::bind_with_vars(
|
||||
ty::PredicateKind::Clause(ty::Clause::WellFormed(ty.into())),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())),
|
||||
bound_vars,
|
||||
);
|
||||
predicates.insert((predicate.to_predicate(tcx), span));
|
||||
|
|
@ -237,9 +236,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
bound_vars,
|
||||
OnlySelfBounds(false),
|
||||
);
|
||||
predicates.extend(
|
||||
bounds.predicates().map(|(clause, span)| (clause.to_predicate(tcx), span)),
|
||||
);
|
||||
predicates
|
||||
.extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
|
||||
}
|
||||
|
||||
hir::WherePredicate::RegionPredicate(region_pred) => {
|
||||
|
|
@ -252,7 +250,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
_ => bug!(),
|
||||
};
|
||||
let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::Clause::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
|
||||
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
|
||||
))
|
||||
.to_predicate(icx.tcx);
|
||||
|
||||
|
|
@ -320,14 +318,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
},
|
||||
);
|
||||
predicates.push((
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
ty::OutlivesPredicate(orig_region, dup_region),
|
||||
)))
|
||||
.to_predicate(icx.tcx),
|
||||
duplicate.span,
|
||||
));
|
||||
predicates.push((
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
ty::OutlivesPredicate(dup_region, orig_region),
|
||||
)))
|
||||
.to_predicate(icx.tcx),
|
||||
|
|
@ -358,8 +356,10 @@ fn const_evaluatable_predicates_of(
|
|||
if let ty::ConstKind::Unevaluated(_) = ct.kind() {
|
||||
let span = self.tcx.def_span(c.def_id);
|
||||
self.preds.insert((
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(ct)))
|
||||
.to_predicate(self.tcx),
|
||||
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(
|
||||
ct,
|
||||
)))
|
||||
.to_predicate(self.tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
|
@ -449,11 +449,13 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
.iter()
|
||||
.copied()
|
||||
.filter(|(pred, _)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(tr)) => !is_assoc_item_ty(tr.self_ty()),
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => {
|
||||
!is_assoc_item_ty(tr.self_ty())
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
|
||||
!is_assoc_item_ty(proj.projection_ty.self_ty())
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(outlives)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
|
||||
!is_assoc_item_ty(outlives.0)
|
||||
}
|
||||
_ => true,
|
||||
|
|
@ -496,7 +498,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
.predicates
|
||||
.into_iter()
|
||||
.filter(|(pred, _)| {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, _)) =
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) =
|
||||
pred.kind().skip_binder()
|
||||
{
|
||||
match ct.kind() {
|
||||
|
|
@ -665,8 +667,8 @@ pub(super) fn implied_predicates_with_filter(
|
|||
// Combine the two lists to form the complete set of superbounds:
|
||||
let implied_bounds = &*tcx.arena.alloc_from_iter(
|
||||
superbounds
|
||||
.predicates()
|
||||
.map(|(clause, span)| (clause.to_predicate(tcx), span))
|
||||
.clauses()
|
||||
.map(|(clause, span)| (clause.as_predicate(), span))
|
||||
.chain(where_bounds_that_match),
|
||||
);
|
||||
debug!(?implied_bounds);
|
||||
|
|
@ -677,7 +679,7 @@ pub(super) fn implied_predicates_with_filter(
|
|||
if matches!(filter, PredicateFilter::SelfOnly) {
|
||||
for &(pred, span) in implied_bounds {
|
||||
debug!("superbound: {:?}", pred);
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder()
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(bound)) = pred.kind().skip_binder()
|
||||
&& bound.polarity == ty::ImplPolarity::Positive
|
||||
{
|
||||
tcx.at(span).super_predicates_of(bound.def_id());
|
||||
|
|
@ -774,7 +776,9 @@ pub(super) fn type_param_predicates(
|
|||
)
|
||||
.into_iter()
|
||||
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => data.self_ty().is_param(index),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
data.self_ty().is_param(index)
|
||||
}
|
||||
_ => false,
|
||||
}),
|
||||
);
|
||||
|
|
@ -825,7 +829,7 @@ impl<'tcx> ItemCtxt<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
bounds.predicates().map(|(clause, span)| (clause.to_predicate(self.tcx), span)).collect()
|
||||
bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)).collect()
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
|
|
|
|||
|
|
@ -1761,7 +1761,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
|
||||
let bound_predicate = pred.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
|
||||
// The order here needs to match what we would get from `subst_supertrait`
|
||||
let pred_bound_vars = bound_predicate.bound_vars();
|
||||
let mut all_bound_vars = bound_vars.clone();
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ pub fn setup_constraining_predicates<'tcx>(
|
|||
for j in i..predicates.len() {
|
||||
// Note that we don't have to care about binders here,
|
||||
// as the impl trait ref never contains any late-bound regions.
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Projection(projection)) =
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) =
|
||||
predicates[j].0.kind().skip_binder()
|
||||
{
|
||||
// Special case: watch out for some kind of sneaky attempt
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
self.tcx,
|
||||
cause,
|
||||
self.param_env,
|
||||
ty::PredicateKind::Clause(ty::Clause::WellFormed(tcx_ty.into())),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(tcx_ty.into())),
|
||||
));
|
||||
|
||||
for error in ocx.select_all_or_error() {
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ fn unconstrained_parent_impl_substs<'tcx>(
|
|||
// the functions in `cgp` add the constrained parameters to a list of
|
||||
// unconstrained parameters.
|
||||
for (predicate, _) in impl_generic_predicates.predicates.iter() {
|
||||
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
|
||||
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
|
||||
predicate.kind().skip_binder()
|
||||
{
|
||||
let projection_ty = proj.projection_ty;
|
||||
|
|
@ -438,8 +438,8 @@ fn trait_predicates_eq<'tcx>(
|
|||
let pred2_kind = predicate2.kind().skip_binder();
|
||||
let (trait_pred1, trait_pred2) = match (pred1_kind, pred2_kind) {
|
||||
(
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred1)),
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(pred2)),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred1)),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred2)),
|
||||
) => (pred1, pred2),
|
||||
// Just use plain syntactic equivalence if either of the predicates aren't
|
||||
// trait predicates or have bound vars.
|
||||
|
|
@ -478,7 +478,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
|||
_ if predicate.is_global() => (),
|
||||
// We allow specializing on explicitly marked traits with no associated
|
||||
// items.
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
polarity: _,
|
||||
|
|
@ -498,7 +498,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
|||
.emit();
|
||||
}
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
|
||||
projection_ty,
|
||||
term,
|
||||
})) => {
|
||||
|
|
@ -509,7 +509,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => {
|
||||
// FIXME(min_specialization), FIXME(const_generics):
|
||||
// It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
|
||||
// about the actual rules that would be sound. Can't just always error here because otherwise
|
||||
|
|
@ -532,22 +532,22 @@ fn trait_predicate_kind<'tcx>(
|
|||
predicate: ty::Predicate<'tcx>,
|
||||
) -> Option<TraitSpecializationKind> {
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
constness: _,
|
||||
polarity: _,
|
||||
})) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(_))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::WellFormed(_))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
// process predicates and convert to `RequiredPredicates` entry, see below
|
||||
for &(predicate, span) in predicates.predicates {
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::Clause::TypeOutlives(OutlivesPredicate(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(OutlivesPredicate(
|
||||
ty,
|
||||
reg,
|
||||
))) => insert_outlives_predicate(
|
||||
|
|
@ -41,10 +41,9 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
&mut required_predicates,
|
||||
),
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(OutlivesPredicate(
|
||||
reg1,
|
||||
reg2,
|
||||
))) => insert_outlives_predicate(
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
|
||||
OutlivesPredicate(reg1, reg2),
|
||||
)) => insert_outlives_predicate(
|
||||
tcx,
|
||||
reg1.into(),
|
||||
reg2,
|
||||
|
|
@ -52,16 +51,16 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
&mut required_predicates,
|
||||
),
|
||||
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
|
||||
| ty::PredicateKind::Clause(ty::Clause::WellFormed(..))
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
|
||||
| ty::PredicateKind::AliasRelate(..)
|
||||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::Clause(ty::Clause::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::Ambiguous
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue