Merge pull request #4402 from rust-lang/rustup-2025-06-17
Automatic Rustup
This commit is contained in:
commit
7dfa752e27
293 changed files with 4630 additions and 1761 deletions
7
.mailmap
7
.mailmap
|
|
@ -34,10 +34,13 @@ Alona Enraght-Moony <code@alona.page> <nixon@caminus.local>
|
|||
Alona Enraght-Moony <code@alona.page> <contact@alona.page>
|
||||
Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com>
|
||||
Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se>
|
||||
Amanieu d'Antras <amanieu@gmail.com> <amanieu.dantras@huawei.com>
|
||||
Amos Onn <amosonn@gmail.com>
|
||||
Ana-Maria Mihalache <mihalacheana.maria@yahoo.com>
|
||||
Anatoly Ikorsky <aikorsky@gmail.com>
|
||||
Andre Bogus <bogusandre@gmail.com>
|
||||
Andre Bogus <bogusandre@gmail.com> <andre.bogus@aleph-alpha.de>
|
||||
Andre Bogus <bogusandre@gmail.com> <andre.bogus@ankordata.de>
|
||||
Andrea Ciliberti <meziu210@icloud.com>
|
||||
Andreas Gal <gal@mozilla.com> <andreas.gal@gmail.com>
|
||||
Andreas Jonson <andjo403@users.noreply.github.com>
|
||||
|
|
@ -116,6 +119,7 @@ Carol Willing <carolcode@willingconsulting.com>
|
|||
Chandler Deng <chandde@microsoft.com>
|
||||
Charles Lew <crlf0710@gmail.com> CrLF0710 <crlf0710@gmail.com>
|
||||
Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com>
|
||||
Chris Denton <chris@chrisdenton.dev> <christophersdenton@gmail.com>
|
||||
Chris Denton <chris@chrisdenton.dev> Chris Denton <ChrisDenton@users.noreply.github.com>
|
||||
Chris Gregory <czipperz@gmail.com>
|
||||
Chris Pardy <chrispardy36@gmail.com>
|
||||
|
|
@ -403,6 +407,8 @@ Urgau <urgau@numericable.fr> <3616612+Urgau@users.noreply.github.com>
|
|||
Lucy <luxx4x@protonmail.com>
|
||||
Lukas H. <lukaramu@users.noreply.github.com>
|
||||
Lukas Lueg <lukas.lueg@gmail.com>
|
||||
Lukas Wirth <lukastw97@gmail.com> <lukas.wirth@ferrous-systems.com>
|
||||
Lukas Wirth <lukastw97@gmail.com> <me@lukaswirth.dev>
|
||||
Luke Metz <luke.metz@students.olin.edu>
|
||||
Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
|
||||
Luqman Aden <me@luqman.ca> <laden@mozilla.com>
|
||||
|
|
@ -493,6 +499,7 @@ Nicolas Abram <abramlujan@gmail.com>
|
|||
Nicole Mazzuca <npmazzuca@gmail.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu>
|
||||
Niko Matsakis <rust@nikomatsakis.com> <nikomat@amazon.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
|
||||
|
|
|
|||
|
|
@ -1450,11 +1450,20 @@ impl Expr {
|
|||
}
|
||||
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
fn prefix_attrs_precedence(attrs: &AttrVec) -> ExprPrecedence {
|
||||
for attr in attrs {
|
||||
if let AttrStyle::Outer = attr.style {
|
||||
return ExprPrecedence::Prefix;
|
||||
}
|
||||
}
|
||||
ExprPrecedence::Unambiguous
|
||||
}
|
||||
|
||||
match &self.kind {
|
||||
ExprKind::Closure(closure) => {
|
||||
match closure.fn_decl.output {
|
||||
FnRetTy::Default(_) => ExprPrecedence::Jump,
|
||||
FnRetTy::Ty(_) => ExprPrecedence::Unambiguous,
|
||||
FnRetTy::Ty(_) => prefix_attrs_precedence(&self.attrs),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1463,7 +1472,7 @@ impl Expr {
|
|||
| ExprKind::Yield(YieldKind::Prefix(value))
|
||||
| ExprKind::Yeet(value) => match value {
|
||||
Some(_) => ExprPrecedence::Jump,
|
||||
None => ExprPrecedence::Unambiguous,
|
||||
None => prefix_attrs_precedence(&self.attrs),
|
||||
},
|
||||
|
||||
ExprKind::Become(_) => ExprPrecedence::Jump,
|
||||
|
|
@ -1490,7 +1499,7 @@ impl Expr {
|
|||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
// Need parens if and only if there are prefix attributes.
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Await(..)
|
||||
| ExprKind::Use(..)
|
||||
|
|
@ -1525,7 +1534,7 @@ impl Expr {
|
|||
| ExprKind::While(..)
|
||||
| ExprKind::Yield(YieldKind::Postfix(..))
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
| ExprKind::Dummy => prefix_attrs_precedence(&self.attrs),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1700,7 +1700,8 @@ fn visit_nested_use_tree<'a, V: Visitor<'a>>(
|
|||
}
|
||||
|
||||
pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
|
||||
let Stmt { id: _, kind, span: _ } = statement;
|
||||
let Stmt { id, kind, span: _ } = statement;
|
||||
try_visit!(visit_id(visitor, id));
|
||||
match kind {
|
||||
StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
|
||||
StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span,
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -599,6 +600,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span,
|
||||
span: this.lower_span(use_tree.span),
|
||||
has_delayed_lints: !this.delayed_lints.is_empty(),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(item))
|
||||
});
|
||||
|
|
@ -697,6 +699,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span: self.lower_span(i.vis.span),
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -941,6 +944,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
span: self.lower_span(i.span),
|
||||
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -1100,6 +1104,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
vis_span: self.lower_span(i.vis.span),
|
||||
span: self.lower_span(i.span),
|
||||
defaultness,
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,24 +130,54 @@ impl Deprecation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represent parsed, *built in*, inert attributes.
|
||||
/// Represents parsed *built-in* inert attributes.
|
||||
///
|
||||
/// That means attributes that are not actually ever expanded.
|
||||
/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate.
|
||||
/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler.
|
||||
/// These are kept around after the AST, into the HIR and further on.
|
||||
/// ## Overview
|
||||
/// These attributes are markers that guide the compilation process and are never expanded into other code.
|
||||
/// They persist throughout the compilation phases, from AST to HIR and beyond.
|
||||
///
|
||||
/// The word "parsed" could be a little misleading here, because the parser already parses
|
||||
/// attributes early on. However, the result, an [`ast::Attribute`]
|
||||
/// is only parsed at a high level, still containing a token stream in many cases. That is
|
||||
/// because the structure of the contents varies from attribute to attribute.
|
||||
/// With a parsed attribute I mean that each attribute is processed individually into a
|
||||
/// final structure, which on-site (the place where the attribute is useful for, think the
|
||||
/// the place where `must_use` is checked) little to no extra parsing or validating needs to
|
||||
/// happen.
|
||||
/// ## Attribute Processing
|
||||
/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams
|
||||
/// because different attributes have different internal structures. This enum represents the final,
|
||||
/// fully parsed form of these attributes, where each variant contains contains all the information and
|
||||
/// structure relevant for the specific attribute.
|
||||
///
|
||||
/// For more docs, look in [`rustc_attr_parsing`].
|
||||
/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single
|
||||
/// semantic attribute. For example:
|
||||
/// ```rust
|
||||
/// #[repr(C)]
|
||||
/// #[repr(packed)]
|
||||
/// struct S { }
|
||||
/// ```
|
||||
/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing
|
||||
/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the
|
||||
/// data structures defined in this enum.
|
||||
///
|
||||
/// ## Usage
|
||||
/// These parsed attributes are used throughout the compiler to:
|
||||
/// - Control code generation (e.g., `#[repr]`)
|
||||
/// - Mark API stability (`#[stable]`, `#[unstable]`)
|
||||
/// - Provide documentation (`#[doc]`)
|
||||
/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`)
|
||||
///
|
||||
/// ## Note on Attribute Organization
|
||||
/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately
|
||||
/// from this enum because they are used in specific compiler phases (like code generation) and don't
|
||||
/// need to persist throughout the entire compilation process. They are typically processed and
|
||||
/// converted into their final form earlier in the compilation pipeline.
|
||||
///
|
||||
/// For example:
|
||||
/// - `InlineAttr` is used during code generation to control function inlining
|
||||
/// - `OptimizeAttr` is used to control optimization levels
|
||||
/// - `InstructionSetAttr` is used for target-specific code generation
|
||||
///
|
||||
/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate
|
||||
/// and don't need to be preserved in the same way as the attributes in this enum.
|
||||
///
|
||||
/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate.
|
||||
///
|
||||
/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html
|
||||
/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html
|
||||
/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
|
||||
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum AttributeKind {
|
||||
|
|
@ -158,6 +188,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[allow_internal_unstable]`.
|
||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
|
||||
|
||||
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
|
||||
AsPtr(Span),
|
||||
|
||||
/// Represents `#[rustc_default_body_unstable]`.
|
||||
BodyStability {
|
||||
stability: DefaultBodyStability,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
//! Data structures for representing parsed attributes in the Rust compiler.
|
||||
//! For detailed documentation about attribute processing,
|
||||
//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html).
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
|
|
|
|||
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct AsPtrParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
// FIXME: check that there's no args (this is currently checked elsewhere)
|
||||
Some(AttributeKind::AsPtr(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ pub(crate) mod allow_unstable;
|
|||
pub(crate) mod cfg;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod stability;
|
||||
pub(crate) mod transparency;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
|||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::lint_helpers::AsPtrParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
|
|
@ -102,6 +103,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Single<AsPtrParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<TransparencyParser>,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||
};
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
type BorrowsDomain = DenseBitSet<BorrowIndex>;
|
||||
type BorrowsDomain = MixedBitSet<BorrowIndex>;
|
||||
|
||||
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
|
||||
/// - we gen the introduced loans
|
||||
|
|
@ -564,7 +564,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
|
||||
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
|
||||
// bottom = nothing is reserved or activated yet;
|
||||
DenseBitSet::new_empty(self.borrow_set.len())
|
||||
MixedBitSet::new_empty(self.borrow_set.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
|
||||
|
|
|
|||
|
|
@ -342,6 +342,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
let sp = info
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(local_decl.source_info.span)
|
||||
.unwrap_or(info.span);
|
||||
if info.tail_result_is_ignored {
|
||||
// #85581: If the first mutable borrow's scope contains
|
||||
// the second borrow, this suggestion isn't helpful.
|
||||
|
|
@ -349,7 +353,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
old.to(info.span.shrink_to_hi()).contains(new)
|
||||
}) {
|
||||
err.span_suggestion_verbose(
|
||||
info.span.shrink_to_hi(),
|
||||
sp.shrink_to_hi(),
|
||||
"consider adding semicolon after the expression so its \
|
||||
temporaries are dropped sooner, before the local variables \
|
||||
declared by the block are dropped",
|
||||
|
|
@ -368,8 +372,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
local variable `x` and then make `x` be the expression at the \
|
||||
end of the block",
|
||||
vec![
|
||||
(info.span.shrink_to_lo(), "let x = ".to_string()),
|
||||
(info.span.shrink_to_hi(), "; x".to_string()),
|
||||
(sp.shrink_to_lo(), "let x = ".to_string()),
|
||||
(sp.shrink_to_hi(), "; x".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_errors::LintDiagnostic;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_index::bit_set::MixedBitSet;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
|
|
@ -1151,11 +1151,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&self,
|
||||
location: Location,
|
||||
state: &'s BorrowckDomain,
|
||||
) -> Cow<'s, DenseBitSet<BorrowIndex>> {
|
||||
) -> Cow<'s, MixedBitSet<BorrowIndex>> {
|
||||
if let Some(polonius) = &self.polonius_output {
|
||||
// Use polonius output if it has been enabled.
|
||||
let location = self.location_table.start_index(location);
|
||||
let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
|
||||
let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,10 +118,7 @@ pub(crate) fn expand_test_or_bench(
|
|||
|
||||
let (item, is_stmt) = match item {
|
||||
Annotatable::Item(i) => (i, false),
|
||||
Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
|
||||
// FIXME: Use an 'if let' guard once they are implemented
|
||||
if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() }
|
||||
}
|
||||
Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true),
|
||||
other => {
|
||||
not_testable_error(cx, attr_sp, None);
|
||||
return vec![other];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Argument passing
|
||||
|
||||
use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
|
||||
use cranelift_codegen::ir::ArgumentPurpose;
|
||||
use rustc_abi::{Reg, RegKind};
|
||||
use rustc_target::callconv::{
|
||||
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
|
||||
|
|
@ -32,16 +32,26 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
|
|||
AbiParam::new(clif_ty)
|
||||
}
|
||||
|
||||
fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
|
||||
fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
|
||||
match arg_attrs.arg_ext {
|
||||
RustcArgExtension::None => {}
|
||||
RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext,
|
||||
RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext,
|
||||
RustcArgExtension::None => param,
|
||||
RustcArgExtension::Zext => param.uext(),
|
||||
RustcArgExtension::Sext => param.sext(),
|
||||
}
|
||||
param
|
||||
}
|
||||
|
||||
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
||||
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> {
|
||||
if let Some(offset_from_start) = cast.rest_offset {
|
||||
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||
let first = cast.prefix[0].unwrap();
|
||||
let second = cast.rest.unit;
|
||||
return smallvec![
|
||||
(Size::ZERO, reg_to_abi_param(first)),
|
||||
(offset_from_start, reg_to_abi_param(second))
|
||||
];
|
||||
}
|
||||
|
||||
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
|
||||
(0, 0)
|
||||
} else {
|
||||
|
|
@ -56,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
|||
// different types in Cranelift IR. Instead a single array of primitive types is used.
|
||||
|
||||
// Create list of fields in the main structure
|
||||
let mut args = cast
|
||||
let args = cast
|
||||
.prefix
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|®| reg_to_abi_param(reg))
|
||||
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
|
||||
.collect::<SmallVec<_>>();
|
||||
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)));
|
||||
|
||||
let mut res = SmallVec::new();
|
||||
let mut offset = Size::ZERO;
|
||||
|
||||
for arg in args {
|
||||
res.push((offset, arg));
|
||||
offset += Size::from_bytes(arg.value_type.bytes());
|
||||
}
|
||||
|
||||
// Append final integer
|
||||
if rem_bytes != 0 {
|
||||
// Only integers can be really split further.
|
||||
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
|
||||
args.push(reg_to_abi_param(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: Size::from_bytes(rem_bytes),
|
||||
}));
|
||||
res.push((
|
||||
offset,
|
||||
reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
|
||||
));
|
||||
}
|
||||
|
||||
args
|
||||
res
|
||||
}
|
||||
|
||||
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
|
|
@ -82,7 +99,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
match self.mode {
|
||||
PassMode::Ignore => smallvec![],
|
||||
PassMode::Direct(attrs) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param(
|
||||
BackendRepr::Scalar(scalar) => smallvec![apply_attrs_to_abi_param(
|
||||
AbiParam::new(scalar_to_clif_type(tcx, scalar)),
|
||||
attrs
|
||||
)],
|
||||
|
|
@ -97,34 +114,34 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
let a = scalar_to_clif_type(tcx, a);
|
||||
let b = scalar_to_clif_type(tcx, b);
|
||||
smallvec![
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
]
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Cast { ref cast, pad_i32 } => {
|
||||
assert!(!pad_i32, "padding support not yet implemented");
|
||||
cast_target_to_abi_params(cast)
|
||||
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||
if on_stack {
|
||||
// Abi requires aligning struct size to pointer size
|
||||
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
|
||||
let size = u32::try_from(size.bytes()).unwrap();
|
||||
smallvec![apply_arg_attrs_to_abi_param(
|
||||
smallvec![apply_attrs_to_abi_param(
|
||||
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
|
||||
attrs
|
||||
)]
|
||||
} else {
|
||||
smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
|
||||
smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
|
||||
}
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
smallvec![
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
|
||||
apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
||||
apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -133,30 +150,47 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
|
||||
match self.mode {
|
||||
PassMode::Ignore => (None, vec![]),
|
||||
PassMode::Direct(_) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => {
|
||||
(None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
|
||||
}
|
||||
PassMode::Direct(attrs) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => (
|
||||
None,
|
||||
vec![apply_attrs_to_abi_param(
|
||||
AbiParam::new(scalar_to_clif_type(tcx, scalar)),
|
||||
attrs,
|
||||
)],
|
||||
),
|
||||
BackendRepr::SimdVector { .. } => {
|
||||
let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
|
||||
(None, vec![AbiParam::new(vector_ty)])
|
||||
(None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)])
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Pair(_, _) => match self.layout.backend_repr {
|
||||
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
|
||||
BackendRepr::ScalarPair(a, b) => {
|
||||
let a = scalar_to_clif_type(tcx, a);
|
||||
let b = scalar_to_clif_type(tcx, b);
|
||||
(None, vec![AbiParam::new(a), AbiParam::new(b)])
|
||||
(
|
||||
None,
|
||||
vec![
|
||||
apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
],
|
||||
)
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
(None, cast_target_to_abi_params(cast).into_iter().collect())
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
|
||||
PassMode::Cast { ref cast, .. } => (
|
||||
None,
|
||||
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
|
||||
),
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
|
||||
(
|
||||
Some(apply_attrs_to_abi_param(
|
||||
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn),
|
||||
attrs,
|
||||
)),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
|
|
@ -172,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>(
|
|||
) -> SmallVec<[Value; 2]> {
|
||||
let (ptr, meta) = arg.force_stack(fx);
|
||||
assert!(meta.is_none());
|
||||
let mut offset = 0;
|
||||
cast_target_to_abi_params(cast)
|
||||
.into_iter()
|
||||
.map(|param| {
|
||||
let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new());
|
||||
offset += i64::from(param.value_type.bytes());
|
||||
.map(|(offset, param)| {
|
||||
let val = ptr.offset_i64(fx, offset.bytes() as i64).load(
|
||||
fx,
|
||||
param.value_type,
|
||||
MemFlags::new(),
|
||||
);
|
||||
val
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -190,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>(
|
|||
cast: &CastTarget,
|
||||
) -> CValue<'tcx> {
|
||||
let abi_params = cast_target_to_abi_params(cast);
|
||||
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
|
||||
let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
|
||||
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
|
||||
let ptr = fx.create_stack_slot(
|
||||
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
|
||||
|
|
@ -199,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>(
|
|||
std::cmp::max(abi_param_size, layout_size),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
);
|
||||
let mut offset = 0;
|
||||
let mut block_params_iter = block_params.iter().copied();
|
||||
for param in abi_params {
|
||||
let val = ptr.offset_i64(fx, offset).store(
|
||||
for (offset, _) in abi_params {
|
||||
ptr.offset_i64(fx, offset.bytes() as i64).store(
|
||||
fx,
|
||||
block_params_iter.next().unwrap(),
|
||||
MemFlags::new(),
|
||||
);
|
||||
offset += i64::from(param.value_type.bytes());
|
||||
val
|
||||
)
|
||||
}
|
||||
assert_eq!(block_params_iter.next(), None, "Leftover block param");
|
||||
CValue::by_ref(ptr, layout)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use std::thread::JoinHandle;
|
|||
use cranelift_object::{ObjectBuilder, ObjectModule};
|
||||
use rustc_codegen_ssa::assert_module_sources::CguReuse;
|
||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
|
||||
use rustc_codegen_ssa::base::determine_cgu_reuse;
|
||||
use rustc_codegen_ssa::{
|
||||
CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors,
|
||||
|
|
@ -19,7 +18,6 @@ use rustc_codegen_ssa::{
|
|||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
|
|
@ -61,8 +59,6 @@ impl<HCX> HashStable<HCX> for OngoingModuleCodegen {
|
|||
pub(crate) struct OngoingCodegen {
|
||||
modules: Vec<OngoingModuleCodegen>,
|
||||
allocator_module: Option<CompiledModule>,
|
||||
metadata_module: Option<CompiledModule>,
|
||||
metadata: EncodedMetadata,
|
||||
crate_info: CrateInfo,
|
||||
concurrency_limiter: ConcurrencyLimiter,
|
||||
}
|
||||
|
|
@ -134,8 +130,6 @@ impl OngoingCodegen {
|
|||
let codegen_results = CodegenResults {
|
||||
modules,
|
||||
allocator_module: self.allocator_module,
|
||||
metadata_module: self.metadata_module,
|
||||
metadata: self.metadata,
|
||||
crate_info: self.crate_info,
|
||||
};
|
||||
|
||||
|
|
@ -646,42 +640,6 @@ fn module_codegen(
|
|||
}))
|
||||
}
|
||||
|
||||
fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule {
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
|
||||
let _timer = tcx.sess.timer("write compressed metadata");
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let metadata_cgu_name = cgu_name_builder
|
||||
.build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata"))
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let tmp_file = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Metadata,
|
||||
&metadata_cgu_name,
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
|
||||
let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
|
||||
let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name);
|
||||
|
||||
if let Err(err) = std::fs::write(&tmp_file, obj) {
|
||||
tcx.dcx().fatal(format!("error writing metadata object file: {}", err));
|
||||
}
|
||||
|
||||
CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(tmp_file),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
links_from_incr_cache: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
||||
let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string());
|
||||
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
|
||||
|
|
@ -706,11 +664,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_aot(
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<OngoingCodegen> {
|
||||
pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box<OngoingCodegen> {
|
||||
// FIXME handle `-Ctarget-cpu=native`
|
||||
let target_cpu = match tcx.sess.opts.cg.target_cpu {
|
||||
Some(ref name) => name,
|
||||
|
|
@ -726,8 +680,6 @@ pub(crate) fn run_aot(
|
|||
return Box::new(OngoingCodegen {
|
||||
modules: vec![],
|
||||
allocator_module: None,
|
||||
metadata_module: None,
|
||||
metadata,
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
concurrency_limiter: ConcurrencyLimiter::new(0),
|
||||
});
|
||||
|
|
@ -787,14 +739,9 @@ pub(crate) fn run_aot(
|
|||
|
||||
let allocator_module = emit_allocator_module(tcx);
|
||||
|
||||
let metadata_module =
|
||||
if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None };
|
||||
|
||||
Box::new(OngoingCodegen {
|
||||
modules,
|
||||
allocator_module,
|
||||
metadata_module,
|
||||
metadata,
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
concurrency_limiter: concurrency_limiter.0,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ use cranelift_codegen::isa::TargetIsa;
|
|||
use cranelift_codegen::settings::{self, Configurable};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, TargetConfig};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::OutputFilenames;
|
||||
|
|
@ -238,12 +237,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
println!("Cranelift version: {}", cranelift_codegen::VERSION);
|
||||
}
|
||||
|
||||
fn codegen_crate(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> {
|
||||
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
|
||||
let config = self.config.clone().unwrap_or_else(|| {
|
||||
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
|
||||
|
|
@ -256,7 +250,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
#[cfg(not(feature = "jit"))]
|
||||
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
|
||||
} else {
|
||||
driver::aot::run_aot(tcx, metadata, need_metadata_module)
|
||||
driver::aot::run_aot(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
|
||||
|
||||
use crate::common::{SignType, TypeReflection, type_is_pointer};
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -2394,12 +2394,6 @@ impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.cx.wasm_c_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
self.cx.x86_abi_opt()
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
|
|||
use rustc_session::Session;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::spec::{
|
||||
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
|
||||
};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use crate::abi::conv_to_fn_attribute;
|
||||
|
|
@ -512,12 +510,6 @@ impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.tcx.sess.opts.unstable_opts.wasm_c_abi
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi {
|
||||
|
|
|
|||
|
|
@ -626,7 +626,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
bx.lifetime_start(llscratch, scratch_size);
|
||||
|
||||
// ... where we first store the value...
|
||||
bx.store(val, llscratch, scratch_align);
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||
|
||||
// ... and then memcpy it to the intended destination.
|
||||
bx.memcpy(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ extern crate rustc_index;
|
|||
#[cfg(feature = "master")]
|
||||
extern crate rustc_interface;
|
||||
extern crate rustc_macros;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
|
@ -106,7 +105,6 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetCon
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
|
|
@ -230,20 +228,9 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
|
||||
}
|
||||
|
||||
fn codegen_crate(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> {
|
||||
let target_cpu = target_cpu(tcx.sess);
|
||||
let res = codegen_crate(
|
||||
self.clone(),
|
||||
tcx,
|
||||
target_cpu.to_string(),
|
||||
metadata,
|
||||
need_metadata_module,
|
||||
);
|
||||
let res = codegen_crate(self.clone(), tcx, target_cpu.to_string());
|
||||
|
||||
Box::new(res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
let llscratch = bx.alloca(scratch_size, scratch_align);
|
||||
bx.lifetime_start(llscratch, scratch_size);
|
||||
// ...store the value...
|
||||
bx.store(val, llscratch, scratch_align);
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||
// ... and then memcpy it to the intended destination.
|
||||
bx.memcpy(
|
||||
dst.val.llval,
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,15 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
bx.bitcast(value, bx.type_vector(bx.type_i16(), count))
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
// Smaller floats are always "NaN-boxed" inside larger floats on LoongArch.
|
||||
let value = bx.bitcast(value, bx.type_i16());
|
||||
let value = bx.zext(value, bx.type_i32());
|
||||
let value = bx.or(value, bx.const_u32(0xFFFF_0000));
|
||||
bx.bitcast(value, bx.type_f32())
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
@ -1178,6 +1187,13 @@ fn llvm_fixup_output<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
bx.bitcast(value, bx.type_vector(bx.type_f16(), count))
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
let value = bx.bitcast(value, bx.type_i32());
|
||||
let value = bx.trunc(value, bx.type_i16());
|
||||
bx.bitcast(value, bx.type_f16())
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
@ -1318,6 +1334,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
cx.type_vector(cx.type_i16(), count)
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
cx.type_f32()
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
|
||||
let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' });
|
||||
|
||||
let res = self.call_intrinsic(&name, &[self.type_ix(width)], &[lhs, rhs]);
|
||||
let res = self.call_intrinsic(name, &[self.type_ix(width)], &[lhs, rhs]);
|
||||
(self.extract_value(res, 0), self.extract_value(res, 1))
|
||||
}
|
||||
|
||||
|
|
@ -1038,7 +1038,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
let size = ty.primitive_size(self.tcx);
|
||||
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
|
||||
|
||||
Some(self.call_intrinsic(&name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
|
||||
Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
|
||||
}
|
||||
|
||||
/* Miscellaneous instructions */
|
||||
|
|
@ -1393,7 +1393,8 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
|
|||
// Forward to the `get_static` method of `CodegenCx`
|
||||
let global = self.cx().get_static(def_id);
|
||||
if self.cx().tcx.is_thread_local_static(def_id) {
|
||||
let pointer = self.call_intrinsic("llvm.threadlocal.address", &[], &[global]);
|
||||
let pointer =
|
||||
self.call_intrinsic("llvm.threadlocal.address", &[self.val_ty(global)], &[global]);
|
||||
// Cast to default address space if globals are in a different addrspace
|
||||
self.pointercast(pointer, self.type_ptr())
|
||||
} else {
|
||||
|
|
@ -1590,15 +1591,15 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
pub(crate) fn call_intrinsic(
|
||||
&mut self,
|
||||
base_name: &str,
|
||||
base_name: impl Into<Cow<'static, str>>,
|
||||
type_params: &[&'ll Type],
|
||||
args: &[&'ll Value],
|
||||
) -> &'ll Value {
|
||||
let (ty, f) = self.cx.get_intrinsic(base_name, type_params);
|
||||
let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params);
|
||||
self.call(ty, None, None, f, args, None, None)
|
||||
}
|
||||
|
||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) {
|
||||
let size = size.bytes();
|
||||
if size == 0 {
|
||||
return;
|
||||
|
|
@ -1608,7 +1609,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.call_intrinsic(intrinsic, &[self.type_ptr()], &[self.cx.const_u64(size), ptr]);
|
||||
self.call_intrinsic(intrinsic, &[self.val_ty(ptr)], &[self.cx.const_u64(size), ptr]);
|
||||
}
|
||||
}
|
||||
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ffi::{CStr, c_char, c_uint};
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -138,7 +138,7 @@ pub(crate) struct FullCx<'ll, 'tcx> {
|
|||
pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>,
|
||||
|
||||
intrinsics:
|
||||
RefCell<FxHashMap<(&'static str, SmallVec<[&'ll Type; 2]>), (&'ll Type, &'ll Value)>>,
|
||||
RefCell<FxHashMap<(Cow<'static, str>, SmallVec<[&'ll Type; 2]>), (&'ll Type, &'ll Value)>>,
|
||||
|
||||
/// A counter that is used for generating local symbol names
|
||||
local_gen_sym_counter: Cell<usize>,
|
||||
|
|
@ -845,45 +845,16 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
impl<'ll> CodegenCx<'ll, '_> {
|
||||
pub(crate) fn get_intrinsic(
|
||||
&self,
|
||||
base_name: &str,
|
||||
base_name: Cow<'static, str>,
|
||||
type_params: &[&'ll Type],
|
||||
) -> (&'ll Type, &'ll Value) {
|
||||
if let Some(v) =
|
||||
self.intrinsics.borrow().get(&(base_name, SmallVec::from_slice(type_params)))
|
||||
{
|
||||
return *v;
|
||||
}
|
||||
|
||||
self.declare_intrinsic(base_name, type_params)
|
||||
}
|
||||
|
||||
fn insert_intrinsic(
|
||||
&self,
|
||||
base_name: &'static str,
|
||||
type_params: &[&'ll Type],
|
||||
args: Option<&[&'ll llvm::Type]>,
|
||||
ret: &'ll llvm::Type,
|
||||
) -> (&'ll llvm::Type, &'ll llvm::Value) {
|
||||
let fn_ty = if let Some(args) = args {
|
||||
self.type_func(args, ret)
|
||||
} else {
|
||||
self.type_variadic_func(&[], ret)
|
||||
};
|
||||
|
||||
let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes())
|
||||
.expect("Unknown LLVM intrinsic `{base_name}`");
|
||||
|
||||
let full_name = if intrinsic.is_overloaded() {
|
||||
&intrinsic.overloaded_name(self.llmod, type_params)
|
||||
} else {
|
||||
base_name
|
||||
};
|
||||
|
||||
let f = self.declare_cfn(full_name, llvm::UnnamedAddr::No, fn_ty);
|
||||
self.intrinsics
|
||||
*self
|
||||
.intrinsics
|
||||
.borrow_mut()
|
||||
.insert((base_name, SmallVec::from_slice(type_params)), (fn_ty, f));
|
||||
(fn_ty, f)
|
||||
.entry((base_name, SmallVec::from_slice(type_params)))
|
||||
.or_insert_with_key(|(base_name, type_params)| {
|
||||
self.declare_intrinsic(base_name, type_params)
|
||||
})
|
||||
}
|
||||
|
||||
fn declare_intrinsic(
|
||||
|
|
@ -891,155 +862,22 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
base_name: &str,
|
||||
type_params: &[&'ll Type],
|
||||
) -> (&'ll Type, &'ll Value) {
|
||||
macro_rules! param {
|
||||
($index:literal) => {
|
||||
type_params[$index]
|
||||
};
|
||||
($other:expr) => {
|
||||
$other
|
||||
};
|
||||
}
|
||||
macro_rules! ifn {
|
||||
($name:expr, fn(...) -> $ret:expr) => (
|
||||
if base_name == $name {
|
||||
return self.insert_intrinsic($name, type_params, None, param!($ret));
|
||||
}
|
||||
);
|
||||
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
|
||||
if base_name == $name {
|
||||
return self.insert_intrinsic($name, type_params, Some(&[$(param!($arg)),*]), param!($ret));
|
||||
}
|
||||
);
|
||||
}
|
||||
macro_rules! mk_struct {
|
||||
($($field_ty:expr),*) => (self.type_struct( &[$(param!($field_ty)),*], false))
|
||||
}
|
||||
|
||||
let same_width_vector = |index, element_ty| {
|
||||
self.type_vector(element_ty, self.vector_length(type_params[index]) as u64)
|
||||
};
|
||||
|
||||
let ptr = self.type_ptr();
|
||||
let void = self.type_void();
|
||||
let i1 = self.type_i1();
|
||||
let t_i32 = self.type_i32();
|
||||
let t_i64 = self.type_i64();
|
||||
let t_isize = self.type_isize();
|
||||
let t_metadata = self.type_metadata();
|
||||
let t_token = self.type_token();
|
||||
|
||||
ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr);
|
||||
ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32);
|
||||
|
||||
ifn!("llvm.wasm.trunc.unsigned", fn(1) -> 0);
|
||||
ifn!("llvm.wasm.trunc.signed", fn(1) -> 0);
|
||||
ifn!("llvm.fptosi.sat", fn(1) -> 0);
|
||||
ifn!("llvm.fptoui.sat", fn(1) -> 0);
|
||||
|
||||
ifn!("llvm.trap", fn() -> void);
|
||||
ifn!("llvm.debugtrap", fn() -> void);
|
||||
ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
|
||||
|
||||
ifn!("llvm.powi", fn(0, 1) -> 0);
|
||||
ifn!("llvm.pow", fn(0, 0) -> 0);
|
||||
ifn!("llvm.sqrt", fn(0) -> 0);
|
||||
ifn!("llvm.sin", fn(0) -> 0);
|
||||
ifn!("llvm.cos", fn(0) -> 0);
|
||||
ifn!("llvm.exp", fn(0) -> 0);
|
||||
ifn!("llvm.exp2", fn(0) -> 0);
|
||||
ifn!("llvm.log", fn(0) -> 0);
|
||||
ifn!("llvm.log10", fn(0) -> 0);
|
||||
ifn!("llvm.log2", fn(0) -> 0);
|
||||
ifn!("llvm.fma", fn(0, 0, 0) -> 0);
|
||||
ifn!("llvm.fmuladd", fn(0, 0, 0) -> 0);
|
||||
ifn!("llvm.fabs", fn(0) -> 0);
|
||||
ifn!("llvm.minnum", fn(0, 0) -> 0);
|
||||
ifn!("llvm.minimum", fn(0, 0) -> 0);
|
||||
ifn!("llvm.maxnum", fn(0, 0) -> 0);
|
||||
ifn!("llvm.maximum", fn(0, 0) -> 0);
|
||||
ifn!("llvm.floor", fn(0) -> 0);
|
||||
ifn!("llvm.ceil", fn(0) -> 0);
|
||||
ifn!("llvm.trunc", fn(0) -> 0);
|
||||
ifn!("llvm.copysign", fn(0, 0) -> 0);
|
||||
ifn!("llvm.round", fn(0) -> 0);
|
||||
ifn!("llvm.rint", fn(0) -> 0);
|
||||
ifn!("llvm.nearbyint", fn(0) -> 0);
|
||||
|
||||
ifn!("llvm.ctpop", fn(0) -> 0);
|
||||
ifn!("llvm.ctlz", fn(0, i1) -> 0);
|
||||
ifn!("llvm.cttz", fn(0, i1) -> 0);
|
||||
ifn!("llvm.bswap", fn(0) -> 0);
|
||||
ifn!("llvm.bitreverse", fn(0) -> 0);
|
||||
ifn!("llvm.fshl", fn(0, 0, 0) -> 0);
|
||||
ifn!("llvm.fshr", fn(0, 0, 0) -> 0);
|
||||
|
||||
ifn!("llvm.sadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
ifn!("llvm.uadd.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
ifn!("llvm.ssub.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
ifn!("llvm.usub.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
ifn!("llvm.smul.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
ifn!("llvm.umul.with.overflow", fn(0, 0) -> mk_struct! {0, i1});
|
||||
|
||||
ifn!("llvm.sadd.sat", fn(0, 0) -> 0);
|
||||
ifn!("llvm.uadd.sat", fn(0, 0) -> 0);
|
||||
ifn!("llvm.ssub.sat", fn(0, 0) -> 0);
|
||||
ifn!("llvm.usub.sat", fn(0, 0) -> 0);
|
||||
|
||||
ifn!("llvm.scmp", fn(1, 1) -> 0);
|
||||
ifn!("llvm.ucmp", fn(1, 1) -> 0);
|
||||
|
||||
ifn!("llvm.lifetime.start", fn(t_i64, 0) -> void);
|
||||
ifn!("llvm.lifetime.end", fn(t_i64, 0) -> void);
|
||||
|
||||
ifn!("llvm.is.constant", fn(0) -> i1);
|
||||
ifn!("llvm.expect", fn(0, 0) -> 0);
|
||||
|
||||
ifn!("llvm.eh.typeid.for", fn(0) -> t_i32);
|
||||
ifn!("llvm.localescape", fn(...) -> void);
|
||||
ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr);
|
||||
|
||||
ifn!("llvm.assume", fn(i1) -> void);
|
||||
ifn!("llvm.prefetch", fn(0, t_i32, t_i32, t_i32) -> void);
|
||||
|
||||
// This isn't an "LLVM intrinsic", but LLVM's optimization passes
|
||||
// recognize it like one (including turning it into `bcmp` sometimes)
|
||||
// and we use it to implement intrinsics like `raw_eq` and `compare_bytes`
|
||||
if base_name == "memcmp" {
|
||||
let fn_ty = self.type_func(&[ptr, ptr, t_isize], self.type_int());
|
||||
let fn_ty = self
|
||||
.type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], self.type_int());
|
||||
let f = self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty);
|
||||
self.intrinsics.borrow_mut().insert(("memcmp", SmallVec::new()), (fn_ty, f));
|
||||
|
||||
return (fn_ty, f);
|
||||
}
|
||||
|
||||
// variadic intrinsics
|
||||
ifn!("llvm.va_start", fn(0) -> void);
|
||||
ifn!("llvm.va_end", fn(0) -> void);
|
||||
ifn!("llvm.va_copy", fn(0, 0) -> void);
|
||||
let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes())
|
||||
.unwrap_or_else(|| bug!("Unknown intrinsic: `{base_name}`"));
|
||||
let f = intrinsic.get_declaration(self.llmod, &type_params);
|
||||
|
||||
if self.sess().instrument_coverage() {
|
||||
ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void);
|
||||
ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void);
|
||||
ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void);
|
||||
}
|
||||
|
||||
ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1);
|
||||
ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1});
|
||||
|
||||
if self.sess().opts.debuginfo != DebugInfo::None {
|
||||
ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata, t_metadata) -> void);
|
||||
ifn!("llvm.dbg.value", fn(t_metadata, t_metadata, t_metadata) -> void);
|
||||
}
|
||||
|
||||
ifn!("llvm.ptrmask", fn(0, 1) -> 0);
|
||||
ifn!("llvm.threadlocal.address", fn(ptr) -> ptr);
|
||||
|
||||
ifn!("llvm.masked.load", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0);
|
||||
ifn!("llvm.masked.store", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void);
|
||||
ifn!("llvm.masked.gather", fn(1, t_i32, same_width_vector(0, i1), 0) -> 0);
|
||||
ifn!("llvm.masked.scatter", fn(0, 1, t_i32, same_width_vector(0, i1)) -> void);
|
||||
|
||||
bug!("Unknown intrinsic: `{base_name}`")
|
||||
(self.get_type_of_global(f), f)
|
||||
}
|
||||
|
||||
pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
|
||||
|
|
|
|||
|
|
@ -154,8 +154,6 @@ fn call_simple_intrinsic<'ll, 'tcx>(
|
|||
sym::roundf64 => ("llvm.round", &[bx.type_f64()]),
|
||||
sym::roundf128 => ("llvm.round", &[bx.type_f128()]),
|
||||
|
||||
sym::ptr_mask => ("llvm.ptrmask", &[bx.type_ptr(), bx.type_isize()]),
|
||||
|
||||
_ => return None,
|
||||
};
|
||||
Some(bx.call_intrinsic(
|
||||
|
|
@ -181,6 +179,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
let simple = call_simple_intrinsic(self, name, args);
|
||||
let llval = match name {
|
||||
_ if simple.is_some() => simple.unwrap(),
|
||||
sym::ptr_mask => {
|
||||
let ptr = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.ptrmask",
|
||||
&[self.val_ty(ptr), self.type_isize()],
|
||||
&[ptr, args[1].immediate()],
|
||||
)
|
||||
}
|
||||
sym::is_val_statically_known => {
|
||||
if let OperandValue::Immediate(imm) = args[0].val {
|
||||
self.call_intrinsic(
|
||||
|
|
@ -232,11 +238,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
|
||||
sym::va_copy => self.call_intrinsic(
|
||||
"llvm.va_copy",
|
||||
&[self.type_ptr()],
|
||||
&[args[0].immediate(), args[1].immediate()],
|
||||
),
|
||||
sym::va_copy => {
|
||||
let dest = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.va_copy",
|
||||
&[self.val_ty(dest)],
|
||||
&[dest, args[1].immediate()],
|
||||
)
|
||||
}
|
||||
sym::va_arg => {
|
||||
match result.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => {
|
||||
|
|
@ -309,15 +318,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
sym::prefetch_write_instruction => (1, 0),
|
||||
_ => bug!(),
|
||||
};
|
||||
let ptr = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.prefetch",
|
||||
&[self.type_ptr()],
|
||||
&[
|
||||
args[0].immediate(),
|
||||
self.const_i32(rw),
|
||||
args[1].immediate(),
|
||||
self.const_i32(cache_type),
|
||||
],
|
||||
&[self.val_ty(ptr)],
|
||||
&[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)],
|
||||
)
|
||||
}
|
||||
sym::carrying_mul_add => {
|
||||
|
|
@ -378,7 +383,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
sym::ctlz | sym::cttz => {
|
||||
let y = self.const_bool(false);
|
||||
let ret = self.call_intrinsic(
|
||||
&format!("llvm.{name}"),
|
||||
format!("llvm.{name}"),
|
||||
&[llty],
|
||||
&[args[0].immediate(), y],
|
||||
);
|
||||
|
|
@ -423,7 +428,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
// always uses `u32`.
|
||||
let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
|
||||
|
||||
self.call_intrinsic(&llvm_name, &[llty], &[val, val, raw_shift])
|
||||
self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift])
|
||||
}
|
||||
sym::saturating_add | sym::saturating_sub => {
|
||||
let is_add = name == sym::saturating_add;
|
||||
|
|
@ -434,7 +439,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
if signed { 's' } else { 'u' },
|
||||
if is_add { "add" } else { "sub" },
|
||||
);
|
||||
self.call_intrinsic(&llvm_name, &[llty], &[lhs, rhs])
|
||||
self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs])
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
|
@ -637,11 +642,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
self.call_intrinsic("llvm.va_start", &[self.type_ptr()], &[va_list])
|
||||
self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list])
|
||||
}
|
||||
|
||||
fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
self.call_intrinsic("llvm.va_end", &[self.type_ptr()], &[va_list])
|
||||
self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1018,7 +1023,7 @@ fn codegen_emcc_try<'ll, 'tcx>(
|
|||
let selector = bx.extract_value(vals, 1);
|
||||
|
||||
// Check if the typeid we got is the one for a Rust panic.
|
||||
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.type_ptr()], &[tydesc]);
|
||||
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]);
|
||||
let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
||||
let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
|
||||
|
||||
|
|
@ -2393,7 +2398,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
);
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
||||
|
||||
return Ok(bx.call_intrinsic(&llvm_intrinsic, &[vec_ty], &[lhs, rhs]));
|
||||
return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs]));
|
||||
}
|
||||
|
||||
span_bug!(span, "unknown SIMD intrinsic");
|
||||
|
|
|
|||
|
|
@ -340,18 +340,11 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
target_config(sess)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
|
||||
Box::new(rustc_codegen_ssa::base::codegen_crate(
|
||||
LlvmCodegenBackend(()),
|
||||
tcx,
|
||||
crate::llvm_util::target_cpu(tcx.sess).to_string(),
|
||||
metadata,
|
||||
need_metadata_module,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -376,14 +369,20 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
(codegen_results, work_products)
|
||||
}
|
||||
|
||||
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
|
||||
use crate::back::archive::LlvmArchiveBuilderBuilder;
|
||||
|
||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||
// This should produce either a finished executable or library.
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs);
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1078,8 +1078,6 @@ unsafe extern "C" {
|
|||
|
||||
// Operations on other types
|
||||
pub(crate) fn LLVMVoidTypeInContext(C: &Context) -> &Type;
|
||||
pub(crate) fn LLVMTokenTypeInContext(C: &Context) -> &Type;
|
||||
pub(crate) fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
|
||||
|
||||
// Operations on all values
|
||||
pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type;
|
||||
|
|
@ -1198,14 +1196,12 @@ unsafe extern "C" {
|
|||
|
||||
// Operations about llvm intrinsics
|
||||
pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
|
||||
pub(crate) fn LLVMIntrinsicIsOverloaded(ID: NonZero<c_uint>) -> Bool;
|
||||
pub(crate) fn LLVMIntrinsicCopyOverloadedName2<'a>(
|
||||
pub(crate) fn LLVMGetIntrinsicDeclaration<'a>(
|
||||
Mod: &'a Module,
|
||||
ID: NonZero<c_uint>,
|
||||
ParamTypes: *const &'a Type,
|
||||
ParamCount: size_t,
|
||||
NameLength: *mut size_t,
|
||||
) -> *mut c_char;
|
||||
) -> &'a Value;
|
||||
|
||||
// Operations on parameters
|
||||
pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::num::NonZero;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
use std::string::FromUtf8Error;
|
||||
use std::{ptr, slice};
|
||||
|
||||
use libc::c_uint;
|
||||
use rustc_abi::{Align, Size, WrappingRange};
|
||||
|
|
@ -339,34 +339,14 @@ impl Intrinsic {
|
|||
NonZero::new(id).map(|id| Self { id })
|
||||
}
|
||||
|
||||
pub(crate) fn is_overloaded(self) -> bool {
|
||||
unsafe { LLVMIntrinsicIsOverloaded(self.id) == True }
|
||||
}
|
||||
|
||||
pub(crate) fn overloaded_name<'ll>(
|
||||
pub(crate) fn get_declaration<'ll>(
|
||||
self,
|
||||
llmod: &'ll Module,
|
||||
type_params: &[&'ll Type],
|
||||
) -> String {
|
||||
let mut len = 0;
|
||||
let ptr = unsafe {
|
||||
LLVMIntrinsicCopyOverloadedName2(
|
||||
llmod,
|
||||
self.id,
|
||||
type_params.as_ptr(),
|
||||
type_params.len(),
|
||||
&mut len,
|
||||
)
|
||||
};
|
||||
|
||||
let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), len) };
|
||||
let copied = str::from_utf8(slice).expect("Non-UTF8 intrinsic name").to_string();
|
||||
|
||||
) -> &'ll Value {
|
||||
unsafe {
|
||||
libc::free(ptr.cast());
|
||||
LLVMGetIntrinsicDeclaration(llmod, self.id, type_params.as_ptr(), type_params.len())
|
||||
}
|
||||
|
||||
copied
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,13 +58,6 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
pub(crate) fn type_void(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) }
|
||||
}
|
||||
pub(crate) fn type_token(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) }
|
||||
}
|
||||
|
||||
pub(crate) fn type_metadata(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) }
|
||||
}
|
||||
|
||||
///x Creates an integer type with the given number of bits, e.g., i24
|
||||
pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
|
||||
|
|
|
|||
|
|
@ -198,8 +198,6 @@ codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status
|
|||
codegen_ssa_malformed_cgu_name =
|
||||
found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
|
||||
|
||||
codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
|
||||
|
||||
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
|
||||
|
||||
codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ use object::read::macho::FatArch;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_fs_util::TempDirBuilder;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Symbol;
|
||||
use tracing::trace;
|
||||
|
||||
use super::metadata::search_for_section;
|
||||
use super::metadata::{create_compressed_metadata_file, search_for_section};
|
||||
use crate::common;
|
||||
// Re-exporting for rustc_codegen_llvm::back::archive
|
||||
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
|
||||
|
|
@ -58,6 +59,15 @@ impl From<ImportLibraryItem> for COFFShortExport {
|
|||
pub trait ArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
||||
|
||||
fn create_dylib_metadata_wrapper(
|
||||
&self,
|
||||
sess: &Session,
|
||||
metadata: &EncodedMetadata,
|
||||
symbol_name: &str,
|
||||
) -> Vec<u8> {
|
||||
create_compressed_metadata_file(sess, metadata, symbol_name)
|
||||
}
|
||||
|
||||
/// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
|
||||
/// and returns the path on disk to that import library.
|
||||
/// This functions doesn't take `self` so that it can be called from
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
|||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
use rustc_metadata::{
|
||||
NativeLibSearchFallback, find_native_static_library, walk_native_lib_search_dirs,
|
||||
EncodedMetadata, NativeLibSearchFallback, find_native_static_library,
|
||||
walk_native_lib_search_dirs,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::lint_level;
|
||||
|
|
@ -91,6 +92,7 @@ pub fn link_binary(
|
|||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
let _timer = sess.timer("link_binary");
|
||||
|
|
@ -142,6 +144,7 @@ pub fn link_binary(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
RlibFlavor::Normal,
|
||||
&path,
|
||||
)
|
||||
|
|
@ -152,6 +155,7 @@ pub fn link_binary(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
&out_filename,
|
||||
&path,
|
||||
);
|
||||
|
|
@ -163,6 +167,7 @@ pub fn link_binary(
|
|||
crate_type,
|
||||
&out_filename,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
path.as_ref(),
|
||||
);
|
||||
}
|
||||
|
|
@ -226,11 +231,7 @@ pub fn link_binary(
|
|||
let remove_temps_from_module =
|
||||
|module: &CompiledModule| maybe_remove_temps_from_module(false, false, module);
|
||||
|
||||
// Otherwise, always remove the metadata and allocator module temporaries.
|
||||
if let Some(ref metadata_module) = codegen_results.metadata_module {
|
||||
remove_temps_from_module(metadata_module);
|
||||
}
|
||||
|
||||
// Otherwise, always remove the allocator module temporaries.
|
||||
if let Some(ref allocator_module) = codegen_results.allocator_module {
|
||||
remove_temps_from_module(allocator_module);
|
||||
}
|
||||
|
|
@ -312,6 +313,7 @@ fn link_rlib<'a>(
|
|||
sess: &'a Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
flavor: RlibFlavor,
|
||||
tmpdir: &MaybeTempDir,
|
||||
) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
|
|
@ -319,12 +321,9 @@ fn link_rlib<'a>(
|
|||
|
||||
let trailing_metadata = match flavor {
|
||||
RlibFlavor::Normal => {
|
||||
let (metadata, metadata_position) = create_wrapper_file(
|
||||
sess,
|
||||
".rmeta".to_string(),
|
||||
codegen_results.metadata.stub_or_full(),
|
||||
);
|
||||
let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME);
|
||||
let (metadata, metadata_position) =
|
||||
create_wrapper_file(sess, ".rmeta".to_string(), metadata.stub_or_full());
|
||||
let metadata = emit_wrapper_file(sess, &metadata, tmpdir.as_ref(), METADATA_FILENAME);
|
||||
match metadata_position {
|
||||
MetadataPosition::First => {
|
||||
// Most of the time metadata in rlib files is wrapped in a "dummy" object
|
||||
|
|
@ -392,7 +391,7 @@ fn link_rlib<'a>(
|
|||
let src = read(path)
|
||||
.unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }));
|
||||
let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
|
||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
|
||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir.as_ref(), filename.as_str());
|
||||
packed_bundled_libs.push(wrapper_file);
|
||||
} else {
|
||||
let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
|
||||
|
|
@ -473,6 +472,7 @@ fn link_staticlib(
|
|||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
out_filename: &Path,
|
||||
tempdir: &MaybeTempDir,
|
||||
) {
|
||||
|
|
@ -481,6 +481,7 @@ fn link_staticlib(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
RlibFlavor::StaticlibBase,
|
||||
tempdir,
|
||||
);
|
||||
|
|
@ -694,6 +695,7 @@ fn link_natively(
|
|||
crate_type: CrateType,
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
tmpdir: &Path,
|
||||
) {
|
||||
info!("preparing {:?} to {:?}", crate_type, out_filename);
|
||||
|
|
@ -718,6 +720,7 @@ fn link_natively(
|
|||
tmpdir,
|
||||
temp_filename,
|
||||
codegen_results,
|
||||
metadata,
|
||||
self_contained_components,
|
||||
);
|
||||
|
||||
|
|
@ -2095,17 +2098,25 @@ fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &Cod
|
|||
/// Add object files containing metadata for the current crate.
|
||||
fn add_local_crate_metadata_objects(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
crate_type: CrateType,
|
||||
tmpdir: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
) {
|
||||
// When linking a dynamic library, we put the metadata into a section of the
|
||||
// executable. This metadata is in a separate object file from the main
|
||||
// object file, so we link that in here.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro)
|
||||
&& let Some(m) = &codegen_results.metadata_module
|
||||
&& let Some(obj) = &m.object
|
||||
{
|
||||
cmd.add_object(obj);
|
||||
// object file, so we create and link it in here.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) {
|
||||
let data = archive_builder_builder.create_dylib_metadata_wrapper(
|
||||
sess,
|
||||
&metadata,
|
||||
&codegen_results.crate_info.metadata_symbol,
|
||||
);
|
||||
let obj = emit_wrapper_file(sess, &data, tmpdir, "rmeta.o");
|
||||
|
||||
cmd.add_object(&obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2195,6 +2206,7 @@ fn linker_with_args(
|
|||
tmpdir: &Path,
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
) -> Command {
|
||||
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
|
||||
|
|
@ -2269,7 +2281,15 @@ fn linker_with_args(
|
|||
// in this DAG so far because they can only depend on other native libraries
|
||||
// and such dependencies are also required to be specified.
|
||||
add_local_crate_regular_objects(cmd, codegen_results);
|
||||
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
|
||||
add_local_crate_metadata_objects(
|
||||
cmd,
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
crate_type,
|
||||
tmpdir,
|
||||
codegen_results,
|
||||
metadata,
|
||||
);
|
||||
add_local_crate_allocator_objects(cmd, codegen_results);
|
||||
|
||||
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
|||
use rustc_incremental::{
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
|
|
@ -142,7 +141,6 @@ impl ModuleConfig {
|
|||
|| match kind {
|
||||
ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object),
|
||||
ModuleKind::Allocator => false,
|
||||
ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata),
|
||||
};
|
||||
|
||||
let emit_obj = if !should_emit_obj {
|
||||
|
|
@ -350,7 +348,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub output_filenames: Arc<OutputFilenames>,
|
||||
pub invocation_temp: Option<String>,
|
||||
pub regular_module_config: Arc<ModuleConfig>,
|
||||
pub metadata_module_config: Arc<ModuleConfig>,
|
||||
pub allocator_module_config: Arc<ModuleConfig>,
|
||||
pub tm_factory: TargetMachineFactoryFn<B>,
|
||||
pub msvc_imps_needed: bool,
|
||||
|
|
@ -395,7 +392,6 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
|
|||
pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
|
||||
match kind {
|
||||
ModuleKind::Regular => &self.regular_module_config,
|
||||
ModuleKind::Metadata => &self.metadata_module_config,
|
||||
ModuleKind::Allocator => &self.allocator_module_config,
|
||||
}
|
||||
}
|
||||
|
|
@ -474,8 +470,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
backend: B,
|
||||
tcx: TyCtxt<'_>,
|
||||
target_cpu: String,
|
||||
metadata: EncodedMetadata,
|
||||
metadata_module: Option<CompiledModule>,
|
||||
) -> OngoingCodegen<B> {
|
||||
let (coordinator_send, coordinator_receive) = channel();
|
||||
|
||||
|
|
@ -485,7 +479,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||
|
||||
let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins);
|
||||
let metadata_config = ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins);
|
||||
let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins);
|
||||
|
||||
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
||||
|
|
@ -499,15 +492,12 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
codegen_worker_send,
|
||||
coordinator_receive,
|
||||
Arc::new(regular_config),
|
||||
Arc::new(metadata_config),
|
||||
Arc::new(allocator_config),
|
||||
coordinator_send.clone(),
|
||||
);
|
||||
|
||||
OngoingCodegen {
|
||||
backend,
|
||||
metadata,
|
||||
metadata_module,
|
||||
crate_info,
|
||||
|
||||
codegen_worker_receive,
|
||||
|
|
@ -843,12 +833,6 @@ pub(crate) fn compute_per_cgu_lto_type(
|
|||
sess_crate_types: &[CrateType],
|
||||
module_kind: ModuleKind,
|
||||
) -> ComputedLtoType {
|
||||
// Metadata modules never participate in LTO regardless of the lto
|
||||
// settings.
|
||||
if module_kind == ModuleKind::Metadata {
|
||||
return ComputedLtoType::No;
|
||||
}
|
||||
|
||||
// If the linker does LTO, we don't have to do it. Note that we
|
||||
// keep doing full LTO, if it is requested, as not to break the
|
||||
// assumption that the output will be a single module.
|
||||
|
|
@ -1029,10 +1013,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
|
|||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
|
||||
if !cgcx.opts.unstable_opts.combine_cgu
|
||||
|| module.kind == ModuleKind::Metadata
|
||||
|| module.kind == ModuleKind::Allocator
|
||||
{
|
||||
if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
|
||||
let module = B::codegen(cgcx, dcx, module, module_config)?;
|
||||
Ok(WorkItemResult::Finished(module))
|
||||
} else {
|
||||
|
|
@ -1123,7 +1104,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
codegen_worker_send: Sender<CguMessage>,
|
||||
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
metadata_config: Arc<ModuleConfig>,
|
||||
allocator_config: Arc<ModuleConfig>,
|
||||
tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
|
||||
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
|
||||
|
|
@ -1216,7 +1196,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
diag_emitter: shared_emitter.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
regular_module_config: regular_config,
|
||||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features),
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
|
|
@ -1673,7 +1652,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
assert!(compiled_allocator_module.is_none());
|
||||
compiled_allocator_module = Some(compiled_module);
|
||||
}
|
||||
ModuleKind::Metadata => bug!("Should be handled separately"),
|
||||
}
|
||||
}
|
||||
Ok(WorkItemResult::NeedsLink(module)) => {
|
||||
|
|
@ -2055,8 +2033,6 @@ impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
|
|||
|
||||
pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
||||
pub backend: B,
|
||||
pub metadata: EncodedMetadata,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub crate_info: CrateInfo,
|
||||
pub codegen_worker_receive: Receiver<CguMessage>,
|
||||
pub shared_emitter_main: SharedEmitterMain,
|
||||
|
|
@ -2096,12 +2072,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
|
||||
(
|
||||
CodegenResults {
|
||||
metadata: self.metadata,
|
||||
crate_info: self.crate_info,
|
||||
|
||||
modules: compiled_modules.modules,
|
||||
allocator_module: compiled_modules.allocator_module,
|
||||
metadata_module: self.metadata_module,
|
||||
},
|
||||
work_products,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ use rustc_data_structures::unord::UnordMap;
|
|||
use rustc_hir::ItemId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::middle::{exported_symbols, lang_items};
|
||||
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
|
||||
use rustc_middle::middle::lang_items;
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
|
||||
|
|
@ -28,7 +27,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
|||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
||||
use rustc_session::config::{self, CrateType, EntryFnType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
|
|
@ -37,7 +36,6 @@ use tracing::{debug, info};
|
|||
|
||||
use crate::assert_module_sources::CguReuse;
|
||||
use crate::back::link::are_upstream_rust_objects_already_included;
|
||||
use crate::back::metadata::create_compressed_metadata_file;
|
||||
use crate::back::write::{
|
||||
ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen,
|
||||
submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
|
||||
|
|
@ -48,8 +46,7 @@ use crate::mir::operand::OperandValue;
|
|||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
errors, meth, mir,
|
||||
CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
||||
};
|
||||
|
||||
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
|
|
@ -669,12 +666,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
backend: B,
|
||||
tcx: TyCtxt<'_>,
|
||||
target_cpu: String,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> 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);
|
||||
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu);
|
||||
|
||||
ongoing_codegen.codegen_finished(tcx);
|
||||
|
||||
|
|
@ -707,39 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
}
|
||||
}
|
||||
|
||||
let metadata_module = need_metadata_module.then(|| {
|
||||
// Emit compressed metadata object.
|
||||
let metadata_cgu_name =
|
||||
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
|
||||
tcx.sess.time("write_compressed_metadata", || {
|
||||
let file_name = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Metadata,
|
||||
&metadata_cgu_name,
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
let data = create_compressed_metadata_file(
|
||||
tcx.sess,
|
||||
&metadata,
|
||||
&exported_symbols::metadata_symbol_name(tcx),
|
||||
);
|
||||
if let Err(error) = std::fs::write(&file_name, data) {
|
||||
tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error });
|
||||
}
|
||||
CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(file_name),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
links_from_incr_cache: Vec::new(),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let ongoing_codegen =
|
||||
start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module);
|
||||
let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu);
|
||||
|
||||
// Codegen an allocator shim, if necessary.
|
||||
if let Some(kind) = allocator_kind_for_codegen(tcx) {
|
||||
|
|
@ -1010,6 +973,7 @@ impl CrateInfo {
|
|||
windows_subsystem,
|
||||
natvis_debugger_visualizers: Default::default(),
|
||||
lint_levels: CodegenLintLevels::from_tcx(tcx),
|
||||
metadata_symbol: exported_symbols::metadata_symbol_name(tcx),
|
||||
};
|
||||
|
||||
info.native_libraries.reserve(n_crates);
|
||||
|
|
|
|||
|
|
@ -777,12 +777,6 @@ pub(crate) struct MultipleMainFunctions {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_metadata_object_file_write)]
|
||||
pub(crate) struct MetadataObjectFileWrite {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_windows_subsystem)]
|
||||
pub(crate) struct InvalidWindowsSubsystem {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use rustc_data_structures::unord::UnordMap;
|
|||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::lint::LevelAndSource;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
|
|
@ -169,7 +170,6 @@ pub(crate) struct CachedModuleCodegen {
|
|||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)]
|
||||
pub enum ModuleKind {
|
||||
Regular,
|
||||
Metadata,
|
||||
Allocator,
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +233,7 @@ pub struct CrateInfo {
|
|||
pub windows_subsystem: Option<String>,
|
||||
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
|
||||
pub lint_levels: CodegenLintLevels,
|
||||
pub metadata_symbol: String,
|
||||
}
|
||||
|
||||
/// Target-specific options that get set in `cfg(...)`.
|
||||
|
|
@ -257,8 +258,6 @@ pub struct TargetConfig {
|
|||
pub struct CodegenResults {
|
||||
pub modules: Vec<CompiledModule>,
|
||||
pub allocator_module: Option<CompiledModule>,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub metadata: rustc_metadata::EncodedMetadata,
|
||||
pub crate_info: CrateInfo,
|
||||
}
|
||||
|
||||
|
|
@ -303,6 +302,7 @@ impl CodegenResults {
|
|||
sess: &Session,
|
||||
rlink_file: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut encoder = FileEncoder::new(rlink_file)?;
|
||||
|
|
@ -312,6 +312,7 @@ impl CodegenResults {
|
|||
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
|
||||
encoder.emit_str(sess.cfg_version);
|
||||
Encodable::encode(codegen_results, &mut encoder);
|
||||
Encodable::encode(metadata, &mut encoder);
|
||||
Encodable::encode(outputs, &mut encoder);
|
||||
encoder.finish().map_err(|(_path, err)| err)
|
||||
}
|
||||
|
|
@ -319,7 +320,7 @@ impl CodegenResults {
|
|||
pub fn deserialize_rlink(
|
||||
sess: &Session,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(Self, OutputFilenames), CodegenErrors> {
|
||||
) -> Result<(Self, EncodedMetadata, OutputFilenames), CodegenErrors> {
|
||||
// The Decodable machinery is not used here because it panics if the input data is invalid
|
||||
// and because its internal representation may change.
|
||||
if !data.starts_with(RLINK_MAGIC) {
|
||||
|
|
@ -350,8 +351,9 @@ impl CodegenResults {
|
|||
}
|
||||
|
||||
let codegen_results = CodegenResults::decode(&mut decoder);
|
||||
let metadata = EncodedMetadata::decode(&mut decoder);
|
||||
let outputs = OutputFilenames::decode(&mut decoder);
|
||||
Ok((codegen_results, outputs))
|
||||
Ok((codegen_results, metadata, outputs))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp;
|
||||
|
||||
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
||||
use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
|
|
@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use super::operand::OperandRef;
|
||||
|
|
@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
|
||||
};
|
||||
let ty = bx.cast_backend_type(cast_ty);
|
||||
bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
|
||||
load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
|
||||
}
|
||||
};
|
||||
bx.ret(llval);
|
||||
|
|
@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
MemFlags::empty(),
|
||||
);
|
||||
// ...and then load it with the ABI type.
|
||||
let cast_ty = bx.cast_backend_type(cast);
|
||||
llval = bx.load(cast_ty, llscratch, scratch_align);
|
||||
llval = load_cast(bx, cast, llscratch, scratch_align);
|
||||
bx.lifetime_end(llscratch, scratch_size);
|
||||
} else {
|
||||
// We can't use `PlaceRef::load` here because the argument
|
||||
|
|
@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> {
|
|||
/// Store a direct return value to an operand local place.
|
||||
DirectOperand(mir::Local),
|
||||
}
|
||||
|
||||
fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
cast: &CastTarget,
|
||||
ptr: Bx::Value,
|
||||
align: Align,
|
||||
) -> Bx::Value {
|
||||
let cast_ty = bx.cast_backend_type(cast);
|
||||
if let Some(offset_from_start) = cast.rest_offset {
|
||||
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||
let first_ty = bx.reg_backend_type(&cast.prefix[0].unwrap());
|
||||
let second_ty = bx.reg_backend_type(&cast.rest.unit);
|
||||
let first = bx.load(first_ty, ptr, align);
|
||||
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||
let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||
let res = bx.cx().const_poison(cast_ty);
|
||||
let res = bx.insert_value(res, first, 0);
|
||||
bx.insert_value(res, second, 1)
|
||||
} else {
|
||||
bx.load(cast_ty, ptr, align)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
cast: &CastTarget,
|
||||
value: Bx::Value,
|
||||
ptr: Bx::Value,
|
||||
align: Align,
|
||||
) {
|
||||
if let Some(offset_from_start) = cast.rest_offset {
|
||||
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||
assert!(cast.prefix[0].is_some());
|
||||
let first = bx.extract_value(value, 0);
|
||||
let second = bx.extract_value(value, 1);
|
||||
bx.store(first, ptr, align);
|
||||
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||
bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||
} else {
|
||||
bx.store(value, ptr, align);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ pub mod place;
|
|||
mod rvalue;
|
||||
mod statement;
|
||||
|
||||
pub use self::block::store_cast;
|
||||
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
|
||||
use self::operand::{OperandRef, OperandValue};
|
||||
use self::place::PlaceRef;
|
||||
|
|
@ -259,7 +260,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
}
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
debug!("alloc: {:?} (return place) -> place", local);
|
||||
let size = cast.size(&start_bx);
|
||||
let size = cast.size(&start_bx).max(layout.size);
|
||||
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
|
||||
use rustc_attr_data_structures::InstructionSetAttr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility};
|
||||
use rustc_middle::mir::{InlineAsmOperand, START_BLOCK};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::spec::{BinaryFormat, WasmCAbi};
|
||||
use rustc_target::spec::BinaryFormat;
|
||||
|
||||
use crate::common;
|
||||
use crate::mir::AsmCodegenMethods;
|
||||
|
|
@ -287,12 +286,7 @@ fn prefix_and_suffix<'tcx>(
|
|||
writeln!(begin, "{}", arch_prefix).unwrap();
|
||||
}
|
||||
writeln!(begin, "{asm_name}:").unwrap();
|
||||
writeln!(
|
||||
begin,
|
||||
".functype {asm_name} {}",
|
||||
wasm_functype(tcx, fn_abi, instance.def_id())
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(begin, ".functype {asm_name} {}", wasm_functype(tcx, fn_abi)).unwrap();
|
||||
|
||||
writeln!(end).unwrap();
|
||||
// .size is ignored for function symbols, so we can skip it
|
||||
|
|
@ -333,7 +327,7 @@ fn prefix_and_suffix<'tcx>(
|
|||
/// The webassembly type signature for the given function.
|
||||
///
|
||||
/// Used by the `.functype` directive on wasm targets.
|
||||
fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id: DefId) -> String {
|
||||
fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
|
||||
let mut signature = String::with_capacity(64);
|
||||
|
||||
let ptr_type = match tcx.data_layout.pointer_size.bits() {
|
||||
|
|
@ -342,17 +336,6 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id
|
|||
other => bug!("wasm pointer size cannot be {other} bits"),
|
||||
};
|
||||
|
||||
// FIXME: remove this once the wasm32-unknown-unknown ABI is fixed
|
||||
// please also add `wasm32-unknown-unknown` back in `tests/assembly/wasm32-naked-fn.rs`
|
||||
// basically the commit introducing this comment should be reverted
|
||||
if let PassMode::Pair { .. } = fn_abi.ret.mode {
|
||||
let _ = WasmCAbi::Legacy { with_lint: true };
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"cannot return a pair (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
|
||||
);
|
||||
}
|
||||
|
||||
let hidden_return = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
|
||||
|
||||
signature.push('(');
|
||||
|
|
@ -366,7 +349,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id
|
|||
|
||||
let mut it = fn_abi.args.iter().peekable();
|
||||
while let Some(arg_abi) = it.next() {
|
||||
wasm_type(tcx, &mut signature, arg_abi, ptr_type, def_id);
|
||||
wasm_type(&mut signature, arg_abi, ptr_type);
|
||||
if it.peek().is_some() {
|
||||
signature.push_str(", ");
|
||||
}
|
||||
|
|
@ -375,7 +358,7 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id
|
|||
signature.push_str(") -> (");
|
||||
|
||||
if !hidden_return {
|
||||
wasm_type(tcx, &mut signature, &fn_abi.ret, ptr_type, def_id);
|
||||
wasm_type(&mut signature, &fn_abi.ret, ptr_type);
|
||||
}
|
||||
|
||||
signature.push(')');
|
||||
|
|
@ -383,27 +366,13 @@ fn wasm_functype<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, def_id
|
|||
signature
|
||||
}
|
||||
|
||||
fn wasm_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
signature: &mut String,
|
||||
arg_abi: &ArgAbi<'_, Ty<'tcx>>,
|
||||
ptr_type: &'static str,
|
||||
def_id: DefId,
|
||||
) {
|
||||
fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_type: &'static str) {
|
||||
match arg_abi.mode {
|
||||
PassMode::Ignore => { /* do nothing */ }
|
||||
PassMode::Direct(_) => {
|
||||
let direct_type = match arg_abi.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type),
|
||||
BackendRepr::SimdVector { .. } => "v128",
|
||||
BackendRepr::Memory { .. } => {
|
||||
// FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed
|
||||
let _ = WasmCAbi::Legacy { with_lint: true };
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"cannot use memory args (the wasm32-unknown-unknown ABI is broken, see https://github.com/rust-lang/rust/issues/115666"
|
||||
);
|
||||
}
|
||||
other => unreachable!("unexpected BackendRepr: {:?}", other),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,12 +74,7 @@ pub trait CodegenBackend {
|
|||
|
||||
fn provide(&self, _providers: &mut Providers) {}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any>;
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any>;
|
||||
|
||||
/// This is called on the returned `Box<dyn Any>` from [`codegen_crate`](Self::codegen_crate)
|
||||
///
|
||||
|
|
@ -94,8 +89,14 @@ pub trait CodegenBackend {
|
|||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>);
|
||||
|
||||
/// This is called on the returned [`CodegenResults`] from [`join_codegen`](Self::join_codegen).
|
||||
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
|
||||
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs);
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -557,27 +557,34 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
|
|||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
dcx.emit_fatal(RlinkUnableToRead { err });
|
||||
});
|
||||
let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) {
|
||||
Ok((codegen, outputs)) => (codegen, outputs),
|
||||
Err(err) => {
|
||||
match err {
|
||||
CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
|
||||
CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => dcx
|
||||
.emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }),
|
||||
CodegenErrors::RustcVersionMismatch { rustc_version } => {
|
||||
dcx.emit_fatal(RLinkRustcVersionMismatch {
|
||||
rustc_version,
|
||||
current_version: sess.cfg_version,
|
||||
})
|
||||
}
|
||||
CodegenErrors::CorruptFile => {
|
||||
dcx.emit_fatal(RlinkCorruptFile { file });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
compiler.codegen_backend.link(sess, codegen_results, &outputs);
|
||||
let (codegen_results, metadata, outputs) =
|
||||
match CodegenResults::deserialize_rlink(sess, rlink_data) {
|
||||
Ok((codegen, metadata, outputs)) => (codegen, metadata, outputs),
|
||||
Err(err) => {
|
||||
match err {
|
||||
CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
|
||||
CodegenErrors::EmptyVersionNumber => {
|
||||
dcx.emit_fatal(RLinkEmptyVersionNumber)
|
||||
}
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
|
||||
dcx.emit_fatal(RLinkEncodingVersionMismatch {
|
||||
version_array,
|
||||
rlink_version,
|
||||
})
|
||||
}
|
||||
CodegenErrors::RustcVersionMismatch { rustc_version } => {
|
||||
dcx.emit_fatal(RLinkRustcVersionMismatch {
|
||||
rustc_version,
|
||||
current_version: sess.cfg_version,
|
||||
})
|
||||
}
|
||||
CodegenErrors::CorruptFile => {
|
||||
dcx.emit_fatal(RlinkCorruptFile { file });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
compiler.codegen_backend.link(sess, codegen_results, metadata, &outputs);
|
||||
} else {
|
||||
dcx.emit_fatal(RlinkNotAFile {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use crate::base::ast::MetaItemInner;
|
|||
use crate::errors;
|
||||
use crate::expand::{self, AstFragment, Invocation};
|
||||
use crate::module::DirOwnership;
|
||||
use crate::stats::MacroStat;
|
||||
|
||||
// When adding new variants, make sure to
|
||||
// adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
|
||||
|
|
@ -1191,7 +1192,7 @@ pub struct ExtCtxt<'a> {
|
|||
/// not to expand it again.
|
||||
pub(super) expanded_inert_attrs: MarkedAttrs,
|
||||
/// `-Zmacro-stats` data.
|
||||
pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals
|
||||
pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>,
|
||||
}
|
||||
|
||||
impl<'a> ExtCtxt<'a> {
|
||||
|
|
|
|||
|
|
@ -887,7 +887,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Do not const-check this function's body. It will always get replaced during CTFE.
|
||||
// Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
|
||||
rustc_attr!(
|
||||
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
|
||||
|
|
|
|||
|
|
@ -2285,12 +2285,23 @@ pub struct Expr<'hir> {
|
|||
}
|
||||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
pub fn precedence(
|
||||
&self,
|
||||
for_each_attr: &dyn Fn(HirId, &mut dyn FnMut(&Attribute)),
|
||||
) -> ExprPrecedence {
|
||||
let prefix_attrs_precedence = || -> ExprPrecedence {
|
||||
let mut has_outer_attr = false;
|
||||
for_each_attr(self.hir_id, &mut |attr: &Attribute| {
|
||||
has_outer_attr |= matches!(attr.style(), AttrStyle::Outer)
|
||||
});
|
||||
if has_outer_attr { ExprPrecedence::Prefix } else { ExprPrecedence::Unambiguous }
|
||||
};
|
||||
|
||||
match &self.kind {
|
||||
ExprKind::Closure(closure) => {
|
||||
match closure.fn_decl.output {
|
||||
FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump,
|
||||
FnRetTy::Return(_) => ExprPrecedence::Unambiguous,
|
||||
FnRetTy::Return(_) => prefix_attrs_precedence(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2315,7 +2326,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
// Need parens if and only if there are prefix attributes.
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
|
|
@ -2337,9 +2348,9 @@ impl Expr<'_> {
|
|||
| ExprKind::Type(..)
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Use(..)
|
||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||
| ExprKind::Err(_) => prefix_attrs_precedence(),
|
||||
|
||||
ExprKind::DropTemps(expr, ..) => expr.precedence(),
|
||||
ExprKind::DropTemps(expr, ..) => expr.precedence(for_each_attr),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3064,6 +3075,7 @@ pub struct TraitItem<'hir> {
|
|||
pub kind: TraitItemKind<'hir>,
|
||||
pub span: Span,
|
||||
pub defaultness: Defaultness,
|
||||
pub has_delayed_lints: bool,
|
||||
}
|
||||
|
||||
macro_rules! expect_methods_self_kind {
|
||||
|
|
@ -3168,6 +3180,7 @@ pub struct ImplItem<'hir> {
|
|||
pub defaultness: Defaultness,
|
||||
pub span: Span,
|
||||
pub vis_span: Span,
|
||||
pub has_delayed_lints: bool,
|
||||
}
|
||||
|
||||
impl<'hir> ImplItem<'hir> {
|
||||
|
|
@ -4087,6 +4100,7 @@ pub struct Item<'hir> {
|
|||
pub kind: ItemKind<'hir>,
|
||||
pub span: Span,
|
||||
pub vis_span: Span,
|
||||
pub has_delayed_lints: bool,
|
||||
}
|
||||
|
||||
impl<'hir> Item<'hir> {
|
||||
|
|
@ -4492,6 +4506,7 @@ pub struct ForeignItem<'hir> {
|
|||
pub owner_id: OwnerId,
|
||||
pub span: Span,
|
||||
pub vis_span: Span,
|
||||
pub has_delayed_lints: bool,
|
||||
}
|
||||
|
||||
impl ForeignItem<'_> {
|
||||
|
|
@ -4974,7 +4989,7 @@ mod size_asserts {
|
|||
static_assert_size!(Expr<'_>, 64);
|
||||
static_assert_size!(ExprKind<'_>, 48);
|
||||
static_assert_size!(FnDecl<'_>, 40);
|
||||
static_assert_size!(ForeignItem<'_>, 88);
|
||||
static_assert_size!(ForeignItem<'_>, 96);
|
||||
static_assert_size!(ForeignItemKind<'_>, 56);
|
||||
static_assert_size!(GenericArg<'_>, 16);
|
||||
static_assert_size!(GenericBound<'_>, 64);
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) ->
|
|||
}
|
||||
|
||||
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result {
|
||||
let Item { owner_id: _, kind, span: _, vis_span: _ } = item;
|
||||
let Item { owner_id: _, kind, span: _, vis_span: _, has_delayed_lints: _ } = item;
|
||||
try_visit!(visitor.visit_id(item.hir_id()));
|
||||
match *kind {
|
||||
ItemKind::ExternCrate(orig_name, ident) => {
|
||||
|
|
@ -656,7 +656,8 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
foreign_item: &'v ForeignItem<'v>,
|
||||
) -> V::Result {
|
||||
let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item;
|
||||
let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _, has_delayed_lints: _ } =
|
||||
foreign_item;
|
||||
try_visit!(visitor.visit_id(foreign_item.hir_id()));
|
||||
try_visit!(visitor.visit_ident(*ident));
|
||||
|
||||
|
|
@ -1205,7 +1206,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(
|
|||
visitor: &mut V,
|
||||
trait_item: &'v TraitItem<'v>,
|
||||
) -> V::Result {
|
||||
let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
|
||||
let TraitItem {
|
||||
ident,
|
||||
generics,
|
||||
ref defaultness,
|
||||
ref kind,
|
||||
span,
|
||||
owner_id: _,
|
||||
has_delayed_lints: _,
|
||||
} = *trait_item;
|
||||
let hir_id = trait_item.hir_id();
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
try_visit!(visitor.visit_generics(&generics));
|
||||
|
|
@ -1261,6 +1270,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(
|
|||
ref defaultness,
|
||||
span: _,
|
||||
vis_span: _,
|
||||
has_delayed_lints: _,
|
||||
} = *impl_item;
|
||||
|
||||
try_visit!(visitor.visit_ident(ident));
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the {$
|
|||
|
||||
hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
|
||||
|
||||
hir_analysis_async_drop_without_sync_drop = `AsyncDrop` impl without `Drop` impl
|
||||
.help = type implementing `AsyncDrop` trait must also implement `Drop` trait to be used in sync context and unwinds
|
||||
|
||||
hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
|
||||
.label = deref recursion limit reached
|
||||
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,15 @@ pub fn provide(providers: &mut Providers) {
|
|||
}
|
||||
|
||||
fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
|
||||
tcx.calculate_dtor(def_id, always_applicable::check_drop_impl)
|
||||
let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
|
||||
if dtor.is_none() && tcx.features().async_drop() {
|
||||
if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
|
||||
// When type has AsyncDrop impl, but doesn't have Drop impl, generate error
|
||||
let span = tcx.def_span(async_dtor.impl_did);
|
||||
tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });
|
||||
}
|
||||
}
|
||||
dtor
|
||||
}
|
||||
|
||||
fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
|
||||
|
|
|
|||
|
|
@ -1712,3 +1712,11 @@ pub(crate) struct AbiCustomClothedFunction {
|
|||
)]
|
||||
pub naked_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_async_drop_without_sync_drop)]
|
||||
#[help]
|
||||
pub(crate) struct AsyncDropWithoutSyncDrop {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,13 +193,41 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
|
||||
});
|
||||
|
||||
for owner_id in tcx.hir_crate_items(()).owners() {
|
||||
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
|
||||
for lint in &delayed_lints.lints {
|
||||
emit_delayed_lint(lint, tcx);
|
||||
tcx.sess.time("emit_ast_lowering_delayed_lints", || {
|
||||
// sanity check in debug mode that all lints are really noticed
|
||||
// and we really will emit them all in the loop right below.
|
||||
//
|
||||
// during ast lowering, when creating items, foreign items, trait items and impl items
|
||||
// we store in them whether they have any lints in their owner node that should be
|
||||
// picked up by `hir_crate_items`. However, theoretically code can run between that
|
||||
// boolean being inserted into the item and the owner node being created.
|
||||
// We don't want any new lints to be emitted there
|
||||
// (though honestly, you have to really try to manage to do that but still),
|
||||
// but this check is there to catch that.
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
// iterate over all owners
|
||||
for owner_id in tcx.hir_crate_items(()).owners() {
|
||||
// if it has delayed lints
|
||||
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
|
||||
if !delayed_lints.lints.is_empty() {
|
||||
// assert that delayed_lint_items also picked up this item to have lints
|
||||
assert!(
|
||||
tcx.hir_crate_items(()).delayed_lint_items().any(|i| i == owner_id)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for owner_id in tcx.hir_crate_items(()).delayed_lint_items() {
|
||||
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
|
||||
for lint in &delayed_lints.lints {
|
||||
emit_delayed_lint(lint, tcx);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tcx.par_hir_body_owners(|item_def_id| {
|
||||
let def_kind = tcx.def_kind(item_def_id);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ impl<'a> State<'a> {
|
|||
(self.attrs)(id)
|
||||
}
|
||||
|
||||
fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
|
||||
let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&hir::Attribute)| {
|
||||
self.attrs(id).iter().for_each(callback);
|
||||
};
|
||||
expr.precedence(&for_each_attr)
|
||||
}
|
||||
|
||||
fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) {
|
||||
self.print_either_attributes(attrs, ast::AttrStyle::Inner)
|
||||
}
|
||||
|
|
@ -1164,7 +1171,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
let npals = || parser::needs_par_as_let_scrutinee(init.precedence());
|
||||
let npals = || parser::needs_par_as_let_scrutinee(self.precedence(init));
|
||||
self.print_expr_cond_paren(init, Self::cond_needs_par(init) || npals())
|
||||
}
|
||||
|
||||
|
|
@ -1265,7 +1272,7 @@ impl<'a> State<'a> {
|
|||
fn print_expr_call(&mut self, func: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||
let needs_paren = match func.kind {
|
||||
hir::ExprKind::Field(..) => true,
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
_ => self.precedence(func) < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(func, needs_paren);
|
||||
|
|
@ -1279,7 +1286,10 @@ impl<'a> State<'a> {
|
|||
args: &[hir::Expr<'_>],
|
||||
) {
|
||||
let base_args = args;
|
||||
self.print_expr_cond_paren(receiver, receiver.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.print_expr_cond_paren(
|
||||
receiver,
|
||||
self.precedence(receiver) < ExprPrecedence::Unambiguous,
|
||||
);
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
|
||||
|
|
@ -1293,8 +1303,8 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_expr_binary(&mut self, op: hir::BinOpKind, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) {
|
||||
let binop_prec = op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
let left_prec = self.precedence(lhs);
|
||||
let right_prec = self.precedence(rhs);
|
||||
|
||||
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
|
|
@ -1323,7 +1333,7 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr<'_>) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
|
|
@ -1340,7 +1350,7 @@ impl<'a> State<'a> {
|
|||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
|
||||
}
|
||||
|
||||
fn print_literal(&mut self, lit: &hir::Lit) {
|
||||
|
|
@ -1483,7 +1493,7 @@ impl<'a> State<'a> {
|
|||
self.print_literal(lit);
|
||||
}
|
||||
hir::ExprKind::Cast(expr, ty) => {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Cast);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Cast);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
|
|
@ -1580,24 +1590,30 @@ impl<'a> State<'a> {
|
|||
self.print_block(blk, cb, ib);
|
||||
}
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
|
||||
self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign);
|
||||
self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign);
|
||||
}
|
||||
hir::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
|
||||
self.print_expr_cond_paren(lhs, self.precedence(lhs) <= ExprPrecedence::Assign);
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
self.print_expr_cond_paren(rhs, rhs.precedence() < ExprPrecedence::Assign);
|
||||
self.print_expr_cond_paren(rhs, self.precedence(rhs) < ExprPrecedence::Assign);
|
||||
}
|
||||
hir::ExprKind::Field(expr, ident) => {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
self.precedence(expr) < ExprPrecedence::Unambiguous,
|
||||
);
|
||||
self.word(".");
|
||||
self.print_ident(ident);
|
||||
}
|
||||
hir::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Unambiguous);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
self.precedence(expr) < ExprPrecedence::Unambiguous,
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index);
|
||||
self.word("]");
|
||||
|
|
@ -1611,7 +1627,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
if let Some(expr) = opt_expr {
|
||||
self.space();
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Continue(destination) => {
|
||||
|
|
@ -1625,13 +1641,13 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(result, result.precedence() < ExprPrecedence::Jump);
|
||||
self.print_expr_cond_paren(result, self.precedence(result) < ExprPrecedence::Jump);
|
||||
}
|
||||
hir::ExprKind::InlineAsm(asm) => {
|
||||
self.word("asm!");
|
||||
|
|
@ -1669,7 +1685,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
hir::ExprKind::Yield(expr, _) => {
|
||||
self.word_space("yield");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Jump);
|
||||
}
|
||||
hir::ExprKind::Err(_) => {
|
||||
self.popen();
|
||||
|
|
|
|||
|
|
@ -620,7 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
if let Ok(rest_snippet) = rest_snippet {
|
||||
let sugg = if callee_expr.precedence() >= ExprPrecedence::Unambiguous {
|
||||
let sugg = if self.precedence(callee_expr) >= ExprPrecedence::Unambiguous {
|
||||
vec![
|
||||
(up_to_rcvr_span, "".to_string()),
|
||||
(rest_span, format!(".{}({rest_snippet}", segment.ident)),
|
||||
|
|
|
|||
|
|
@ -1100,7 +1100,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
}
|
||||
|
||||
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
|
||||
let expr_prec = self.expr.precedence();
|
||||
let expr_prec = fcx.precedence(self.expr);
|
||||
let needs_parens = expr_prec < ExprPrecedence::Unambiguous;
|
||||
|
||||
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//! See [`rustc_hir_analysis::check`] for more context on type checking in general.
|
||||
|
||||
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx};
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
|
|
@ -17,7 +18,7 @@ use rustc_errors::{
|
|||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ExprKind, HirId, QPath};
|
||||
use rustc_hir::{Attribute, ExprKind, HirId, QPath};
|
||||
use rustc_hir_analysis::NoVariantNamed;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
|
||||
use rustc_infer::infer;
|
||||
|
|
@ -54,6 +55,30 @@ use crate::{
|
|||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(crate) fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
|
||||
let for_each_attr = |id: HirId, callback: &mut dyn FnMut(&Attribute)| {
|
||||
for attr in self.tcx.hir_attrs(id) {
|
||||
// For the purpose of rendering suggestions, disregard attributes
|
||||
// that originate from desugaring of any kind. For example, `x?`
|
||||
// desugars to `#[allow(unreachable_code)] match ...`. Failing to
|
||||
// ignore the prefix attribute in the desugaring would cause this
|
||||
// suggestion:
|
||||
//
|
||||
// let y: u32 = x?.try_into().unwrap();
|
||||
// ++++++++++++++++++++
|
||||
//
|
||||
// to be rendered as:
|
||||
//
|
||||
// let y: u32 = (x?).try_into().unwrap();
|
||||
// + +++++++++++++++++++++
|
||||
if attr.span().desugaring_kind().is_none() {
|
||||
callback(attr);
|
||||
}
|
||||
}
|
||||
};
|
||||
expr.precedence(&for_each_attr)
|
||||
}
|
||||
|
||||
/// Check an expr with an expectation type, and also demand that the expr's
|
||||
/// evaluated type is a subtype of the expectation at the end. This is a
|
||||
/// *hard* requirement.
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we remove the user's `clone` call.
|
||||
{
|
||||
vec![(receiver_method.ident.span, conversion_method_name.to_string())]
|
||||
} else if expr.precedence() < ExprPrecedence::Unambiguous {
|
||||
} else if self.precedence(expr) < ExprPrecedence::Unambiguous {
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
|
||||
|
|
@ -1395,7 +1395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
|
||||
|
||||
let mut sugg = if expr.precedence() >= ExprPrecedence::Unambiguous {
|
||||
let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
|
||||
vec![(span.shrink_to_hi(), ".into()".to_owned())]
|
||||
} else {
|
||||
vec![
|
||||
|
|
@ -3106,7 +3106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"change the type of the numeric literal from `{checked_ty}` to `{expected_ty}`",
|
||||
);
|
||||
|
||||
let close_paren = if expr.precedence() < ExprPrecedence::Unambiguous {
|
||||
let close_paren = if self.precedence(expr) < ExprPrecedence::Unambiguous {
|
||||
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
|
||||
")"
|
||||
} else {
|
||||
|
|
@ -3131,7 +3131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let len = src.trim_end_matches(&checked_ty.to_string()).len();
|
||||
span.with_lo(span.lo() + BytePos(len as u32))
|
||||
},
|
||||
if expr.precedence() < ExprPrecedence::Unambiguous {
|
||||
if self.precedence(expr) < ExprPrecedence::Unambiguous {
|
||||
// Readd `)`
|
||||
format!("{expected_ty})")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
|
|||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_incremental::setup_dep_graph;
|
||||
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::dep_graph::DepsType;
|
||||
|
|
@ -1174,7 +1175,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||
pub(crate) fn start_codegen<'tcx>(
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Box<dyn Any> {
|
||||
) -> (Box<dyn Any>, EncodedMetadata) {
|
||||
// Hook for tests.
|
||||
if let Some((def_id, _)) = tcx.entry_fn(())
|
||||
&& tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query)
|
||||
|
|
@ -1197,11 +1198,9 @@ pub(crate) fn start_codegen<'tcx>(
|
|||
|
||||
info!("Pre-codegen\n{:?}", tcx.debug_stats());
|
||||
|
||||
let (metadata, need_metadata_module) = rustc_metadata::fs::encode_and_write_metadata(tcx);
|
||||
let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx);
|
||||
|
||||
let codegen = tcx.sess.time("codegen_crate", move || {
|
||||
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
|
||||
});
|
||||
let codegen = tcx.sess.time("codegen_crate", move || codegen_backend.codegen_crate(tcx));
|
||||
|
||||
info!("Post-codegen\n{:?}", tcx.debug_stats());
|
||||
|
||||
|
|
@ -1211,7 +1210,7 @@ pub(crate) fn start_codegen<'tcx>(
|
|||
tcx.sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
codegen
|
||||
(codegen, metadata)
|
||||
}
|
||||
|
||||
/// Compute and validate the crate name.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_codegen_ssa::CodegenResults;
|
|||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::DepGraph;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -18,6 +19,7 @@ pub struct Linker {
|
|||
output_filenames: Arc<OutputFilenames>,
|
||||
// Only present when incr. comp. is enabled.
|
||||
crate_hash: Option<Svh>,
|
||||
metadata: EncodedMetadata,
|
||||
ongoing_codegen: Box<dyn Any>,
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +28,7 @@ impl Linker {
|
|||
tcx: TyCtxt<'_>,
|
||||
codegen_backend: &dyn CodegenBackend,
|
||||
) -> Linker {
|
||||
let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
|
||||
let (ongoing_codegen, metadata) = passes::start_codegen(codegen_backend, tcx);
|
||||
|
||||
Linker {
|
||||
dep_graph: tcx.dep_graph.clone(),
|
||||
|
|
@ -36,6 +38,7 @@ impl Linker {
|
|||
} else {
|
||||
None
|
||||
},
|
||||
metadata,
|
||||
ongoing_codegen,
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +78,7 @@ impl Linker {
|
|||
sess,
|
||||
&rlink_file,
|
||||
&codegen_results,
|
||||
&self.metadata,
|
||||
&*self.output_filenames,
|
||||
)
|
||||
.unwrap_or_else(|error| {
|
||||
|
|
@ -84,6 +88,6 @@ impl Linker {
|
|||
}
|
||||
|
||||
let _timer = sess.prof.verbose_generic_activity("link_crate");
|
||||
codegen_backend.link(sess, codegen_results, &self.output_filenames)
|
||||
codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
|
|||
use rustc_span::{FileName, SourceFileHashAlgorithm, sym};
|
||||
use rustc_target::spec::{
|
||||
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
|
||||
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, WasmCAbi,
|
||||
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel,
|
||||
};
|
||||
|
||||
use crate::interface::{initialize_checked_jobserver, parse_cfg};
|
||||
|
|
@ -882,7 +882,6 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(verify_llvm_ir, true);
|
||||
tracked!(virtual_function_elimination, true);
|
||||
tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
|
||||
tracked!(wasm_c_abi, WasmCAbi::Spec);
|
||||
// tidy-alphabetical-end
|
||||
|
||||
macro_rules! tracked_no_crate_hash {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use std::cell::Cell;
|
|||
use std::slice;
|
||||
|
||||
use rustc_ast::BindingMode;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
|
|
@ -850,6 +851,20 @@ impl<'tcx> LateContext<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns the effective precedence of an expression for the purpose of
|
||||
/// rendering diagnostic. This is not the same as the precedence that would
|
||||
/// be used for pretty-printing HIR by rustc_hir_pretty.
|
||||
pub fn precedence(&self, expr: &hir::Expr<'_>) -> ExprPrecedence {
|
||||
let for_each_attr = |id: hir::HirId, callback: &mut dyn FnMut(&hir::Attribute)| {
|
||||
for attr in self.tcx.hir_attrs(id) {
|
||||
if attr.span().desugaring_kind().is_none() {
|
||||
callback(attr);
|
||||
}
|
||||
}
|
||||
};
|
||||
expr.precedence(&for_each_attr)
|
||||
}
|
||||
|
||||
/// If the given expression is a local binding, find the initializer expression.
|
||||
/// If that initializer expression is another local binding, find its initializer again.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_ast::visit::{visit_opt, walk_list};
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
|
||||
|
|
@ -133,7 +134,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& owns_allocation(cx.tcx, ty)
|
||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(fn_id), AttributeKind::AsPtr(_))
|
||||
{
|
||||
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||
cx.tcx.emit_node_span_lint(
|
||||
|
|
|
|||
|
|
@ -33,10 +33,8 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> {
|
|||
}
|
||||
|
||||
impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
|
||||
// This always-inlined function is for the hot call site.
|
||||
#[inline(always)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn inlined_check_id(&mut self, id: ast::NodeId) {
|
||||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
self.context.opt_span_lint(lint_id.lint, span, |diag| {
|
||||
|
|
@ -45,11 +43,6 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// This non-inlined function is for the cold call sites.
|
||||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
self.inlined_check_id(id)
|
||||
}
|
||||
|
||||
/// Merge the lints specified by any lint attributes into the
|
||||
/// current lint context, call the provided function, then reset the
|
||||
/// lints in effect to their previous state.
|
||||
|
|
@ -61,7 +54,6 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
|
|||
debug!(?id);
|
||||
let push = self.context.builder.push(attrs, is_crate_node, None);
|
||||
|
||||
self.inlined_check_id(id);
|
||||
debug!("early context: enter_attrs({:?})", attrs);
|
||||
lint_callback!(self, check_attributes, attrs);
|
||||
ensure_sufficient_stack(|| f(self));
|
||||
|
|
@ -136,12 +128,8 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
|
|||
// the AST struct that they wrap (e.g. an item)
|
||||
self.with_lint_attrs(s.id, s.attrs(), |cx| {
|
||||
lint_callback!(cx, check_stmt, s);
|
||||
ast_visit::walk_stmt(cx, s);
|
||||
});
|
||||
// The visitor for the AST struct wrapped
|
||||
// by the statement (e.g. `Item`) will call
|
||||
// `with_lint_attrs`, so do this walk
|
||||
// outside of the above `with_lint_attrs` call
|
||||
ast_visit::walk_stmt(self, s);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) {
|
||||
|
|
|
|||
|
|
@ -623,6 +623,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||
"converted into hard error, \
|
||||
see <https://github.com/rust-lang/rust/issues/40107> for more information",
|
||||
);
|
||||
store.register_removed("wasm_c_abi", "the wasm C ABI has been fixed");
|
||||
}
|
||||
|
||||
fn register_internals(store: &mut LintStore) {
|
||||
|
|
|
|||
|
|
@ -140,7 +140,6 @@ declare_lint_pass! {
|
|||
UNUSED_VARIABLES,
|
||||
USELESS_DEPRECATED,
|
||||
WARNINGS,
|
||||
WASM_C_ABI,
|
||||
// tidy-alphabetical-end
|
||||
]
|
||||
}
|
||||
|
|
@ -4100,6 +4099,7 @@ declare_lint! {
|
|||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(Edition::Edition2024),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>",
|
||||
report_in_deps: true,
|
||||
};
|
||||
@edition Edition2024 => Deny;
|
||||
report_in_external_macro
|
||||
|
|
@ -4154,6 +4154,7 @@ declare_lint! {
|
|||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionAndFutureReleaseError(Edition::Edition2024),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2024/never-type-fallback.html>",
|
||||
report_in_deps: true,
|
||||
};
|
||||
report_in_external_macro
|
||||
}
|
||||
|
|
@ -4980,50 +4981,6 @@ declare_lint! {
|
|||
crate_level_only
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `wasm_c_abi` lint detects usage of the `extern "C"` ABI of wasm that is affected
|
||||
/// by a planned ABI change that has the goal of aligning Rust with the standard C ABI
|
||||
/// of this target.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs wasm32-unknown-unknown)
|
||||
/// #[repr(C)]
|
||||
/// struct MyType(i32, i32);
|
||||
///
|
||||
/// extern "C" my_fun(x: MyType) {}
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// error: this function function definition is affected by the wasm ABI transition: it passes an argument of non-scalar type `MyType`
|
||||
/// --> $DIR/wasm_c_abi_transition.rs:17:1
|
||||
/// |
|
||||
/// | pub extern "C" fn my_fun(_x: MyType) {}
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
/// |
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue #138762 <https://github.com/rust-lang/rust/issues/138762>
|
||||
/// = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Rust has historically implemented a non-spec-compliant C ABI on wasm32-unknown-unknown. This
|
||||
/// has caused incompatibilities with other compilers and Wasm targets. In a future version
|
||||
/// of Rust, this will be fixed, and therefore code relying on the non-spec-compliant C ABI will
|
||||
/// stop functioning.
|
||||
pub WASM_C_ABI,
|
||||
Warn,
|
||||
"detects code relying on rustc's non-spec-compliant wasm C ABI",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
reference: "issue #138762 <https://github.com/rust-lang/rust/issues/138762>",
|
||||
report_in_deps: true,
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `aarch64_softfloat_neon` lint detects usage of `#[target_feature(enable = "neon")]` on
|
||||
/// softfloat aarch64 targets. Enabling this target feature causes LLVM to alter the ABI of
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ use std::{fs, io};
|
|||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_fs_util::TempDirBuilder;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{CrateType, OutFileName, OutputType};
|
||||
use rustc_session::output::filename_for_metadata;
|
||||
use rustc_session::{MetadataKind, Session};
|
||||
|
||||
use crate::errors::{
|
||||
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
|
||||
|
|
@ -22,13 +22,8 @@ pub const METADATA_FILENAME: &str = "lib.rmeta";
|
|||
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
|
||||
/// directory being searched for `extern crate` (observing an incomplete file).
|
||||
/// The returned path is the temporary file containing the complete metadata.
|
||||
pub fn emit_wrapper_file(
|
||||
sess: &Session,
|
||||
data: &[u8],
|
||||
tmpdir: &MaybeTempDir,
|
||||
name: &str,
|
||||
) -> PathBuf {
|
||||
let out_filename = tmpdir.as_ref().join(name);
|
||||
pub fn emit_wrapper_file(sess: &Session, data: &[u8], tmpdir: &Path, name: &str) -> PathBuf {
|
||||
let out_filename = tmpdir.join(name);
|
||||
let result = fs::write(&out_filename, data);
|
||||
|
||||
if let Err(err) = result {
|
||||
|
|
@ -38,7 +33,7 @@ pub fn emit_wrapper_file(
|
|||
out_filename
|
||||
}
|
||||
|
||||
pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
||||
pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
|
||||
let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(()));
|
||||
// To avoid races with another rustc process scanning the output directory,
|
||||
// we need to write the file somewhere else and atomically move it to its
|
||||
|
|
@ -59,25 +54,20 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
|||
None
|
||||
};
|
||||
|
||||
// Always create a file at `metadata_filename`, even if we have nothing to write to it.
|
||||
// This simplifies the creation of the output `out_filename` when requested.
|
||||
let metadata_kind = tcx.metadata_kind();
|
||||
match metadata_kind {
|
||||
MetadataKind::None => {
|
||||
std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
|
||||
tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
|
||||
if tcx.needs_metadata() {
|
||||
encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref());
|
||||
} else {
|
||||
// Always create a file at `metadata_filename`, even if we have nothing to write to it.
|
||||
// This simplifies the creation of the output `out_filename` when requested.
|
||||
std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
|
||||
tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
|
||||
});
|
||||
if let Some(metadata_stub_filename) = &metadata_stub_filename {
|
||||
std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| {
|
||||
tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err });
|
||||
});
|
||||
if let Some(metadata_stub_filename) = &metadata_stub_filename {
|
||||
std::fs::File::create(metadata_stub_filename).unwrap_or_else(|err| {
|
||||
tcx.dcx()
|
||||
.emit_fatal(FailedCreateFile { filename: &metadata_stub_filename, err });
|
||||
});
|
||||
}
|
||||
}
|
||||
MetadataKind::Uncompressed | MetadataKind::Compressed => {
|
||||
encode_metadata(tcx, &metadata_filename, metadata_stub_filename.as_deref())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
|
||||
|
||||
|
|
@ -118,9 +108,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
|||
tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err });
|
||||
});
|
||||
|
||||
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
|
||||
|
||||
(metadata, need_metadata_module)
|
||||
metadata
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
|
|
|
|||
|
|
@ -1233,6 +1233,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
|
|||
body_owners: body_owners.into_boxed_slice(),
|
||||
opaques: opaques.into_boxed_slice(),
|
||||
nested_bodies: nested_bodies.into_boxed_slice(),
|
||||
delayed_lint_items: Box::new([]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1254,6 +1255,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
|
|||
body_owners,
|
||||
opaques,
|
||||
nested_bodies,
|
||||
delayed_lint_items,
|
||||
..
|
||||
} = collector;
|
||||
|
||||
|
|
@ -1266,6 +1268,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
|
|||
body_owners: body_owners.into_boxed_slice(),
|
||||
opaques: opaques.into_boxed_slice(),
|
||||
nested_bodies: nested_bodies.into_boxed_slice(),
|
||||
delayed_lint_items: delayed_lint_items.into_boxed_slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1282,6 +1285,7 @@ struct ItemCollector<'tcx> {
|
|||
body_owners: Vec<LocalDefId>,
|
||||
opaques: Vec<LocalDefId>,
|
||||
nested_bodies: Vec<LocalDefId>,
|
||||
delayed_lint_items: Vec<OwnerId>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemCollector<'tcx> {
|
||||
|
|
@ -1297,6 +1301,7 @@ impl<'tcx> ItemCollector<'tcx> {
|
|||
body_owners: Vec::default(),
|
||||
opaques: Vec::default(),
|
||||
nested_bodies: Vec::default(),
|
||||
delayed_lint_items: Vec::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1314,6 +1319,9 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
}
|
||||
|
||||
self.items.push(item.item_id());
|
||||
if self.crate_collector && item.has_delayed_lints {
|
||||
self.delayed_lint_items.push(item.item_id().owner_id);
|
||||
}
|
||||
|
||||
// Items that are modules are handled here instead of in visit_mod.
|
||||
if let ItemKind::Mod(_, module) = &item.kind {
|
||||
|
|
@ -1329,6 +1337,9 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
|
||||
fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
|
||||
self.foreign_items.push(item.foreign_item_id());
|
||||
if self.crate_collector && item.has_delayed_lints {
|
||||
self.delayed_lint_items.push(item.foreign_item_id().owner_id);
|
||||
}
|
||||
intravisit::walk_foreign_item(self, item)
|
||||
}
|
||||
|
||||
|
|
@ -1362,6 +1373,10 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
}
|
||||
|
||||
self.trait_items.push(item.trait_item_id());
|
||||
if self.crate_collector && item.has_delayed_lints {
|
||||
self.delayed_lint_items.push(item.trait_item_id().owner_id);
|
||||
}
|
||||
|
||||
intravisit::walk_trait_item(self, item)
|
||||
}
|
||||
|
||||
|
|
@ -1371,6 +1386,10 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
|
|||
}
|
||||
|
||||
self.impl_items.push(item.impl_item_id());
|
||||
if self.crate_collector && item.has_delayed_lints {
|
||||
self.delayed_lint_items.push(item.impl_item_id().owner_id);
|
||||
}
|
||||
|
||||
intravisit::walk_impl_item(self, item)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ pub struct ModuleItems {
|
|||
opaques: Box<[LocalDefId]>,
|
||||
body_owners: Box<[LocalDefId]>,
|
||||
nested_bodies: Box<[LocalDefId]>,
|
||||
// only filled with hir_crate_items, not with hir_module_items
|
||||
delayed_lint_items: Box<[OwnerId]>,
|
||||
}
|
||||
|
||||
impl ModuleItems {
|
||||
|
|
@ -49,6 +51,10 @@ impl ModuleItems {
|
|||
self.trait_items.iter().copied()
|
||||
}
|
||||
|
||||
pub fn delayed_lint_items(&self) -> impl Iterator<Item = OwnerId> {
|
||||
self.delayed_lint_items.iter().copied()
|
||||
}
|
||||
|
||||
/// Returns all items that are associated with some `impl` block (both inherent and trait impl
|
||||
/// blocks).
|
||||
pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,64 @@
|
|||
//! Defines the various compiler queries.
|
||||
//!
|
||||
//! For more information on the query system, see
|
||||
//! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
|
||||
//! This chapter includes instructions for adding new queries.
|
||||
//! # The rustc Query System: Query Definitions and Modifiers
|
||||
//!
|
||||
//! The core processes in rustc are shipped as queries. Each query is a demand-driven function from some key to a value.
|
||||
//! The execution result of the function is cached and directly read during the next request, thereby improving compilation efficiency.
|
||||
//! Some results are saved locally and directly read during the next compilation, which are core of incremental compilation.
|
||||
//!
|
||||
//! ## How to Read This Module
|
||||
//!
|
||||
//! Each `query` block in this file defines a single query, specifying its key and value types, along with various modifiers.
|
||||
//! These query definitions are processed by the [`rustc_macros`], which expands them into the necessary boilerplate code
|
||||
//! for the query system—including the [`Providers`] struct (a function table for all query implementations, where each field is
|
||||
//! a function pointer to the actual provider), caching, and dependency graph integration.
|
||||
//! **Note:** The `Providers` struct is not a Rust trait, but a struct generated by the `rustc_macros` to hold all provider functions.
|
||||
//! The `rustc_macros` also supports a set of **query modifiers** (see below) that control the behavior of each query.
|
||||
//!
|
||||
//! The actual provider functions are implemented in various modules and registered into the `Providers` struct
|
||||
//! during compiler initialization (see [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]).
|
||||
//!
|
||||
//! [`rustc_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/index.html
|
||||
//! [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]: ../../rustc_interface/passes/static.DEFAULT_QUERY_PROVIDERS.html
|
||||
//!
|
||||
//! ## Query Modifiers
|
||||
//!
|
||||
//! Query modifiers are special flags that alter the behavior of a query. They are parsed and processed by the `rustc_macros`
|
||||
//! The main modifiers are:
|
||||
//!
|
||||
//! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required for every query.
|
||||
//! - `arena_cache`: Use an arena for in-memory caching of the query result.
|
||||
//! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to true.
|
||||
//! - `fatal_cycle`: If a dependency cycle is detected, abort compilation with a fatal error.
|
||||
//! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately.
|
||||
//! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling.
|
||||
//! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed.
|
||||
//! - `anon`: Make the query anonymous in the dependency graph (no dep node is created).
|
||||
//! - `eval_always`: Always evaluate the query, ignoring its dependencies and cached results.
|
||||
//! - `depth_limit`: Impose a recursion depth limit on the query to prevent stack overflows.
|
||||
//! - `separate_provide_extern`: Use separate provider functions for local and external crates.
|
||||
//! - `feedable`: Allow the query result to be set from another query ("fed" externally).
|
||||
//! - `return_result_from_ensure_ok`: When called via `tcx.ensure_ok()`, return `Result<(), ErrorGuaranteed>` instead of `()`.
|
||||
//! If the query needs to be executed and returns an error, the error is returned to the caller.
|
||||
//! Only valid for queries returning `Result<_, ErrorGuaranteed>`.
|
||||
//!
|
||||
//! For the up-to-date list, see the `QueryModifiers` struct in
|
||||
//! [`rustc_macros/src/query.rs`](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/query.rs)
|
||||
//! and for more details in incremental compilation, see the
|
||||
//! [Query modifiers in incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation-in-detail.html#query-modifiers) section of the rustc-dev-guide.
|
||||
//!
|
||||
//! ## Query Expansion and Code Generation
|
||||
//!
|
||||
//! The [`rustc_macros::rustc_queries`] macro expands each query definition into:
|
||||
//! - A method on [`TyCtxt`] (and [`TyCtxtAt`]) for invoking the query.
|
||||
//! - Provider traits and structs for supplying the query's value.
|
||||
//! - Caching and dependency graph integration.
|
||||
//! - Support for incremental compilation, disk caching, and arena allocation as controlled by the modifiers.
|
||||
//!
|
||||
//! [`rustc_macros::rustc_queries`]: ../../rustc_macros/macro.rustc_queries.html
|
||||
//!
|
||||
//! The macro-based approach allows the query system to be highly flexible and maintainable, while minimizing boilerplate.
|
||||
//!
|
||||
//! For more details, see the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/query.html).
|
||||
|
||||
#![allow(unused_parens)]
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,13 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
|
|||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
// Perf testing has found that this check is slightly faster than
|
||||
// folding and re-interning an empty `ExternalConstraintsData`.
|
||||
// See: <https://github.com/rust-lang/rust/pull/142430>.
|
||||
if self.is_empty() {
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
Ok(FallibleTypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData {
|
||||
region_constraints: self.region_constraints.clone().try_fold_with(folder)?,
|
||||
opaque_types: self
|
||||
|
|
@ -64,6 +71,13 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
|
|||
}
|
||||
|
||||
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
|
||||
// Perf testing has found that this check is slightly faster than
|
||||
// folding and re-interning an empty `ExternalConstraintsData`.
|
||||
// See: <https://github.com/rust-lang/rust/pull/142430>.
|
||||
if self.is_empty() {
|
||||
return self;
|
||||
}
|
||||
|
||||
TypeFolder::cx(folder).mk_external_constraints(ExternalConstraintsData {
|
||||
region_constraints: self.region_constraints.clone().fold_with(folder),
|
||||
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
|||
use rustc_session::config::CrateType;
|
||||
use rustc_session::cstore::{CrateStoreDyn, Untracked};
|
||||
use rustc_session::lint::Lint;
|
||||
use rustc_session::{Limit, MetadataKind, Session};
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
|
|
@ -1858,23 +1858,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
&self.crate_types
|
||||
}
|
||||
|
||||
pub fn metadata_kind(self) -> MetadataKind {
|
||||
self.crate_types()
|
||||
.iter()
|
||||
.map(|ty| match *ty {
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => MetadataKind::None,
|
||||
CrateType::Rlib => MetadataKind::Uncompressed,
|
||||
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(MetadataKind::None)
|
||||
}
|
||||
|
||||
pub fn needs_metadata(self) -> bool {
|
||||
self.metadata_kind() != MetadataKind::None
|
||||
self.crate_types().iter().any(|ty| match *ty {
|
||||
CrateType::Executable
|
||||
| CrateType::Staticlib
|
||||
| CrateType::Cdylib
|
||||
| CrateType::Sdylib => false,
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn needs_crate_hash(self) -> bool {
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
|
|||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use rustc_target::spec::{
|
||||
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi,
|
||||
};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi};
|
||||
use tracing::debug;
|
||||
use {rustc_abi as abi, rustc_hir as hir};
|
||||
|
||||
|
|
@ -565,12 +563,6 @@ impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.sess.opts.unstable_opts.wasm_c_abi
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi {
|
||||
|
|
@ -625,12 +617,6 @@ impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.calc.cx.wasm_c_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
self.calc.cx.x86_abi_opt()
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ fn build_poll_switch<'tcx>(
|
|||
body: &mut Body<'tcx>,
|
||||
poll_enum: Ty<'tcx>,
|
||||
poll_unit_place: &Place<'tcx>,
|
||||
fut_pin_place: &Place<'tcx>,
|
||||
ready_block: BasicBlock,
|
||||
yield_block: BasicBlock,
|
||||
) -> BasicBlock {
|
||||
|
|
@ -162,9 +163,11 @@ fn build_poll_switch<'tcx>(
|
|||
Rvalue::Discriminant(*poll_unit_place),
|
||||
))),
|
||||
};
|
||||
let storage_dead =
|
||||
Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) };
|
||||
let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable);
|
||||
body.basic_blocks_mut().push(BasicBlockData {
|
||||
statements: [discr_assign].to_vec(),
|
||||
statements: [storage_dead, discr_assign].to_vec(),
|
||||
terminator: Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
|
|
@ -332,10 +335,17 @@ pub(super) fn expand_async_drops<'tcx>(
|
|||
kind: StatementKind::Assign(Box::new((context_ref_place, arg))),
|
||||
});
|
||||
let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
|
||||
let switch_block =
|
||||
build_poll_switch(tcx, body, poll_enum, &poll_unit_place, target, yield_block);
|
||||
let (pin_bb, fut_pin_place) =
|
||||
build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue);
|
||||
let switch_block = build_poll_switch(
|
||||
tcx,
|
||||
body,
|
||||
poll_enum,
|
||||
&poll_unit_place,
|
||||
&fut_pin_place,
|
||||
target,
|
||||
yield_block,
|
||||
);
|
||||
let call_bb = build_poll_call(
|
||||
tcx,
|
||||
body,
|
||||
|
|
@ -357,16 +367,17 @@ pub(super) fn expand_async_drops<'tcx>(
|
|||
body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)),
|
||||
);
|
||||
let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
|
||||
let (pin_bb2, fut_pin_place2) =
|
||||
build_pin_fut(tcx, body, fut_place, UnwindAction::Continue);
|
||||
let drop_switch_block = build_poll_switch(
|
||||
tcx,
|
||||
body,
|
||||
poll_enum,
|
||||
&poll_unit_place,
|
||||
&fut_pin_place2,
|
||||
drop.unwrap(),
|
||||
drop_yield_block,
|
||||
);
|
||||
let (pin_bb2, fut_pin_place2) =
|
||||
build_pin_fut(tcx, body, fut_place, UnwindAction::Continue);
|
||||
let drop_call_bb = build_poll_call(
|
||||
tcx,
|
||||
body,
|
||||
|
|
|
|||
|
|
@ -390,6 +390,20 @@ where
|
|||
Location { block: self.succ, statement_index: 0 },
|
||||
StatementKind::StorageDead(fut.local),
|
||||
);
|
||||
// StorageDead(fut) in unwind block (at the begin)
|
||||
if let Unwind::To(block) = unwind {
|
||||
self.elaborator.patch().add_statement(
|
||||
Location { block, statement_index: 0 },
|
||||
StatementKind::StorageDead(fut.local),
|
||||
);
|
||||
}
|
||||
// StorageDead(fut) in dropline block (at the begin)
|
||||
if let Some(block) = dropline {
|
||||
self.elaborator.patch().add_statement(
|
||||
Location { block, statement_index: 0 },
|
||||
StatementKind::StorageDead(fut.local),
|
||||
);
|
||||
}
|
||||
|
||||
// #1:pin_obj_bb >>> call Pin<ObjTy>::new_unchecked(&mut obj)
|
||||
self.elaborator.patch().patch_terminator(
|
||||
|
|
|
|||
|
|
@ -60,11 +60,4 @@ monomorphize_start_not_found = using `fn main` requires the standard library
|
|||
|
||||
monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
|
||||
|
||||
monomorphize_wasm_c_abi_transition =
|
||||
this function {$is_call ->
|
||||
[true] call
|
||||
*[false] definition
|
||||
} involves an argument of type `{$ty}` which is affected by the wasm ABI transition
|
||||
.help = the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target
|
||||
|
||||
monomorphize_written_to_path = the full type name has been written to '{$path}'
|
||||
|
|
|
|||
|
|
@ -100,12 +100,3 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
|
|||
/// Whether this is a problem at a call site or at a declaration.
|
||||
pub is_call: bool,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(monomorphize_wasm_c_abi_transition)]
|
||||
#[help]
|
||||
pub(crate) struct WasmCAbiTransition<'a> {
|
||||
pub ty: Ty<'a>,
|
||||
/// Whether this is a problem at a call site or at a declaration.
|
||||
pub is_call: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,10 @@
|
|||
use rustc_abi::{BackendRepr, CanonAbi, RegKind, X86Call};
|
||||
use rustc_hir::{CRATE_HIR_ID, HirId};
|
||||
use rustc_middle::mir::{self, Location, traversal};
|
||||
use rustc_middle::ty::layout::LayoutCx;
|
||||
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv};
|
||||
use rustc_session::lint::builtin::WASM_C_ABI;
|
||||
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi};
|
||||
use rustc_target::callconv::{FnAbi, PassMode};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -81,73 +78,6 @@ fn do_check_simd_vector_abi<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Determines whether the given argument is passed the same way on the old and new wasm ABIs.
|
||||
fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool {
|
||||
if matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Both the old and the new ABIs treat vector types like `v128` the same
|
||||
// way.
|
||||
if uses_vector_registers(&arg.mode, &arg.layout.backend_repr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This matches `unwrap_trivial_aggregate` in the wasm ABI logic.
|
||||
if arg.layout.is_aggregate() {
|
||||
let cx = LayoutCx::new(tcx, TypingEnv::fully_monomorphized());
|
||||
if let Some(unit) = arg.layout.homogeneous_aggregate(&cx).ok().and_then(|ha| ha.unit()) {
|
||||
let size = arg.layout.size;
|
||||
// Ensure there's just a single `unit` element in `arg`.
|
||||
if unit.size == size {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zero-sized types are dropped in both ABIs, so they're safe
|
||||
if arg.layout.is_zst() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Warns against usage of `extern "C"` on wasm32-unknown-unknown that is affected by the
|
||||
/// ABI transition.
|
||||
fn do_check_wasm_abi<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
is_call: bool,
|
||||
loc: impl Fn() -> (Span, HirId),
|
||||
) {
|
||||
// Only proceed for `extern "C" fn` on wasm32-unknown-unknown (same check as what
|
||||
// `adjust_for_foreign_abi` uses to call `compute_wasm_abi_info`), and only proceed if
|
||||
// `wasm_c_abi_opt` indicates we should emit the lint.
|
||||
if !(tcx.sess.target.arch == "wasm32"
|
||||
&& tcx.sess.target.os == "unknown"
|
||||
&& tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true }
|
||||
&& abi.conv == CanonAbi::C)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Warn against all types whose ABI will change. Return values are not affected by this change.
|
||||
for arg_abi in abi.args.iter() {
|
||||
if wasm_abi_safe(tcx, arg_abi) {
|
||||
continue;
|
||||
}
|
||||
let (span, hir_id) = loc();
|
||||
tcx.emit_node_span_lint(
|
||||
WASM_C_ABI,
|
||||
hir_id,
|
||||
span,
|
||||
errors::WasmCAbiTransition { ty: arg_abi.layout.ty, is_call },
|
||||
);
|
||||
// Let's only warn once per function.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
|
||||
/// or return values for which the corresponding target feature is not enabled.
|
||||
fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
|
||||
|
|
@ -173,7 +103,6 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
|
|||
)
|
||||
};
|
||||
do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, loc);
|
||||
do_check_wasm_abi(tcx, abi, /*is_call*/ false, loc);
|
||||
}
|
||||
|
||||
/// Checks that a call expression does not try to pass a vector-passed argument which requires a
|
||||
|
|
@ -212,7 +141,6 @@ fn check_call_site_abi<'tcx>(
|
|||
return;
|
||||
};
|
||||
do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, loc);
|
||||
do_check_wasm_abi(tcx, callee_abi, /*is_call*/ true, loc);
|
||||
}
|
||||
|
||||
fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
|
||||
|
|
|
|||
|
|
@ -686,23 +686,34 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
if let token::DocComment(kind, style, _) = self.token.kind {
|
||||
// We have something like `expr //!val` where the user likely meant `expr // !val`
|
||||
let pos = self.token.span.lo() + BytePos(2);
|
||||
let span = self.token.span.with_lo(pos).with_hi(pos);
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"add a space before {} to write a regular comment",
|
||||
match (kind, style) {
|
||||
(token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
|
||||
(token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
|
||||
(token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
|
||||
(token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
|
||||
},
|
||||
),
|
||||
" ".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
// This is to avoid suggesting converting a doc comment to a regular comment
|
||||
// when missing a comma before the doc comment in lists (#142311):
|
||||
//
|
||||
// ```
|
||||
// enum Foo{
|
||||
// A /// xxxxxxx
|
||||
// B,
|
||||
// }
|
||||
// ```
|
||||
if !expected.contains(&TokenType::Comma) {
|
||||
// We have something like `expr //!val` where the user likely meant `expr // !val`
|
||||
let pos = self.token.span.lo() + BytePos(2);
|
||||
let span = self.token.span.with_lo(pos).with_hi(pos);
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
format!(
|
||||
"add a space before {} to write a regular comment",
|
||||
match (kind, style) {
|
||||
(token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
|
||||
(token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
|
||||
(token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
|
||||
(token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
|
||||
},
|
||||
),
|
||||
" ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let sp = if self.token == token::Eof {
|
||||
|
|
@ -2273,23 +2284,18 @@ impl<'a> Parser<'a> {
|
|||
),
|
||||
// Also catches `fn foo(&a)`.
|
||||
PatKind::Ref(ref inner_pat, mutab)
|
||||
if matches!(inner_pat.clone().kind, PatKind::Ident(..)) =>
|
||||
if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
|
||||
{
|
||||
match inner_pat.clone().kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
let mutab = mutab.prefix_str();
|
||||
(
|
||||
ident,
|
||||
"self: ",
|
||||
format!("{ident}: &{mutab}TypeName"),
|
||||
"_: ",
|
||||
pat.span.shrink_to_lo(),
|
||||
pat.span,
|
||||
pat.span.shrink_to_lo(),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let mutab = mutab.prefix_str();
|
||||
(
|
||||
ident,
|
||||
"self: ",
|
||||
format!("{ident}: &{mutab}TypeName"),
|
||||
"_: ",
|
||||
pat.span.shrink_to_lo(),
|
||||
pat.span,
|
||||
pat.span.shrink_to_lo(),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, try to get a type and emit a suggestion.
|
||||
|
|
|
|||
|
|
@ -147,6 +147,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::ConstStabilityIndirect
|
||||
| AttributeKind::MacroTransparency(_),
|
||||
) => { /* do nothing */ }
|
||||
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
|
||||
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Unparsed(_) => {
|
||||
match attr.path().as_slice() {
|
||||
[sym::diagnostic, sym::do_not_recommend, ..] => {
|
||||
|
|
@ -188,26 +191,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_rustc_std_internal_symbol(attr, span, target)
|
||||
}
|
||||
[sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
|
||||
[sym::rustc_as_ptr, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
}
|
||||
[sym::rustc_no_implicit_autorefs, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_never_returns_null_ptr, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_legacy_const_generics, ..] => {
|
||||
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
|
||||
}
|
||||
[sym::rustc_lint_query_instability, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_lint_untracked_query_information, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_lint_diagnostics, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
|
||||
[sym::rustc_lint_opt_deny_field_access, ..] => {
|
||||
|
|
@ -1825,15 +1825,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
fn check_applied_to_fn_or_method(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr: &Attribute,
|
||||
span: Span,
|
||||
attr_span: Span,
|
||||
defn_span: Span,
|
||||
target: Target,
|
||||
) {
|
||||
let is_function = matches!(target, Target::Fn | Target::Method(..));
|
||||
if !is_function {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span(),
|
||||
defn_span: span,
|
||||
attr_span,
|
||||
defn_span,
|
||||
on_crate: hir_id == CRATE_HIR_ID,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,24 +415,24 @@ pub(crate) enum AliasPossibility {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) enum PathSource<'a, 'c> {
|
||||
pub(crate) enum PathSource<'a, 'ast, 'ra> {
|
||||
/// Type paths `Path`.
|
||||
Type,
|
||||
/// Trait paths in bounds or impls.
|
||||
Trait(AliasPossibility),
|
||||
/// Expression paths `path`, with optional parent context.
|
||||
Expr(Option<&'a Expr>),
|
||||
Expr(Option<&'ast Expr>),
|
||||
/// Paths in path patterns `Path`.
|
||||
Pat,
|
||||
/// Paths in struct expressions and patterns `Path { .. }`.
|
||||
Struct,
|
||||
/// Paths in tuple struct patterns `Path(..)`.
|
||||
TupleStruct(Span, &'a [Span]),
|
||||
TupleStruct(Span, &'ra [Span]),
|
||||
/// `m::A::B` in `<T as m::A>::B::C`.
|
||||
///
|
||||
/// Second field holds the "cause" of this one, i.e. the context within
|
||||
/// which the trait item is resolved. Used for diagnostics.
|
||||
TraitItem(Namespace, &'c PathSource<'a, 'c>),
|
||||
TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
|
||||
/// Paths in delegation item
|
||||
Delegation,
|
||||
/// An arg in a `use<'a, N>` precise-capturing bound.
|
||||
|
|
@ -443,7 +443,7 @@ pub(crate) enum PathSource<'a, 'c> {
|
|||
DefineOpaques,
|
||||
}
|
||||
|
||||
impl<'a> PathSource<'a, '_> {
|
||||
impl PathSource<'_, '_, '_> {
|
||||
fn namespace(self) -> Namespace {
|
||||
match self {
|
||||
PathSource::Type
|
||||
|
|
@ -773,7 +773,7 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
|
||||
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
||||
impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
fn visit_attribute(&mut self, _: &'ast Attribute) {
|
||||
// We do not want to resolve expressions that appear in attributes,
|
||||
// as they do not correspond to actual code.
|
||||
|
|
@ -1462,7 +1462,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||
impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||
fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||
// During late resolution we only track the module component of the parent scope,
|
||||
// although it may be useful to track other components as well for diagnostics.
|
||||
|
|
@ -2010,7 +2010,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
partial_res: PartialRes,
|
||||
path: &[Segment],
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path_span: Span,
|
||||
) {
|
||||
let proj_start = path.len() - partial_res.unresolved_segments();
|
||||
|
|
@ -4161,7 +4161,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
id: NodeId,
|
||||
qself: &Option<P<QSelf>>,
|
||||
path: &Path,
|
||||
source: PathSource<'ast, '_>,
|
||||
source: PathSource<'_, 'ast, '_>,
|
||||
) {
|
||||
self.smart_resolve_path_fragment(
|
||||
qself,
|
||||
|
|
@ -4178,7 +4178,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
qself: &Option<P<QSelf>>,
|
||||
path: &[Segment],
|
||||
source: PathSource<'ast, '_>,
|
||||
source: PathSource<'_, 'ast, '_>,
|
||||
finalize: Finalize,
|
||||
record_partial_res: RecordPartialRes,
|
||||
parent_qself: Option<&QSelf>,
|
||||
|
|
@ -4482,7 +4482,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
span: Span,
|
||||
defer_to_typeck: bool,
|
||||
finalize: Finalize,
|
||||
source: PathSource<'ast, '_>,
|
||||
source: PathSource<'_, 'ast, '_>,
|
||||
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
||||
let mut fin_res = None;
|
||||
|
||||
|
|
@ -4525,7 +4525,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
path: &[Segment],
|
||||
ns: Namespace,
|
||||
finalize: Finalize,
|
||||
source: PathSource<'ast, '_>,
|
||||
source: PathSource<'_, 'ast, '_>,
|
||||
) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
|
||||
debug!(
|
||||
"resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
|
||||
|
|
|
|||
|
|
@ -170,12 +170,12 @@ impl TypoCandidate {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||
fn make_base_error(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
res: Option<Res>,
|
||||
) -> BaseError {
|
||||
// Make the base error.
|
||||
|
|
@ -421,7 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
path: &[Segment],
|
||||
following_seg: Option<&Segment>,
|
||||
span: Span,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
res: Option<Res>,
|
||||
qself: Option<&QSelf>,
|
||||
) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
|
||||
|
|
@ -539,7 +539,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
path: &[Segment],
|
||||
following_seg: Option<&Segment>,
|
||||
span: Span,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
res: Option<Res>,
|
||||
qself: Option<&QSelf>,
|
||||
) {
|
||||
|
|
@ -650,7 +650,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn try_lookup_name_relaxed(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
following_seg: Option<&Segment>,
|
||||
span: Span,
|
||||
|
|
@ -940,7 +940,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_trait_and_bounds(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
res: Option<Res>,
|
||||
span: Span,
|
||||
base_error: &BaseError,
|
||||
|
|
@ -1017,7 +1017,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_typo(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
following_seg: Option<&Segment>,
|
||||
span: Span,
|
||||
|
|
@ -1063,7 +1063,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_shadowed(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
following_seg: Option<&Segment>,
|
||||
span: Span,
|
||||
|
|
@ -1096,7 +1096,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn err_code_special_cases(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
) {
|
||||
|
|
@ -1141,7 +1141,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_self_ty(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
) -> bool {
|
||||
|
|
@ -1164,7 +1164,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_self_value(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
span: Span,
|
||||
) -> bool {
|
||||
|
|
@ -1332,7 +1332,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_swapping_misplaced_self_ty_and_trait(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
res: Option<Res>,
|
||||
span: Span,
|
||||
) {
|
||||
|
|
@ -1361,7 +1361,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
res: Option<Res>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
) {
|
||||
let PathSource::TupleStruct(_, _) = source else { return };
|
||||
let Some(Res::Def(DefKind::Fn, _)) = res else { return };
|
||||
|
|
@ -1373,7 +1373,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
res: Option<Res>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
span: Span,
|
||||
) {
|
||||
let PathSource::Trait(_) = source else { return };
|
||||
|
|
@ -1422,7 +1422,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_pattern_match_with_let(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
if let PathSource::Expr(_) = source
|
||||
|
|
@ -1448,7 +1448,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn get_single_associated_item(
|
||||
&mut self,
|
||||
path: &[Segment],
|
||||
source: &PathSource<'_, '_>,
|
||||
source: &PathSource<'_, '_, '_>,
|
||||
filter_fn: &impl Fn(Res) -> bool,
|
||||
) -> Option<TypoSuggestion> {
|
||||
if let crate::PathSource::TraitItem(_, _) = source {
|
||||
|
|
@ -1556,7 +1556,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
|
||||
/// Check if the source is call expression and the first argument is `self`. If true,
|
||||
/// return the span of whole call and the span for all arguments expect the first one (`self`).
|
||||
fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option<Span>)> {
|
||||
fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> {
|
||||
let mut has_self_arg = None;
|
||||
if let PathSource::Expr(Some(parent)) = source
|
||||
&& let ExprKind::Call(_, args) = &parent.kind
|
||||
|
|
@ -1614,7 +1614,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
path: &[Segment],
|
||||
res: Res,
|
||||
path_str: &str,
|
||||
|
|
@ -1666,7 +1666,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| {
|
||||
let find_span = |source: &PathSource<'_, '_, '_>, err: &mut Diag<'_>| {
|
||||
match source {
|
||||
PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
|
||||
| PathSource::TupleStruct(span, _) => {
|
||||
|
|
@ -2699,7 +2699,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
fn suggest_using_enum_variant(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
def_id: DefId,
|
||||
span: Span,
|
||||
) {
|
||||
|
|
@ -2877,7 +2877,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
pub(crate) fn suggest_adding_generic_parameter(
|
||||
&self,
|
||||
path: &[Segment],
|
||||
source: PathSource<'_, '_>,
|
||||
source: PathSource<'_, '_, '_>,
|
||||
) -> Option<(Span, &'static str, String, Applicability)> {
|
||||
let (ident, span) = match path {
|
||||
[segment]
|
||||
|
|
|
|||
|
|
@ -3066,7 +3066,7 @@ pub(crate) mod dep_tracking {
|
|||
use rustc_target::spec::{
|
||||
CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
|
||||
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
|
||||
TlsModel, WasmCAbi,
|
||||
TlsModel,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -3177,7 +3177,6 @@ pub(crate) mod dep_tracking {
|
|||
Polonius,
|
||||
InliningThreshold,
|
||||
FunctionReturn,
|
||||
WasmCAbi,
|
||||
Align,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_span::{RealFileName, SourceFileHashAlgorithm};
|
|||
use rustc_target::spec::{
|
||||
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
|
||||
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
|
||||
TargetTuple, TlsModel, WasmCAbi,
|
||||
TargetTuple, TlsModel,
|
||||
};
|
||||
|
||||
use crate::config::*;
|
||||
|
|
@ -802,7 +802,6 @@ mod desc {
|
|||
"either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
|
||||
pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
|
||||
pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
|
||||
pub(crate) const parse_wasm_c_abi: &str = "`legacy` or `spec`";
|
||||
pub(crate) const parse_mir_include_spans: &str =
|
||||
"either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
|
||||
pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
|
||||
|
|
@ -1898,16 +1897,6 @@ pub mod parse {
|
|||
true
|
||||
}
|
||||
|
||||
pub(crate) fn parse_wasm_c_abi(slot: &mut WasmCAbi, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("spec") => *slot = WasmCAbi::Spec,
|
||||
// Explicitly setting the `-Z` flag suppresses the lint.
|
||||
Some("legacy") => *slot = WasmCAbi::Legacy { with_lint: false },
|
||||
_ => return false,
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool {
|
||||
*slot = match v {
|
||||
Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On,
|
||||
|
|
@ -2642,8 +2631,6 @@ written to standard error output)"),
|
|||
Requires `-Clto[=[fat,yes]]`"),
|
||||
wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
|
||||
"whether to build a wasi command or reactor"),
|
||||
wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy { with_lint: true }, parse_wasm_c_abi, [TRACKED],
|
||||
"use spec-compliant C ABI for `wasm32-unknown-unknown` (default: legacy)"),
|
||||
write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED],
|
||||
"whether long type names should be written to files instead of being printed in errors"),
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -215,13 +215,6 @@ pub struct Session {
|
|||
pub invocation_temp: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum MetadataKind {
|
||||
None,
|
||||
Uncompressed,
|
||||
Compressed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CodegenUnits {
|
||||
/// Specified by the user. In this case we try fairly hard to produce the
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ use rustc_middle::ty::layout::{
|
|||
};
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{
|
||||
GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
|
||||
CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt,
|
||||
ValTree,
|
||||
};
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
|
|
@ -22,9 +23,9 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
|||
use stable_mir::mir::{BinOp, Body, Place, UnOp};
|
||||
use stable_mir::target::{MachineInfo, MachineSize};
|
||||
use stable_mir::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef,
|
||||
ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, Ty,
|
||||
TyConst, TyKind, UintTy, VariantDef,
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
|
||||
ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy,
|
||||
Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx,
|
||||
};
|
||||
use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
|
||||
|
||||
|
|
@ -447,6 +448,30 @@ impl<'tcx> SmirCtxt<'tcx> {
|
|||
def.internal(&mut *tables, tcx).variants().len()
|
||||
}
|
||||
|
||||
/// Discriminant for a given variant index of AdtDef
|
||||
pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let adt = adt.internal(&mut *tables, tcx);
|
||||
let variant = variant.internal(&mut *tables, tcx);
|
||||
adt.discriminant_for_variant(tcx, variant).stable(&mut *tables)
|
||||
}
|
||||
|
||||
/// Discriminant for a given variand index and args of a coroutine
|
||||
pub fn coroutine_discr_for_variant(
|
||||
&self,
|
||||
coroutine: CoroutineDef,
|
||||
args: &GenericArgs,
|
||||
variant: VariantIdx,
|
||||
) -> Discr {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let coroutine = coroutine.def_id().internal(&mut *tables, tcx);
|
||||
let args = args.internal(&mut *tables, tcx);
|
||||
let variant = variant.internal(&mut *tables, tcx);
|
||||
args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables)
|
||||
}
|
||||
|
||||
/// The name of a variant.
|
||||
pub fn variant_name(&self, def: VariantDef) -> Symbol {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
|
|
|
|||
|
|
@ -960,3 +960,11 @@ impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> {
|
||||
type T = stable_mir::ty::Discr;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef};
|
|||
use stable_mir::mir::{BinOp, Body, Place, UnOp};
|
||||
use stable_mir::target::MachineInfo;
|
||||
use stable_mir::ty::{
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef,
|
||||
ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
|
||||
ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl,
|
||||
TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef,
|
||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
|
||||
ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
|
||||
Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
|
||||
TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
|
||||
};
|
||||
use stable_mir::{
|
||||
AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls,
|
||||
|
|
@ -230,6 +230,21 @@ impl<'tcx> SmirInterface<'tcx> {
|
|||
self.cx.adt_variants_len(def)
|
||||
}
|
||||
|
||||
/// Discriminant for a given variant index of AdtDef
|
||||
pub(crate) fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
|
||||
self.cx.adt_discr_for_variant(adt, variant)
|
||||
}
|
||||
|
||||
/// Discriminant for a given variand index and args of a coroutine
|
||||
pub(crate) fn coroutine_discr_for_variant(
|
||||
&self,
|
||||
coroutine: CoroutineDef,
|
||||
args: &GenericArgs,
|
||||
variant: VariantIdx,
|
||||
) -> Discr {
|
||||
self.cx.coroutine_discr_for_variant(coroutine, args, variant)
|
||||
}
|
||||
|
||||
/// The name of a variant.
|
||||
pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol {
|
||||
self.cx.variant_name(def)
|
||||
|
|
|
|||
|
|
@ -756,6 +756,12 @@ crate_def! {
|
|||
pub CoroutineDef;
|
||||
}
|
||||
|
||||
impl CoroutineDef {
|
||||
pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr {
|
||||
with(|cx| cx.coroutine_discr_for_variant(*self, args, idx))
|
||||
}
|
||||
}
|
||||
|
||||
crate_def! {
|
||||
#[derive(Serialize)]
|
||||
pub CoroutineClosureDef;
|
||||
|
|
@ -831,6 +837,15 @@ impl AdtDef {
|
|||
pub fn repr(&self) -> ReprOptions {
|
||||
with(|cx| cx.adt_repr(*self))
|
||||
}
|
||||
|
||||
pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr {
|
||||
with(|cx| cx.adt_discr_for_variant(*self, idx))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Discr {
|
||||
pub val: u128,
|
||||
pub ty: Ty,
|
||||
}
|
||||
|
||||
/// Definition of a variant, which can be either a struct / union field or an enum variant.
|
||||
|
|
|
|||
|
|
@ -37,9 +37,11 @@ impl LoongArchInlineAsmRegClass {
|
|||
arch: InlineAsmArch,
|
||||
) -> &'static [(InlineAsmType, Option<Symbol>)] {
|
||||
match (self, arch) {
|
||||
(Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
|
||||
(Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; },
|
||||
(Self::freg, _) => types! { f: F32; d: F64; },
|
||||
(Self::reg, InlineAsmArch::LoongArch64) => {
|
||||
types! { _: I8, I16, I32, I64, F16, F32, F64; }
|
||||
}
|
||||
(Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F16, F32; },
|
||||
(Self::freg, _) => types! { f: F16, F32; d: F64; },
|
||||
_ => unreachable!("unsupported register class"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ use rustc_abi::{
|
|||
BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
|
||||
};
|
||||
|
||||
use crate::callconv::{
|
||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Uniform,
|
||||
};
|
||||
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
|
||||
|
||||
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
|
||||
// Always sign extend u32 values on 64-bit mips
|
||||
|
|
@ -140,16 +138,7 @@ where
|
|||
|
||||
// Extract first 8 chunks as the prefix
|
||||
let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
|
||||
arg.cast_to(CastTarget {
|
||||
prefix,
|
||||
rest: Uniform::new(Reg::i64(), rest_size),
|
||||
attrs: ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
},
|
||||
});
|
||||
arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)));
|
||||
}
|
||||
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_abi::{
|
|||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
pub use crate::spec::AbiMap;
|
||||
use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
|
||||
use crate::spec::{HasTargetSpec, HasX86AbiOpt};
|
||||
|
||||
mod aarch64;
|
||||
mod amdgpu;
|
||||
|
|
@ -197,6 +197,17 @@ impl ArgAttributes {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ArgAttribute> for ArgAttributes {
|
||||
fn from(value: ArgAttribute) -> Self {
|
||||
Self {
|
||||
regular: value,
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An argument passed entirely registers with the
|
||||
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
|
|
@ -251,6 +262,9 @@ impl Uniform {
|
|||
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct CastTarget {
|
||||
pub prefix: [Option<Reg>; 8],
|
||||
/// The offset of `rest` from the start of the value. Currently only implemented for a `Reg`
|
||||
/// pair created by the `offset_pair` method.
|
||||
pub rest_offset: Option<Size>,
|
||||
pub rest: Uniform,
|
||||
pub attrs: ArgAttributes,
|
||||
}
|
||||
|
|
@ -263,42 +277,45 @@ impl From<Reg> for CastTarget {
|
|||
|
||||
impl From<Uniform> for CastTarget {
|
||||
fn from(uniform: Uniform) -> CastTarget {
|
||||
CastTarget {
|
||||
prefix: [None; 8],
|
||||
rest: uniform,
|
||||
attrs: ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
},
|
||||
}
|
||||
Self::prefixed([None; 8], uniform)
|
||||
}
|
||||
}
|
||||
|
||||
impl CastTarget {
|
||||
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
||||
CastTarget {
|
||||
pub fn prefixed(prefix: [Option<Reg>; 8], rest: Uniform) -> Self {
|
||||
Self { prefix, rest_offset: None, rest, attrs: ArgAttributes::new() }
|
||||
}
|
||||
|
||||
pub fn offset_pair(a: Reg, offset_from_start: Size, b: Reg) -> Self {
|
||||
Self {
|
||||
prefix: [Some(a), None, None, None, None, None, None, None],
|
||||
rest: Uniform::from(b),
|
||||
attrs: ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
},
|
||||
rest_offset: Some(offset_from_start),
|
||||
rest: b.into(),
|
||||
attrs: ArgAttributes::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_attrs(mut self, attrs: ArgAttributes) -> Self {
|
||||
self.attrs = attrs;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn pair(a: Reg, b: Reg) -> CastTarget {
|
||||
Self::prefixed([Some(a), None, None, None, None, None, None, None], Uniform::from(b))
|
||||
}
|
||||
|
||||
/// When you only access the range containing valid data, you can use this unaligned size;
|
||||
/// otherwise, use the safer `size` method.
|
||||
pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
|
||||
// Prefix arguments are passed in specific designated registers
|
||||
let prefix_size = self
|
||||
.prefix
|
||||
.iter()
|
||||
.filter_map(|x| x.map(|reg| reg.size))
|
||||
.fold(Size::ZERO, |acc, size| acc + size);
|
||||
let prefix_size = if let Some(offset_from_start) = self.rest_offset {
|
||||
offset_from_start
|
||||
} else {
|
||||
self.prefix
|
||||
.iter()
|
||||
.filter_map(|x| x.map(|reg| reg.size))
|
||||
.fold(Size::ZERO, |acc, size| acc + size)
|
||||
};
|
||||
// Remaining arguments are passed in chunks of the unit size
|
||||
let rest_size =
|
||||
self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
|
||||
|
|
@ -322,9 +339,22 @@ impl CastTarget {
|
|||
/// Checks if these two `CastTarget` are equal enough to be considered "the same for all
|
||||
/// function call ABIs".
|
||||
pub fn eq_abi(&self, other: &Self) -> bool {
|
||||
let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self;
|
||||
let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other;
|
||||
prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r)
|
||||
let CastTarget {
|
||||
prefix: prefix_l,
|
||||
rest_offset: rest_offset_l,
|
||||
rest: rest_l,
|
||||
attrs: attrs_l,
|
||||
} = self;
|
||||
let CastTarget {
|
||||
prefix: prefix_r,
|
||||
rest_offset: rest_offset_r,
|
||||
rest: rest_r,
|
||||
attrs: attrs_r,
|
||||
} = other;
|
||||
prefix_l == prefix_r
|
||||
&& rest_offset_l == rest_offset_r
|
||||
&& rest_l == rest_r
|
||||
&& attrs_l.eq_abi(attrs_r)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -593,7 +623,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
pub fn adjust_for_foreign_abi<C>(&mut self, cx: &C, abi: ExternAbi)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
|
||||
C: HasDataLayout + HasTargetSpec + HasX86AbiOpt,
|
||||
{
|
||||
if abi == ExternAbi::X86Interrupt {
|
||||
if let Some(arg) = self.args.first_mut() {
|
||||
|
|
@ -669,14 +699,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
|||
"hexagon" => hexagon::compute_abi_info(self),
|
||||
"xtensa" => xtensa::compute_abi_info(cx, self),
|
||||
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
|
||||
"wasm32" => {
|
||||
if spec.os == "unknown" && matches!(cx.wasm_c_abi_opt(), WasmCAbi::Legacy { .. }) {
|
||||
wasm::compute_wasm_abi_info(self)
|
||||
} else {
|
||||
wasm::compute_c_abi_info(cx, self)
|
||||
}
|
||||
}
|
||||
"wasm64" => wasm::compute_c_abi_info(cx, self),
|
||||
"wasm32" | "wasm64" => wasm::compute_abi_info(cx, self),
|
||||
"bpf" => bpf::compute_abi_info(self),
|
||||
arch => panic!("no lowering implemented for {arch}"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
|
||||
|
||||
use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
|
||||
use super::CastTarget;
|
||||
use crate::callconv::{ArgAbi, FnAbi, Uniform};
|
||||
|
||||
fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
|
|
@ -34,16 +34,10 @@ fn classify_aggregate<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
|||
};
|
||||
|
||||
if align_bytes == size.bytes() {
|
||||
arg.cast_to(CastTarget {
|
||||
prefix: [Some(reg), None, None, None, None, None, None, None],
|
||||
rest: Uniform::new(Reg::i8(), Size::from_bytes(0)),
|
||||
attrs: ArgAttributes {
|
||||
regular: ArgAttribute::default(),
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
},
|
||||
});
|
||||
arg.cast_to(CastTarget::prefixed(
|
||||
[Some(reg), None, None, None, None, None, None, None],
|
||||
Uniform::new(Reg::i8(), Size::ZERO),
|
||||
));
|
||||
} else {
|
||||
arg.cast_to(Uniform::new(reg, size));
|
||||
}
|
||||
|
|
@ -78,11 +72,10 @@ where
|
|||
};
|
||||
if arg.layout.size.bytes() / align_bytes == 1 {
|
||||
// Make sure we pass the struct as array at the LLVM IR level and not as a single integer.
|
||||
arg.cast_to(CastTarget {
|
||||
prefix: [Some(unit), None, None, None, None, None, None, None],
|
||||
rest: Uniform::new(unit, Size::ZERO),
|
||||
attrs: ArgAttributes::new(),
|
||||
});
|
||||
arg.cast_to(CastTarget::prefixed(
|
||||
[Some(unit), None, None, None, None, None, None, None],
|
||||
Uniform::new(unit, Size::ZERO),
|
||||
));
|
||||
} else {
|
||||
arg.cast_to(Uniform::new(unit, arg.layout.size));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@ use crate::spec::HasTargetSpec;
|
|||
|
||||
#[derive(Copy, Clone)]
|
||||
enum RegPassKind {
|
||||
Float(Reg),
|
||||
Integer(Reg),
|
||||
Float { offset_from_start: Size, ty: Reg },
|
||||
Integer { offset_from_start: Size, ty: Reg },
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum FloatConv {
|
||||
FloatPair(Reg, Reg),
|
||||
FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
|
||||
Float(Reg),
|
||||
MixedPair(Reg, Reg),
|
||||
MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -43,6 +43,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
|
|||
flen: u64,
|
||||
field1_kind: &mut RegPassKind,
|
||||
field2_kind: &mut RegPassKind,
|
||||
offset_from_start: Size,
|
||||
) -> Result<(), CannotUseFpConv>
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
|
|
@ -55,16 +56,16 @@ where
|
|||
}
|
||||
match (*field1_kind, *field2_kind) {
|
||||
(RegPassKind::Unknown, _) => {
|
||||
*field1_kind = RegPassKind::Integer(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: arg_layout.size,
|
||||
});
|
||||
*field1_kind = RegPassKind::Integer {
|
||||
offset_from_start,
|
||||
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
|
||||
};
|
||||
}
|
||||
(RegPassKind::Float(_), RegPassKind::Unknown) => {
|
||||
*field2_kind = RegPassKind::Integer(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: arg_layout.size,
|
||||
});
|
||||
(RegPassKind::Float { .. }, RegPassKind::Unknown) => {
|
||||
*field2_kind = RegPassKind::Integer {
|
||||
offset_from_start,
|
||||
ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
|
||||
};
|
||||
}
|
||||
_ => return Err(CannotUseFpConv),
|
||||
}
|
||||
|
|
@ -75,12 +76,16 @@ where
|
|||
}
|
||||
match (*field1_kind, *field2_kind) {
|
||||
(RegPassKind::Unknown, _) => {
|
||||
*field1_kind =
|
||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
||||
*field1_kind = RegPassKind::Float {
|
||||
offset_from_start,
|
||||
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
|
||||
};
|
||||
}
|
||||
(_, RegPassKind::Unknown) => {
|
||||
*field2_kind =
|
||||
RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
|
||||
*field2_kind = RegPassKind::Float {
|
||||
offset_from_start,
|
||||
ty: Reg { kind: RegKind::Float, size: arg_layout.size },
|
||||
};
|
||||
}
|
||||
_ => return Err(CannotUseFpConv),
|
||||
}
|
||||
|
|
@ -102,13 +107,14 @@ where
|
|||
flen,
|
||||
field1_kind,
|
||||
field2_kind,
|
||||
offset_from_start,
|
||||
);
|
||||
}
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
}
|
||||
FieldsShape::Array { count, .. } => {
|
||||
for _ in 0..count {
|
||||
for i in 0..count {
|
||||
let elem_layout = arg_layout.field(cx, 0);
|
||||
should_use_fp_conv_helper(
|
||||
cx,
|
||||
|
|
@ -117,6 +123,7 @@ where
|
|||
flen,
|
||||
field1_kind,
|
||||
field2_kind,
|
||||
offset_from_start + elem_layout.size * i,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +134,15 @@ where
|
|||
}
|
||||
for i in arg_layout.fields.index_by_increasing_offset() {
|
||||
let field = arg_layout.field(cx, i);
|
||||
should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
|
||||
should_use_fp_conv_helper(
|
||||
cx,
|
||||
&field,
|
||||
xlen,
|
||||
flen,
|
||||
field1_kind,
|
||||
field2_kind,
|
||||
offset_from_start + arg_layout.fields.offset(i),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -146,14 +161,52 @@ where
|
|||
{
|
||||
let mut field1_kind = RegPassKind::Unknown;
|
||||
let mut field2_kind = RegPassKind::Unknown;
|
||||
if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
|
||||
if should_use_fp_conv_helper(
|
||||
cx,
|
||||
arg,
|
||||
xlen,
|
||||
flen,
|
||||
&mut field1_kind,
|
||||
&mut field2_kind,
|
||||
Size::ZERO,
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
match (field1_kind, field2_kind) {
|
||||
(RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
|
||||
(RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
|
||||
(RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
|
||||
(RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
|
||||
(
|
||||
RegPassKind::Integer { offset_from_start, .. }
|
||||
| RegPassKind::Float { offset_from_start, .. },
|
||||
_,
|
||||
) if offset_from_start != Size::ZERO => {
|
||||
panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty)
|
||||
}
|
||||
(
|
||||
RegPassKind::Integer { ty: first_ty, .. },
|
||||
RegPassKind::Float { offset_from_start, ty: second_ty },
|
||||
) => Some(FloatConv::MixedPair {
|
||||
first_ty,
|
||||
second_ty_offset_from_start: offset_from_start,
|
||||
second_ty,
|
||||
}),
|
||||
(
|
||||
RegPassKind::Float { ty: first_ty, .. },
|
||||
RegPassKind::Integer { offset_from_start, ty: second_ty },
|
||||
) => Some(FloatConv::MixedPair {
|
||||
first_ty,
|
||||
second_ty_offset_from_start: offset_from_start,
|
||||
second_ty,
|
||||
}),
|
||||
(
|
||||
RegPassKind::Float { ty: first_ty, .. },
|
||||
RegPassKind::Float { offset_from_start, ty: second_ty },
|
||||
) => Some(FloatConv::FloatPair {
|
||||
first_ty,
|
||||
second_ty_offset_from_start: offset_from_start,
|
||||
second_ty,
|
||||
}),
|
||||
(RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -171,11 +224,19 @@ where
|
|||
FloatConv::Float(f) => {
|
||||
arg.cast_to(f);
|
||||
}
|
||||
FloatConv::FloatPair(l, r) => {
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => {
|
||||
arg.cast_to(CastTarget::offset_pair(
|
||||
first_ty,
|
||||
second_ty_offset_from_start,
|
||||
second_ty,
|
||||
));
|
||||
}
|
||||
FloatConv::MixedPair(l, r) => {
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => {
|
||||
arg.cast_to(CastTarget::offset_pair(
|
||||
first_ty,
|
||||
second_ty_offset_from_start,
|
||||
second_ty,
|
||||
));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -239,15 +300,27 @@ fn classify_arg<'a, Ty, C>(
|
|||
arg.cast_to(f);
|
||||
return;
|
||||
}
|
||||
Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
|
||||
Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty })
|
||||
if *avail_fprs >= 2 =>
|
||||
{
|
||||
*avail_fprs -= 2;
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
arg.cast_to(CastTarget::offset_pair(
|
||||
first_ty,
|
||||
second_ty_offset_from_start,
|
||||
second_ty,
|
||||
));
|
||||
return;
|
||||
}
|
||||
Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
|
||||
Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty })
|
||||
if *avail_fprs >= 1 && *avail_gprs >= 1 =>
|
||||
{
|
||||
*avail_gprs -= 1;
|
||||
*avail_fprs -= 1;
|
||||
arg.cast_to(CastTarget::pair(l, r));
|
||||
arg.cast_to(CastTarget::offset_pair(
|
||||
first_ty,
|
||||
second_ty_offset_from_start,
|
||||
second_ty,
|
||||
));
|
||||
return;
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ use rustc_abi::{
|
|||
TyAndLayout,
|
||||
};
|
||||
|
||||
use crate::callconv::{
|
||||
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Uniform,
|
||||
};
|
||||
use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -197,16 +195,10 @@ where
|
|||
rest_size = rest_size - Reg::i32().size;
|
||||
}
|
||||
|
||||
arg.cast_to(CastTarget {
|
||||
prefix: data.prefix,
|
||||
rest: Uniform::new(Reg::i64(), rest_size),
|
||||
attrs: ArgAttributes {
|
||||
regular: data.arg_attribute,
|
||||
arg_ext: ArgExtension::None,
|
||||
pointee_size: Size::ZERO,
|
||||
pointee_align: None,
|
||||
},
|
||||
});
|
||||
arg.cast_to(
|
||||
CastTarget::prefixed(data.prefix, Uniform::new(Reg::i64(), rest_size))
|
||||
.with_attrs(data.arg_attribute.into()),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ where
|
|||
}
|
||||
|
||||
/// The purpose of this ABI is to match the C ABI (aka clang) exactly.
|
||||
pub(crate) fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
|
|
@ -75,43 +75,3 @@ where
|
|||
classify_arg(cx, arg);
|
||||
}
|
||||
}
|
||||
|
||||
/// The purpose of this ABI is for matching the WebAssembly standard. This
|
||||
/// intentionally diverges from the C ABI and is specifically crafted to take
|
||||
/// advantage of LLVM's support of multiple returns in WebAssembly.
|
||||
///
|
||||
/// This ABI is *bad*! It uses `PassMode::Direct` for `abi::Aggregate` types, which leaks LLVM
|
||||
/// implementation details into the ABI. It's just hard to fix because ABIs are hard to change.
|
||||
/// Also see <https://github.com/rust-lang/rust/issues/115666>.
|
||||
pub(crate) fn compute_wasm_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
classify_ret_wasm_abi(&mut fn_abi.ret);
|
||||
}
|
||||
|
||||
for arg in fn_abi.args.iter_mut() {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
classify_arg_wasm_abi(arg);
|
||||
}
|
||||
|
||||
fn classify_ret_wasm_abi<Ty>(ret: &mut ArgAbi<'_, Ty>) {
|
||||
if !ret.layout.is_sized() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
// FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666
|
||||
ret.make_direct_deprecated();
|
||||
ret.extend_integer_width_to(32);
|
||||
}
|
||||
|
||||
fn classify_arg_wasm_abi<Ty>(arg: &mut ArgAbi<'_, Ty>) {
|
||||
if !arg.layout.is_sized() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
// FIXME: this is bad! https://github.com/rust-lang/rust/issues/115666
|
||||
arg.make_direct_deprecated();
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_abi::{
|
|||
};
|
||||
|
||||
use crate::callconv::{ArgAbi, CastTarget, FnAbi};
|
||||
use crate::spec::HasTargetSpec;
|
||||
|
||||
/// Classification of "eightbyte" components.
|
||||
// N.B., the order of the variants is from general to specific,
|
||||
|
|
@ -175,7 +176,7 @@ const MAX_SSE_REGS: usize = 8; // XMM0-7
|
|||
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
let mut int_regs = MAX_INT_REGS;
|
||||
let mut sse_regs = MAX_SSE_REGS;
|
||||
|
|
@ -236,7 +237,7 @@ where
|
|||
if arg.layout.is_aggregate() {
|
||||
let size = arg.layout.size;
|
||||
arg.cast_to(cast_target(cls, size));
|
||||
} else {
|
||||
} else if is_arg || cx.target_spec().is_like_darwin {
|
||||
arg.extend_integer_width_to(32);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2233,22 +2233,6 @@ impl HasTargetSpec for Target {
|
|||
}
|
||||
}
|
||||
|
||||
/// Which C ABI to use for `wasm32-unknown-unknown`.
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub enum WasmCAbi {
|
||||
/// Spec-compliant C ABI.
|
||||
Spec,
|
||||
/// Legacy ABI. Which is non-spec-compliant.
|
||||
Legacy {
|
||||
/// Indicates whether the `wasm_c_abi` lint should be emitted.
|
||||
with_lint: bool,
|
||||
},
|
||||
}
|
||||
|
||||
pub trait HasWasmCAbiOpt {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi;
|
||||
}
|
||||
|
||||
/// x86 (32-bit) abi options.
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct X86Abi {
|
||||
|
|
|
|||
|
|
@ -403,28 +403,18 @@ fn fn_abi_sanity_check<'tcx>(
|
|||
// For an unsized type we'd only pass the sized prefix, so there is no universe
|
||||
// in which we ever want to allow this.
|
||||
assert!(sized, "`PassMode::Direct` for unsized type in ABI: {:#?}", fn_abi);
|
||||
|
||||
// This really shouldn't happen even for sized aggregates, since
|
||||
// `immediate_llvm_type` will use `layout.fields` to turn this Rust type into an
|
||||
// LLVM type. This means all sorts of Rust type details leak into the ABI.
|
||||
// However wasm sadly *does* currently use this mode for it's "C" ABI so we
|
||||
// have to allow it -- but we absolutely shouldn't let any more targets do
|
||||
// that. (Also see <https://github.com/rust-lang/rust/issues/115666>.)
|
||||
//
|
||||
// The unadjusted ABI also uses Direct for all args and is ill-specified,
|
||||
// The unadjusted ABI however uses Direct for all args. It is ill-specified,
|
||||
// but unfortunately we need it for calling certain LLVM intrinsics.
|
||||
|
||||
match spec_abi {
|
||||
ExternAbi::Unadjusted => {}
|
||||
ExternAbi::C { unwind: _ }
|
||||
if matches!(&*tcx.sess.target.arch, "wasm32" | "wasm64") => {}
|
||||
_ => {
|
||||
panic!(
|
||||
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\" functions and on wasm\n\
|
||||
Problematic type: {:#?}",
|
||||
arg.layout,
|
||||
);
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
matches!(spec_abi, ExternAbi::Unadjusted),
|
||||
"`PassMode::Direct` for aggregates only allowed for \"unadjusted\"\n\
|
||||
Problematic type: {:#?}",
|
||||
arg.layout,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -842,9 +842,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
/// evaluating this entry would not have ended up depending on either a goal
|
||||
/// already on the stack or a provisional cache entry.
|
||||
fn candidate_is_applicable(
|
||||
stack: &Stack<X>,
|
||||
&self,
|
||||
step_kind_from_parent: PathKind,
|
||||
provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
|
||||
nested_goals: &NestedGoals<X>,
|
||||
) -> bool {
|
||||
// If the global cache entry didn't depend on any nested goals, it always
|
||||
|
|
@ -855,7 +854,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
|
||||
// If a nested goal of the global cache entry is on the stack, we would
|
||||
// definitely encounter a cycle.
|
||||
if stack.iter().any(|e| nested_goals.contains(e.input)) {
|
||||
if self.stack.iter().any(|e| nested_goals.contains(e.input)) {
|
||||
debug!("cache entry not applicable due to stack");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -864,7 +863,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
// would apply for any of its nested goals.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (input, path_from_global_entry) in nested_goals.iter() {
|
||||
let Some(entries) = provisional_cache.get(&input) else {
|
||||
let Some(entries) = self.provisional_cache.get(&input) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -890,7 +889,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
// We check if any of the paths taken while computing the global goal
|
||||
// would end up with an applicable provisional cache entry.
|
||||
let head = heads.highest_cycle_head();
|
||||
let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
|
||||
let head_to_curr = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head);
|
||||
let full_paths = path_from_global_entry.extend_with(head_to_curr);
|
||||
if full_paths.contains(head_to_provisional.into()) {
|
||||
debug!(
|
||||
|
|
@ -918,12 +917,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
cx.with_global_cache(|cache| {
|
||||
cache
|
||||
.get(cx, input, available_depth, |nested_goals| {
|
||||
Self::candidate_is_applicable(
|
||||
&self.stack,
|
||||
step_kind_from_parent,
|
||||
&self.provisional_cache,
|
||||
nested_goals,
|
||||
)
|
||||
self.candidate_is_applicable(step_kind_from_parent, nested_goals)
|
||||
})
|
||||
.map(|c| c.result)
|
||||
})
|
||||
|
|
@ -942,12 +936,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
|
|||
cx.with_global_cache(|cache| {
|
||||
let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
|
||||
.get(cx, input, available_depth, |nested_goals| {
|
||||
Self::candidate_is_applicable(
|
||||
&self.stack,
|
||||
step_kind_from_parent,
|
||||
&self.provisional_cache,
|
||||
nested_goals,
|
||||
)
|
||||
self.candidate_is_applicable(step_kind_from_parent, nested_goals)
|
||||
})?;
|
||||
|
||||
// We don't move cycle participants to the global cache, so the
|
||||
|
|
|
|||
|
|
@ -236,6 +236,14 @@ pub struct ExternalConstraintsData<I: Interner> {
|
|||
pub normalization_nested_goals: NestedNormalizationGoals<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner> ExternalConstraintsData<I> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.region_constraints.is_empty()
|
||||
&& self.opaque_types.is_empty()
|
||||
&& self.normalization_nested_goals.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453
|
||||
Subproject commit b65ab935fb2e0d59dba8966ffca09c9cc5a5f57c
|
||||
|
|
@ -30,7 +30,7 @@ use crate::fmt;
|
|||
/// Files are compared as strings, not `Path`, which could be unexpected.
|
||||
/// See [`Location::file`]'s documentation for more discussion.
|
||||
#[lang = "panic_location"]
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
||||
pub struct Location<'a> {
|
||||
// Note: this filename will have exactly one nul byte at its end, but otherwise
|
||||
|
|
@ -43,6 +43,17 @@ pub struct Location<'a> {
|
|||
col: u32,
|
||||
}
|
||||
|
||||
#[stable(feature = "panic_hooks", since = "1.10.0")]
|
||||
impl fmt::Debug for Location<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Location")
|
||||
.field("file", &self.file())
|
||||
.field("line", &self.line)
|
||||
.field("column", &self.col)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Location<'a> {
|
||||
/// Returns the source location of the caller of this function. If that function's caller is
|
||||
/// annotated then its call location will be returned, and so on up the stack to the first call
|
||||
|
|
|
|||
|
|
@ -29,3 +29,11 @@ fn location_const_column() {
|
|||
const COLUMN: u32 = CALLER.column();
|
||||
assert_eq!(COLUMN, 40);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn location_debug() {
|
||||
let f = format!("{:?}", Location::caller());
|
||||
assert!(f.contains(&format!("{:?}", file!())));
|
||||
assert!(f.contains("35"));
|
||||
assert!(f.contains("29"));
|
||||
}
|
||||
|
|
|
|||
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