Merge from rust-lang/rust
This commit is contained in:
commit
5db2aa865c
2585 changed files with 34566 additions and 24459 deletions
6
.gitattributes
vendored
6
.gitattributes
vendored
|
|
@ -4,8 +4,10 @@
|
|||
*.cpp rust
|
||||
*.h rust
|
||||
*.rs rust diff=rust
|
||||
*.fixed linguist-language=Rust
|
||||
*.mir linguist-language=Rust
|
||||
*.fixed linguist-language=Rust -merge
|
||||
*.mir linguist-language=Rust -merge
|
||||
*.stderr -merge
|
||||
*.stdout -merge
|
||||
src/etc/installer/gfx/* binary
|
||||
src/vendor/** -text
|
||||
Cargo.lock linguist-generated=false
|
||||
|
|
|
|||
14
.github/renovate.json5
vendored
Normal file
14
.github/renovate.json5
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
// Let Renovatebot keep an opened issue that tracks our dependencies
|
||||
"dependencyDashboard": true,
|
||||
// Disable "normal" package updates
|
||||
"enabledManagers": [],
|
||||
// Update lockfiles once per week
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true,
|
||||
"schedule": [
|
||||
"before 5am on Tuesday"
|
||||
]
|
||||
}
|
||||
}
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
|
|
@ -46,8 +46,7 @@ no_llvm_build
|
|||
/inst/
|
||||
/llvm/
|
||||
/mingw-build/
|
||||
build/
|
||||
!/compiler/rustc_mir_build/src/build/
|
||||
/build
|
||||
/build-rust-analyzer/
|
||||
/dist/
|
||||
/unicode-downloads
|
||||
|
|
@ -89,12 +88,12 @@ package.json
|
|||
tests/rustdoc-gui/src/**.lock
|
||||
|
||||
## direnv
|
||||
.envrc
|
||||
.direnv/
|
||||
/.envrc
|
||||
/.direnv/
|
||||
|
||||
## nix
|
||||
flake.nix
|
||||
/flake.nix
|
||||
flake.lock
|
||||
default.nix
|
||||
/default.nix
|
||||
|
||||
# Before adding new lines, see the comment at the top.
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -33,7 +33,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/19.1-2024-09-17
|
||||
branch = rustc/19.1-2024-12-03
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -254,6 +254,7 @@ Jack Huey <jack.huey@umassmed.edu> <jackh726@gmail.com>
|
|||
Jacob <jacob.macritchie@gmail.com>
|
||||
Jacob Greenfield <xales@naveria.com>
|
||||
Jacob Pratt <jacob@jhpratt.dev> <the.z.cuber@gmail.com>
|
||||
Jacob Pratt <jacob@jhpratt.dev> <jacopratt@tesla.com>
|
||||
Jake Vossen <jake@vossen.dev>
|
||||
Jakob Degen <jakob.e.degen@gmail.com> <jakob@degen.com>
|
||||
Jakob Lautrup Nysom <jako3047@gmail.com>
|
||||
|
|
|
|||
643
Cargo.lock
643
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -21,7 +21,7 @@ standard library, and documentation.
|
|||
|
||||
## Why Rust?
|
||||
|
||||
- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages.
|
||||
- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages.
|
||||
|
||||
- **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
|
||||
|
||||
|
|
|
|||
10
RELEASES.md
10
RELEASES.md
|
|
@ -43,7 +43,7 @@ Libraries
|
|||
- [Document that `catch_unwind` can deal with foreign exceptions without UB, although the exact behavior is unspecified.](https://github.com/rust-lang/rust/pull/128321)
|
||||
- [Implement `Default` for `HashMap`/`HashSet` iterators that don't already have it.](https://github.com/rust-lang/rust/pull/128711)
|
||||
- [Bump Unicode to version 16.0.0.](https://github.com/rust-lang/rust/pull/130183)
|
||||
- [Change documentation of `ptr::add`/`sub` to not claim equivalence with `offset`.](https://github.com/rust-lang/rust/pull/130229).
|
||||
- [Change documentation of `ptr::add`/`sub` to not claim equivalence with `offset`.](https://github.com/rust-lang/rust/pull/130229)
|
||||
|
||||
|
||||
<a id="1.83.0-Stabilized-APIs"></a>
|
||||
|
|
@ -503,7 +503,7 @@ Compatibility Notes
|
|||
* We have renamed `std::panic::PanicInfo` to `std::panic::PanicHookInfo`. The old name will continue to work as an alias, but will result in a deprecation warning starting in Rust 1.82.0.
|
||||
|
||||
`core::panic::PanicInfo` will remain unchanged, however, as this is now a *different type*.
|
||||
|
||||
|
||||
The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`.
|
||||
|
||||
* The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data.
|
||||
|
|
@ -584,7 +584,7 @@ Stabilized APIs
|
|||
- [`impl Default for Arc<CStr>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E)
|
||||
- [`impl Default for Arc<[T]>`](https://doc.rust-lang.org/beta/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3C%5BT%5D%3E)
|
||||
- [`impl IntoIterator for Box<[T]>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-IntoIterator-for-Box%3C%5BI%5D,+A%3E)
|
||||
- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E)
|
||||
- [`impl FromIterator<String> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3CString%3E-for-Box%3Cstr%3E)
|
||||
- [`impl FromIterator<char> for Box<str>`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html#impl-FromIterator%3Cchar%3E-for-Box%3Cstr%3E)
|
||||
- [`LazyCell`](https://doc.rust-lang.org/beta/core/cell/struct.LazyCell.html)
|
||||
- [`LazyLock`](https://doc.rust-lang.org/beta/std/sync/struct.LazyLock.html)
|
||||
|
|
@ -1816,7 +1816,7 @@ Compiler
|
|||
- [Detect uninhabited types early in const eval](https://github.com/rust-lang/rust/pull/109435/)
|
||||
- [Switch to LLD as default linker for {arm,thumb}v4t-none-eabi](https://github.com/rust-lang/rust/pull/109721/)
|
||||
- [Add tier 3 target `loongarch64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/96971)
|
||||
- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/),
|
||||
- [Add tier 3 target for `i586-pc-nto-qnx700` (QNX Neutrino RTOS, version 7.0)](https://github.com/rust-lang/rust/pull/109173/),
|
||||
- [Insert alignment checks for pointer dereferences as debug assertions](https://github.com/rust-lang/rust/pull/98112)
|
||||
This catches undefined behavior at runtime, and may cause existing code to fail.
|
||||
|
||||
|
|
@ -2023,7 +2023,7 @@ Compatibility Notes
|
|||
If `tools = [...]` is set in config.toml, we will respect a missing rustdoc in that list. By
|
||||
default rustdoc remains included. To retain the prior behavior explicitly add `"rustdoc"` to the
|
||||
list.
|
||||
|
||||
|
||||
<a id="1.69.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ rustc_smir = { path = "../rustc_smir" }
|
|||
stable_mir = { path = "../stable_mir" }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[dependencies.jemalloc-sys]
|
||||
version = "0.5.0"
|
||||
[dependencies.tikv-jemalloc-sys]
|
||||
version = "0.6.0"
|
||||
optional = true
|
||||
features = ['unprefixed_malloc_on_supported_platforms']
|
||||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
jemalloc = ['dep:jemalloc-sys']
|
||||
jemalloc = ['dep:tikv-jemalloc-sys']
|
||||
llvm = ['rustc_driver_impl/llvm']
|
||||
max_level_info = ['rustc_driver_impl/max_level_info']
|
||||
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ fn main() {
|
|||
{
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
use tikv_jemalloc_sys as jemalloc_sys;
|
||||
|
||||
#[used]
|
||||
static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
|
||||
#[used]
|
||||
|
|
|
|||
|
|
@ -1215,6 +1215,15 @@ impl Scalar {
|
|||
Scalar::Union { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a signed integer scalar
|
||||
#[inline]
|
||||
pub fn is_signed(&self) -> bool {
|
||||
match self.primitive() {
|
||||
Primitive::Int(_, signed) => signed,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This struct is generic over the FieldIdx for rust-analyzer usage.
|
||||
|
|
@ -1401,10 +1410,7 @@ impl BackendRepr {
|
|||
#[inline]
|
||||
pub fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
BackendRepr::Scalar(scal) => match scal.primitive() {
|
||||
Primitive::Int(_, signed) => signed,
|
||||
_ => false,
|
||||
},
|
||||
BackendRepr::Scalar(scal) => scal.is_signed(),
|
||||
_ => panic!("`is_signed` on non-scalar ABI {self:?}"),
|
||||
}
|
||||
}
|
||||
|
|
@ -1499,7 +1505,11 @@ impl BackendRepr {
|
|||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
|
||||
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
|
||||
Single { index: VariantIdx },
|
||||
Single {
|
||||
/// Always 0 for non-enums/generators.
|
||||
/// For enums without a variant, this is an invalid index!
|
||||
index: VariantIdx,
|
||||
},
|
||||
|
||||
/// Enum-likes with more than one variant: each variant comes with
|
||||
/// a *discriminant* (usually the same as the variant index but the user can
|
||||
|
|
@ -1528,14 +1538,22 @@ pub enum TagEncoding<VariantIdx: Idx> {
|
|||
/// The variant `untagged_variant` contains a niche at an arbitrary
|
||||
/// offset (field `tag_field` of the enum), which for a variant with
|
||||
/// discriminant `d` is set to
|
||||
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
|
||||
/// `(d - niche_variants.start).wrapping_add(niche_start)`
|
||||
/// (this is wrapping arithmetic using the type of the niche field).
|
||||
///
|
||||
/// For example, `Option<(usize, &T)>` is represented such that
|
||||
/// `None` has a null pointer for the second tuple field, and
|
||||
/// `Some` is the identity function (with a non-null reference).
|
||||
///
|
||||
/// Other variants that are not `untagged_variant` and that are outside the `niche_variants`
|
||||
/// range cannot be represented; they must be uninhabited.
|
||||
Niche {
|
||||
untagged_variant: VariantIdx,
|
||||
/// This range *may* contain `untagged_variant`; that is then just a "dead value" and
|
||||
/// not used to encode anything.
|
||||
niche_variants: RangeInclusive<VariantIdx>,
|
||||
/// This is inbounds of the type of the niche field
|
||||
/// (not sign-extended, i.e., all bits beyond the niche field size are 0).
|
||||
niche_start: u128,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,7 @@ pub use crate::format::*;
|
|||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter};
|
||||
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
|
||||
use crate::util::parser::{
|
||||
AssocOp, PREC_CLOSURE, PREC_JUMP, PREC_PREFIX, PREC_RANGE, PREC_UNAMBIGUOUS,
|
||||
};
|
||||
use crate::util::parser::{AssocOp, ExprPrecedence};
|
||||
|
||||
/// A "Label" is an identifier of some point in sources,
|
||||
/// e.g. in the following code:
|
||||
|
|
@ -629,9 +627,11 @@ impl Pat {
|
|||
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
|
||||
|
||||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
|
||||
s.walk(it)
|
||||
}
|
||||
PatKind::Box(s)
|
||||
| PatKind::Deref(s)
|
||||
| PatKind::Ref(s, _)
|
||||
| PatKind::Paren(s)
|
||||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
// These patterns do not contain subpatterns, skip.
|
||||
PatKind::Wild
|
||||
|
|
@ -841,6 +841,9 @@ pub enum PatKind {
|
|||
// A never pattern `!`.
|
||||
Never,
|
||||
|
||||
/// A guard pattern (e.g., `x if guard(x)`).
|
||||
Guard(P<Pat>, P<Expr>),
|
||||
|
||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||
Paren(P<Pat>),
|
||||
|
||||
|
|
@ -1184,14 +1187,15 @@ pub struct Expr {
|
|||
}
|
||||
|
||||
impl Expr {
|
||||
/// Is this expr either `N`, or `{ N }`.
|
||||
/// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter.
|
||||
///
|
||||
/// If this is not the case, name resolution does not resolve `N` when using
|
||||
/// `min_const_generics` as more complex expressions are not supported.
|
||||
///
|
||||
/// Does not ensure that the path resolves to a const param, the caller should check this.
|
||||
pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool {
|
||||
let this = if strip_identity_block { self.maybe_unwrap_block() } else { self };
|
||||
/// This also does not consider macros, so it's only correct after macro-expansion.
|
||||
pub fn is_potential_trivial_const_arg(&self) -> bool {
|
||||
let this = self.maybe_unwrap_block();
|
||||
|
||||
if let ExprKind::Path(None, path) = &this.kind
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
|
|
@ -1316,29 +1320,29 @@ impl Expr {
|
|||
Some(P(Ty { kind, id: self.id, span: self.span, tokens: None }))
|
||||
}
|
||||
|
||||
pub fn precedence(&self) -> i8 {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Closure(..) => PREC_CLOSURE,
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => PREC_JUMP,
|
||||
| ExprKind::Become(..) => ExprPrecedence::Jump,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
// ensures that `pprust` will add parentheses in the right places to get the desired
|
||||
// parse.
|
||||
ExprKind::Range(..) => PREC_RANGE,
|
||||
ExprKind::Range(..) => ExprPrecedence::Range,
|
||||
|
||||
// Binop-like expr kinds, handled by `AssocOp`.
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence() as i8,
|
||||
ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
|
||||
ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(),
|
||||
ExprKind::Cast(..) => ExprPrecedence::Cast,
|
||||
|
||||
ExprKind::Assign(..) |
|
||||
ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
|
||||
ExprKind::AssignOp(..) => ExprPrecedence::Assign,
|
||||
|
||||
// Unary, prefix
|
||||
ExprKind::AddrOf(..)
|
||||
|
|
@ -1347,7 +1351,7 @@ impl Expr {
|
|||
// need parens sometimes. E.g. we can print `(let _ = a) && b` as `let _ = a && b`
|
||||
// but we need to print `(let _ = a) < b` as-is with parens.
|
||||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => PREC_PREFIX,
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
ExprKind::Array(_)
|
||||
|
|
@ -1380,7 +1384,7 @@ impl Expr {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => PREC_UNAMBIGUOUS,
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1732,12 +1736,12 @@ pub enum AttrArgs {
|
|||
/// Delimited arguments: `#[attr()/[]/{}]`.
|
||||
Delimited(DelimArgs),
|
||||
/// Arguments of a key-value attribute: `#[attr = "value"]`.
|
||||
Eq(
|
||||
Eq {
|
||||
/// Span of the `=` token.
|
||||
Span,
|
||||
/// The "value".
|
||||
AttrArgsEq,
|
||||
),
|
||||
eq_span: Span,
|
||||
|
||||
value: AttrArgsEq,
|
||||
},
|
||||
}
|
||||
|
||||
// The RHS of an `AttrArgs::Eq` starts out as an expression. Once macro
|
||||
|
|
@ -1749,15 +1753,39 @@ pub enum AttrArgsEq {
|
|||
Hir(MetaItemLit),
|
||||
}
|
||||
|
||||
impl AttrArgsEq {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
AttrArgsEq::Ast(p) => p.span,
|
||||
AttrArgsEq::Hir(lit) => lit.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_ast(&self) -> &Expr {
|
||||
match self {
|
||||
AttrArgsEq::Ast(p) => p,
|
||||
AttrArgsEq::Hir(lit) => {
|
||||
unreachable!("in literal form when getting inner tokens: {lit:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_ast_mut(&mut self) -> &mut P<Expr> {
|
||||
match self {
|
||||
AttrArgsEq::Ast(p) => p,
|
||||
AttrArgsEq::Hir(lit) => {
|
||||
unreachable!("in literal form when getting inner tokens: {lit:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AttrArgs {
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
match self {
|
||||
AttrArgs::Empty => None,
|
||||
AttrArgs::Delimited(args) => Some(args.dspan.entire()),
|
||||
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => Some(eq_span.to(expr.span)),
|
||||
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
|
||||
unreachable!("in literal form when getting span: {:?}", lit);
|
||||
}
|
||||
AttrArgs::Eq { eq_span, value } => Some(eq_span.to(value.span())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1767,10 +1795,7 @@ impl AttrArgs {
|
|||
match self {
|
||||
AttrArgs::Empty => TokenStream::default(),
|
||||
AttrArgs::Delimited(args) => args.tokens.clone(),
|
||||
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => TokenStream::from_ast(expr),
|
||||
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
|
||||
unreachable!("in literal form when getting inner tokens: {:?}", lit)
|
||||
}
|
||||
AttrArgs::Eq { value, .. } => TokenStream::from_ast(value.unwrap_ast()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1784,10 +1809,10 @@ where
|
|||
match self {
|
||||
AttrArgs::Empty => {}
|
||||
AttrArgs::Delimited(args) => args.hash_stable(ctx, hasher),
|
||||
AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => {
|
||||
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => {
|
||||
unreachable!("hash_stable {:?}", expr);
|
||||
}
|
||||
AttrArgs::Eq(eq_span, AttrArgsEq::Hir(lit)) => {
|
||||
AttrArgs::Eq { eq_span, value: AttrArgsEq::Hir(lit) } => {
|
||||
eq_span.hash_stable(ctx, hasher);
|
||||
lit.hash_stable(ctx, hasher);
|
||||
}
|
||||
|
|
@ -2546,6 +2571,18 @@ pub enum SelfKind {
|
|||
Explicit(P<Ty>, Mutability),
|
||||
}
|
||||
|
||||
impl SelfKind {
|
||||
pub fn to_ref_suggestion(&self) -> String {
|
||||
match self {
|
||||
SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
|
||||
SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
|
||||
SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
|
||||
unreachable!("if we had an explicit self, we wouldn't be here")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ExplicitSelf = Spanned<SelfKind>;
|
||||
|
||||
impl Param {
|
||||
|
|
@ -3082,6 +3119,7 @@ pub struct FieldDef {
|
|||
pub ident: Option<Ident>,
|
||||
|
||||
pub ty: P<Ty>,
|
||||
pub default: Option<AnonConst>,
|
||||
pub is_placeholder: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ impl AttrItem {
|
|||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
MetaItemKind::list_from_tokens(args.tokens.clone())
|
||||
}
|
||||
AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
|
||||
AttrArgs::Delimited(_) | AttrArgs::Eq { .. } | AttrArgs::Empty => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +268,7 @@ impl AttrItem {
|
|||
/// ```
|
||||
fn value_str(&self) -> Option<Symbol> {
|
||||
match &self.args {
|
||||
AttrArgs::Eq(_, args) => args.value_str(),
|
||||
AttrArgs::Eq { value, .. } => value.value_str(),
|
||||
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -492,7 +492,7 @@ impl MetaItemKind {
|
|||
MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
|
||||
}
|
||||
AttrArgs::Delimited(..) => None,
|
||||
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
|
||||
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => match expr.kind {
|
||||
ExprKind::Lit(token_lit) => {
|
||||
// Turn failures to `None`, we'll get parse errors elsewhere.
|
||||
MetaItemLit::from_token_lit(token_lit, expr.span)
|
||||
|
|
@ -501,7 +501,9 @@ impl MetaItemKind {
|
|||
}
|
||||
_ => None,
|
||||
},
|
||||
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
|
||||
AttrArgs::Eq { value: AttrArgsEq::Hir(lit), .. } => {
|
||||
Some(MetaItemKind::NameValue(lit.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -702,7 +704,7 @@ pub fn mk_attr_name_value_str(
|
|||
tokens: None,
|
||||
});
|
||||
let path = Path::from_ident(Ident::new(name, span));
|
||||
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
|
||||
let args = AttrArgs::Eq { eq_span: span, value: AttrArgsEq::Ast(expr) };
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -451,13 +451,10 @@ fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
|
|||
match args {
|
||||
AttrArgs::Empty => {}
|
||||
AttrArgs::Delimited(args) => visit_delim_args(vis, args),
|
||||
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => {
|
||||
vis.visit_expr(expr);
|
||||
AttrArgs::Eq { eq_span, value } => {
|
||||
vis.visit_expr(value.unwrap_ast_mut());
|
||||
vis.visit_span(eq_span);
|
||||
}
|
||||
AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => {
|
||||
unreachable!("in literal form when visiting mac args eq: {:?}", lit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1123,13 +1120,14 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
|
|||
}
|
||||
|
||||
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = fd;
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd;
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
visit_safety(visitor, safety);
|
||||
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(default, |default| visitor.visit_anon_const(default));
|
||||
visitor.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -1528,6 +1526,10 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
|||
visit_opt(e2, |e| vis.visit_expr(e));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
PatKind::Guard(p, e) => {
|
||||
vis.visit_pat(p);
|
||||
vis.visit_expr(e);
|
||||
}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
visit_thin_vec(elems, |elem| vis.visit_pat(elem))
|
||||
}
|
||||
|
|
@ -1628,9 +1630,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
|||
visit_thin_exprs(vis, call_args);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Binary(_binop, lhs, rhs) => {
|
||||
ExprKind::Binary(binop, lhs, rhs) => {
|
||||
vis.visit_expr(lhs);
|
||||
vis.visit_expr(rhs);
|
||||
vis.visit_span(&mut binop.span);
|
||||
}
|
||||
ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
|
|
@ -1788,20 +1791,21 @@ pub fn noop_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Optio
|
|||
|
||||
pub fn walk_flat_map_stmt<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
Stmt { kind, mut span, mut id }: Stmt,
|
||||
Stmt { kind, span, mut id }: Stmt,
|
||||
) -> SmallVec<[Stmt; 1]> {
|
||||
vis.visit_id(&mut id);
|
||||
let stmts: SmallVec<_> = walk_flat_map_stmt_kind(vis, kind)
|
||||
let mut stmts: SmallVec<[Stmt; 1]> = walk_flat_map_stmt_kind(vis, kind)
|
||||
.into_iter()
|
||||
.map(|kind| Stmt { id, kind, span })
|
||||
.collect();
|
||||
if stmts.len() > 1 {
|
||||
panic!(
|
||||
match stmts.len() {
|
||||
0 => {}
|
||||
1 => vis.visit_span(&mut stmts[0].span),
|
||||
2.. => panic!(
|
||||
"cloning statement `NodeId`s is prohibited by default, \
|
||||
the visitor should implement custom statement visiting"
|
||||
);
|
||||
),
|
||||
}
|
||||
vis.visit_span(&mut span);
|
||||
stmts
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,21 +128,21 @@ impl AssocOp {
|
|||
}
|
||||
|
||||
/// Gets the precedence of this operator
|
||||
pub fn precedence(&self) -> usize {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
use AssocOp::*;
|
||||
match *self {
|
||||
As => 14,
|
||||
Multiply | Divide | Modulus => 13,
|
||||
Add | Subtract => 12,
|
||||
ShiftLeft | ShiftRight => 11,
|
||||
BitAnd => 10,
|
||||
BitXor => 9,
|
||||
BitOr => 8,
|
||||
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7,
|
||||
LAnd => 6,
|
||||
LOr => 5,
|
||||
DotDot | DotDotEq => 4,
|
||||
Assign | AssignOp(_) => 2,
|
||||
As => ExprPrecedence::Cast,
|
||||
Multiply | Divide | Modulus => ExprPrecedence::Product,
|
||||
Add | Subtract => ExprPrecedence::Sum,
|
||||
ShiftLeft | ShiftRight => ExprPrecedence::Shift,
|
||||
BitAnd => ExprPrecedence::BitAnd,
|
||||
BitXor => ExprPrecedence::BitXor,
|
||||
BitOr => ExprPrecedence::BitOr,
|
||||
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare,
|
||||
LAnd => ExprPrecedence::LAnd,
|
||||
LOr => ExprPrecedence::LOr,
|
||||
DotDot | DotDotEq => ExprPrecedence::Range,
|
||||
Assign | AssignOp(_) => ExprPrecedence::Assign,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -229,17 +229,44 @@ impl AssocOp {
|
|||
}
|
||||
}
|
||||
|
||||
pub const PREC_CLOSURE: i8 = -40;
|
||||
pub const PREC_JUMP: i8 = -30;
|
||||
pub const PREC_RANGE: i8 = -10;
|
||||
// The range 2..=14 is reserved for AssocOp binary operator precedences.
|
||||
pub const PREC_PREFIX: i8 = 50;
|
||||
pub const PREC_UNAMBIGUOUS: i8 = 60;
|
||||
pub const PREC_FORCE_PAREN: i8 = 100;
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum ExprPrecedence {
|
||||
Closure,
|
||||
// return, break, yield
|
||||
Jump,
|
||||
// = += -= *= /= %= &= |= ^= <<= >>=
|
||||
Assign,
|
||||
// .. ..=
|
||||
Range,
|
||||
// ||
|
||||
LOr,
|
||||
// &&
|
||||
LAnd,
|
||||
// == != < > <= >=
|
||||
Compare,
|
||||
// |
|
||||
BitOr,
|
||||
// ^
|
||||
BitXor,
|
||||
// &
|
||||
BitAnd,
|
||||
// << >>
|
||||
Shift,
|
||||
// + -
|
||||
Sum,
|
||||
// * / %
|
||||
Product,
|
||||
// as
|
||||
Cast,
|
||||
// unary - * ! & &mut
|
||||
Prefix,
|
||||
// paths, loops, function calls, array indexing, field expressions, method calls
|
||||
Unambiguous,
|
||||
}
|
||||
|
||||
/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
|
||||
pub fn prec_let_scrutinee_needs_par() -> usize {
|
||||
AssocOp::LAnd.precedence()
|
||||
pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
|
||||
ExprPrecedence::LAnd
|
||||
}
|
||||
|
||||
/// Suppose we have `let _ = e` and the `order` of `e`.
|
||||
|
|
@ -247,8 +274,8 @@ pub fn prec_let_scrutinee_needs_par() -> usize {
|
|||
///
|
||||
/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
|
||||
/// Can we print this as `let _ = a OP b`?
|
||||
pub fn needs_par_as_let_scrutinee(order: i8) -> bool {
|
||||
order <= prec_let_scrutinee_needs_par() as i8
|
||||
pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
|
||||
order <= prec_let_scrutinee_needs_par()
|
||||
}
|
||||
|
||||
/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
|
||||
|
|
|
|||
|
|
@ -682,6 +682,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
}
|
||||
PatKind::Guard(subpattern, guard_condition) => {
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
try_visit!(visitor.visit_expr(guard_condition));
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Err(_guar) => {}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
|
|
@ -971,11 +975,13 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>(
|
|||
}
|
||||
|
||||
pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
|
||||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field;
|
||||
let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _, default } =
|
||||
field;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_vis(vis));
|
||||
visit_opt!(visitor, visit_ident, ident);
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_anon_const, &*default);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
|
|
@ -1273,10 +1279,7 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -
|
|||
match args {
|
||||
AttrArgs::Empty => {}
|
||||
AttrArgs::Delimited(_args) => {}
|
||||
AttrArgs::Eq(_eq_span, AttrArgsEq::Ast(expr)) => try_visit!(visitor.visit_expr(expr)),
|
||||
AttrArgs::Eq(_eq_span, AttrArgsEq::Hir(lit)) => {
|
||||
unreachable!("in literal form when walking mac args eq: {:?}", lit)
|
||||
}
|
||||
AttrArgs::Eq { value, .. } => try_visit!(visitor.visit_expr(value.unwrap_ast())),
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,6 @@ ast_lowering_bad_return_type_notation_output =
|
|||
|
||||
ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet
|
||||
|
||||
ast_lowering_base_expression_double_dot =
|
||||
base expression required after `..`
|
||||
.suggestion = add a base expression here
|
||||
|
||||
ast_lowering_clobber_abi_not_supported =
|
||||
`clobber_abi` is not supported on this target
|
||||
|
||||
|
|
@ -57,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static
|
|||
ast_lowering_coroutine_too_many_parameters =
|
||||
too many parameters for a coroutine (expected 0 or 1 parameters)
|
||||
|
||||
ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
|
||||
.label = default fields are only supported on structs
|
||||
|
||||
ast_lowering_does_not_support_modifiers =
|
||||
the `{$class_name}` register class does not support template modifiers
|
||||
|
||||
|
|
|
|||
|
|
@ -227,18 +227,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
|
||||
// Wrap the expression in an AnonConst.
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let parent_def_id = self.current_hir_id_owner.def_id;
|
||||
let node_id = self.next_node_id();
|
||||
// HACK(min_generic_const_args): see lower_anon_const
|
||||
if !expr.is_potential_trivial_const_arg(true) {
|
||||
self.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
*op_sp,
|
||||
);
|
||||
}
|
||||
self.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
*op_sp,
|
||||
);
|
||||
let anon_const = AnonConst { id: node_id, value: P(expr) };
|
||||
hir::InlineAsmOperand::SymFn {
|
||||
anon_const: self.lower_anon_const_to_anon_const(&anon_const),
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ pub(crate) struct InvalidAbi {
|
|||
pub suggestion: Option<InvalidAbiSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_default_field_in_tuple)]
|
||||
pub(crate) struct TupleStructWithDefault {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub(crate) struct InvalidAbiReason(pub &'static str);
|
||||
|
||||
impl Subdiagnostic for InvalidAbiReason {
|
||||
|
|
@ -114,14 +122,6 @@ pub(crate) struct UnderscoreExprLhsAssign {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_base_expression_double_dot, code = E0797)]
|
||||
pub(crate) struct BaseExpressionDoubleDot {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ use thin_vec::{ThinVec, thin_vec};
|
|||
use visit::{Visitor, walk_expr};
|
||||
|
||||
use super::errors::{
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||
ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||
NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign,
|
||||
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic,
|
||||
CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment,
|
||||
InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard,
|
||||
UnderscoreExprLhsAssign,
|
||||
};
|
||||
use super::{
|
||||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
|
|
@ -109,9 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ConstBlock {
|
||||
def_id,
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(c.value.span, Some(&c.value))
|
||||
}),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
}
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
|
|
@ -359,12 +357,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
),
|
||||
ExprKind::Struct(se) => {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||
StructRest::Rest(sp) => {
|
||||
let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp });
|
||||
Some(&*self.arena.alloc(self.expr_err(*sp, guar)))
|
||||
}
|
||||
StructRest::None => None,
|
||||
StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)),
|
||||
StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp),
|
||||
StructRest::None => hir::StructTailExpr::None,
|
||||
};
|
||||
hir::ExprKind::Struct(
|
||||
self.arena.alloc(self.lower_qpath(
|
||||
|
|
@ -452,15 +447,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let mut generic_args = ThinVec::new();
|
||||
for (idx, arg) in args.iter().cloned().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let parent_def_id = self.current_hir_id_owner.def_id;
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
// HACK(min_generic_const_args): see lower_anon_const
|
||||
if !arg.is_potential_trivial_const_arg(true) {
|
||||
// Add a definition for the in-band const def.
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
||||
}
|
||||
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
||||
let mut visitor = WillCreateDefIdsVisitor {};
|
||||
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||
AstP(Expr {
|
||||
|
|
@ -759,19 +748,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
let body = self.with_def_id_parent(closure_def_id, move |this| {
|
||||
this.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
let old_ctx = this.task_context;
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
|
||||
(params, res)
|
||||
})
|
||||
(params, res)
|
||||
});
|
||||
|
||||
// `static |<_task_context?>| -> <return_ty> { <body> }`:
|
||||
|
|
@ -1056,26 +1043,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
this.with_def_id_parent(closure_def_id, move |this| {
|
||||
let mut coroutine_kind = if this
|
||||
.attrs
|
||||
.get(&closure_hir_id.local_id)
|
||||
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
|
||||
{
|
||||
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
})
|
||||
let mut coroutine_kind = if this
|
||||
.attrs
|
||||
.get(&closure_hir_id.local_id)
|
||||
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
|
||||
{
|
||||
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
});
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
|
|
@ -1165,28 +1150,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
this.with_def_id_parent(closure_def_id, |this| {
|
||||
let inner_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
let inner_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_body(|this| {
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
&inner_decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
fn_decl_span,
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
);
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_body(|this| {
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
&inner_decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
fn_decl_span,
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
);
|
||||
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
|
||||
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
})
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
});
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
|
|
@ -1540,7 +1523,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Struct(
|
||||
self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
|
||||
fields,
|
||||
None,
|
||||
hir::StructTailExpr::None,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@ use smallvec::{SmallVec, smallvec};
|
|||
use thin_vec::ThinVec;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
|
||||
use super::errors::{
|
||||
InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
|
||||
TupleStructWithDefault,
|
||||
};
|
||||
use super::{
|
||||
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
|
||||
ResolverAstLoweringExt,
|
||||
|
|
@ -690,13 +693,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
VariantData::Tuple(fields, id) => {
|
||||
let ctor_id = self.lower_node_id(*id);
|
||||
self.alias_attrs(ctor_id, parent_id);
|
||||
hir::VariantData::Tuple(
|
||||
self.arena.alloc_from_iter(
|
||||
fields.iter().enumerate().map(|f| self.lower_field_def(f)),
|
||||
),
|
||||
ctor_id,
|
||||
self.local_def_id(*id),
|
||||
)
|
||||
let fields = self
|
||||
.arena
|
||||
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
|
||||
for field in &fields[..] {
|
||||
if let Some(default) = field.default {
|
||||
// Default values in tuple struct and tuple variants are not allowed by the
|
||||
// RFC due to concerns about the syntax, both in the item definition and the
|
||||
// expression. We could in the future allow `struct S(i32 = 0);` and force
|
||||
// users to construct the value with `let _ = S { .. };`.
|
||||
if self.tcx.features().default_field_values() {
|
||||
self.dcx().emit_err(TupleStructWithDefault { span: default.span });
|
||||
} else {
|
||||
let _ = self.dcx().span_delayed_bug(
|
||||
default.span,
|
||||
"expected `default values on `struct` fields aren't supported` \
|
||||
feature-gate error but none was produced",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id))
|
||||
}
|
||||
VariantData::Unit(id) => {
|
||||
let ctor_id = self.lower_node_id(*id);
|
||||
|
|
@ -723,6 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
|
||||
},
|
||||
vis_span: self.lower_span(f.vis.span),
|
||||
default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
|
||||
ty,
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,18 +117,6 @@ struct LoweringContext<'a, 'hir> {
|
|||
is_in_dyn_type: bool,
|
||||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
/// Why do we need this in addition to [`Self::current_hir_id_owner`]?
|
||||
///
|
||||
/// Currently (as of June 2024), anonymous constants are not HIR owners; however,
|
||||
/// they do get their own DefIds. Some of these DefIds have to be created during
|
||||
/// AST lowering, rather than def collection, because we can't tell until after
|
||||
/// name resolution whether an anonymous constant will end up instead being a
|
||||
/// [`hir::ConstArgKind::Path`]. However, to compute which generics are
|
||||
/// available to an anonymous constant nested inside another, we need to make
|
||||
/// sure that the parent is recorded as the parent anon const, not the enclosing
|
||||
/// item. So we need to track parent defs differently from HIR owners, since they
|
||||
/// will be finer-grained in the case of anon consts.
|
||||
current_def_id_parent: LocalDefId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
|
||||
|
||||
|
|
@ -161,7 +149,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
attrs: SortedMap::default(),
|
||||
children: Vec::default(),
|
||||
current_hir_id_owner: hir::CRATE_OWNER_ID,
|
||||
current_def_id_parent: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::ZERO,
|
||||
ident_and_label_to_local_id: Default::default(),
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -565,7 +552,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
debug_assert_eq!(_old, None);
|
||||
}
|
||||
|
||||
let item = self.with_def_id_parent(def_id, f);
|
||||
let item = f(self);
|
||||
debug_assert_eq!(def_id, item.def_id().def_id);
|
||||
// `f` should have consumed all the elements in these vectors when constructing `item`.
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
|
|
@ -590,13 +577,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.children.push((def_id, hir::MaybeOwner::Owner(info)));
|
||||
}
|
||||
|
||||
fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent);
|
||||
let result = f(self);
|
||||
self.current_def_id_parent = current_def_id_parent;
|
||||
result
|
||||
}
|
||||
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
|
|
@ -773,7 +753,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
LifetimeRes::Fresh { param, kind, .. } => {
|
||||
// Late resolution delegates to us the creation of the `LocalDefId`.
|
||||
let _def_id = self.create_def(
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
self.current_hir_id_owner.def_id,
|
||||
param,
|
||||
kw::UnderscoreLifetime,
|
||||
DefKind::LifetimeParam,
|
||||
|
|
@ -909,7 +889,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// This is an inert key-value attribute - it will never be visible to macros
|
||||
// after it gets lowered to HIR. Therefore, we can extract literals to handle
|
||||
// nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
|
||||
AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => {
|
||||
&AttrArgs::Eq { eq_span, ref value } => {
|
||||
let expr = value.unwrap_ast();
|
||||
// In valid code the value always ends up as a single literal. Otherwise, a dummy
|
||||
// literal suffices because the error is handled elsewhere.
|
||||
let lit = if let ExprKind::Lit(token_lit) = expr.kind
|
||||
|
|
@ -925,10 +906,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: DUMMY_SP,
|
||||
}
|
||||
};
|
||||
AttrArgs::Eq(*eq_span, AttrArgsEq::Hir(lit))
|
||||
}
|
||||
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
|
||||
unreachable!("in literal form when lowering mac args eq: {:?}", lit)
|
||||
AttrArgs::Eq { eq_span, value: AttrArgsEq::Hir(lit) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1467,17 +1445,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
|
||||
debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
|
||||
|
||||
let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
|
||||
let bounds = lower_item_bounds(this);
|
||||
let opaque_ty_def = hir::OpaqueTy {
|
||||
hir_id: opaque_ty_hir_id,
|
||||
def_id: opaque_ty_def_id,
|
||||
bounds,
|
||||
origin,
|
||||
span: this.lower_span(opaque_ty_span),
|
||||
};
|
||||
this.arena.alloc(opaque_ty_def)
|
||||
});
|
||||
let bounds = lower_item_bounds(self);
|
||||
let opaque_ty_def = hir::OpaqueTy {
|
||||
hir_id: opaque_ty_hir_id,
|
||||
def_id: opaque_ty_def_id,
|
||||
bounds,
|
||||
origin,
|
||||
span: self.lower_span(opaque_ty_span),
|
||||
};
|
||||
let opaque_ty_def = self.arena.alloc(opaque_ty_def);
|
||||
|
||||
hir::TyKind::OpaqueDef(opaque_ty_def)
|
||||
}
|
||||
|
|
@ -2035,7 +2011,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ExprKind::Underscore => {
|
||||
if self.tcx.features().generic_arg_infer() {
|
||||
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
|
||||
self.arena
|
||||
.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
|
||||
} else {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
|
|
@ -2083,7 +2060,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
} else {
|
||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let parent_def_id = self.current_hir_id_owner.def_id;
|
||||
let node_id = self.next_node_id();
|
||||
let span = self.lower_span(span);
|
||||
|
||||
|
|
@ -2107,9 +2084,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.arena.alloc(hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(path_expr.span, Some(&path_expr))
|
||||
}),
|
||||
body: this.lower_const_body(path_expr.span, Some(&path_expr)),
|
||||
span,
|
||||
})
|
||||
});
|
||||
|
|
@ -2158,7 +2133,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
None,
|
||||
);
|
||||
|
||||
return ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) };
|
||||
return ConstArg {
|
||||
hir_id: self.lower_node_id(anon.id),
|
||||
kind: hir::ConstArgKind::Path(qpath),
|
||||
};
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
|
|
@ -2168,29 +2146,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_const_arg`].
|
||||
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||
if c.value.is_potential_trivial_const_arg(true) {
|
||||
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
|
||||
// Over there, we guess if this is a bare param and only create a def if
|
||||
// we think it's not. However we may can guess wrong (see there for example)
|
||||
// in which case we have to create the def here.
|
||||
self.create_def(
|
||||
self.current_def_id_parent,
|
||||
c.id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
c.value.span,
|
||||
);
|
||||
}
|
||||
|
||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
let hir_id = this.lower_node_id(c.id);
|
||||
hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(c.value.span, Some(&c.value))
|
||||
}),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
span: this.lower_span(c.value.span),
|
||||
}
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.lower_range_end(end, e2.is_some()),
|
||||
);
|
||||
}
|
||||
// FIXME(guard_patterns): lower pattern guards to HIR
|
||||
PatKind::Guard(inner, _) => pattern = inner,
|
||||
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
// If we reach here the `..` pattern is not semantically allowed.
|
||||
|
|
|
|||
|
|
@ -207,8 +207,6 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
|
|||
|
||||
ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
|
||||
|
||||
ast_passes_show_span = {$msg}
|
||||
|
||||
ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
|
||||
|
||||
ast_passes_static_without_body =
|
||||
|
|
|
|||
|
|
@ -779,14 +779,6 @@ pub(crate) struct IncompatibleFeatures {
|
|||
pub f2: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_show_span)]
|
||||
pub(crate) struct ShowSpan {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub msg: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_negative_bound_not_supported)]
|
||||
pub(crate) struct NegativeBoundUnsupported {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ use rustc_ast::{NodeId, PatKind, attr, token};
|
|||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_target::spec::abi;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
@ -516,6 +516,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
"async closures are unstable",
|
||||
"to use an async block, remove the `||`: `async {`"
|
||||
);
|
||||
gate_all!(
|
||||
async_trait_bounds,
|
||||
"`async` trait bounds are unstable",
|
||||
"use the desugared name of the async trait, such as `AsyncFn`"
|
||||
);
|
||||
gate_all!(async_for_loop, "`for await` loops are experimental");
|
||||
gate_all!(
|
||||
closure_lifetime_binder,
|
||||
|
|
@ -551,6 +556,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
|
||||
gate_all!(default_field_values, "default values on fields are experimental");
|
||||
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
|
||||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
|
|
@ -690,6 +697,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
|||
.find(|feat| feat.gate_name == sym::generic_const_exprs)
|
||||
.map(|feat| feat.attr_sp)
|
||||
{
|
||||
#[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans: vec![gce_span],
|
||||
f1: Symbol::intern("-Znext-solver=globally"),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
//! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax`
|
||||
//! parsed by `rustc_parse` and then lowered, after the passes in this crate,
|
||||
//! by `rustc_ast_lowering`.
|
||||
//!
|
||||
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
|
|
@ -18,6 +16,5 @@
|
|||
pub mod ast_validation;
|
||||
mod errors;
|
||||
pub mod feature_gate;
|
||||
pub mod show_span;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
//! Span debugger
|
||||
//!
|
||||
//! This module shows spans for all expressions in the crate
|
||||
//! to help with compiler debugging.
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
enum Mode {
|
||||
Expression,
|
||||
Pattern,
|
||||
Type,
|
||||
}
|
||||
|
||||
impl FromStr for Mode {
|
||||
type Err = ();
|
||||
fn from_str(s: &str) -> Result<Mode, ()> {
|
||||
let mode = match s {
|
||||
"expr" => Mode::Expression,
|
||||
"pat" => Mode::Pattern,
|
||||
"ty" => Mode::Type,
|
||||
_ => return Err(()),
|
||||
};
|
||||
Ok(mode)
|
||||
}
|
||||
}
|
||||
|
||||
struct ShowSpanVisitor<'a> {
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
|
||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
if let Mode::Expression = self.mode {
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: e.span, msg: "expression" });
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &'a ast::Pat) {
|
||||
if let Mode::Pattern = self.mode {
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: p.span, msg: "pattern" });
|
||||
}
|
||||
visit::walk_pat(self, p);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'a ast::Ty) {
|
||||
if let Mode::Type = self.mode {
|
||||
self.dcx.emit_warn(errors::ShowSpan { span: t.span, msg: "type" });
|
||||
}
|
||||
visit::walk_ty(self, t);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(dcx: DiagCtxtHandle<'_>, mode: &str, krate: &ast::Crate) {
|
||||
let Ok(mode) = mode.parse() else {
|
||||
return;
|
||||
};
|
||||
let mut v = ShowSpanVisitor { dcx, mode };
|
||||
visit::walk_crate(&mut v, krate);
|
||||
}
|
||||
|
|
@ -648,14 +648,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
AttrArgs::Empty => {
|
||||
self.print_path(&item.path, false, 0);
|
||||
}
|
||||
AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
|
||||
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => {
|
||||
self.print_path(&item.path, false, 0);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
let token_str = self.expr_to_string(expr);
|
||||
self.word(token_str);
|
||||
}
|
||||
AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
|
||||
AttrArgs::Eq { value: AttrArgsEq::Hir(lit), .. } => {
|
||||
self.print_path(&item.path, false, 0);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
|
|
@ -1709,6 +1709,14 @@ impl<'a> State<'a> {
|
|||
self.print_expr(e, FixupContext::default());
|
||||
}
|
||||
}
|
||||
PatKind::Guard(subpat, condition) => {
|
||||
self.popen();
|
||||
self.print_pat(subpat);
|
||||
self.space();
|
||||
self.word_space("if");
|
||||
self.print_expr(condition, FixupContext::default());
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Slice(elts) => {
|
||||
self.word("[");
|
||||
self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use itertools::{Itertools, Position};
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{
|
||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||
FormatDebugHex, FormatSign, FormatTrait, token,
|
||||
|
|
@ -58,10 +58,6 @@ impl<'a> State<'a> {
|
|||
self.pclose()
|
||||
}
|
||||
|
||||
fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8, fixup: FixupContext) {
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < prec, fixup);
|
||||
}
|
||||
|
||||
/// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
|
||||
/// `if cond { ... }`.
|
||||
fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
|
||||
|
|
@ -216,9 +212,9 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let prec = match func.kind {
|
||||
ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
|
||||
_ => parser::PREC_UNAMBIGUOUS,
|
||||
let needs_paren = match func.kind {
|
||||
ast::ExprKind::Field(..) => true,
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
|
|
@ -237,7 +233,7 @@ impl<'a> State<'a> {
|
|||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_maybe_paren(func, prec, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
|
||||
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
|
@ -258,7 +254,11 @@ impl<'a> State<'a> {
|
|||
// boundaries, `$receiver.method()` can be parsed back as a statement
|
||||
// containing an expression if and only if `$receiver` can be parsed as
|
||||
// a statement containing an expression.
|
||||
self.print_expr_maybe_paren(receiver, parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(
|
||||
receiver,
|
||||
receiver.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
|
|
@ -276,21 +276,22 @@ impl<'a> State<'a> {
|
|||
fixup: FixupContext,
|
||||
) {
|
||||
let assoc_op = AssocOp::from_ast_binop(op.node);
|
||||
let prec = assoc_op.precedence() as i8;
|
||||
let fixity = assoc_op.fixity();
|
||||
let binop_prec = assoc_op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
|
||||
let (left_prec, right_prec) = match fixity {
|
||||
Fixity::Left => (prec, prec + 1),
|
||||
Fixity::Right => (prec + 1, prec),
|
||||
Fixity::None => (prec + 1, prec + 1),
|
||||
let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec),
|
||||
Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec),
|
||||
};
|
||||
|
||||
let left_prec = match (&lhs.kind, op.node) {
|
||||
match (&lhs.kind, op.node) {
|
||||
// These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
|
||||
// the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
|
||||
// of `(x as i32) < ...`. We need to convince it _not_ to do that.
|
||||
(&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
left_needs_paren = true;
|
||||
}
|
||||
// We are given `(let _ = a) OP b`.
|
||||
//
|
||||
|
|
@ -300,23 +301,25 @@ impl<'a> State<'a> {
|
|||
// - Otherwise, e.g. when we have `(let a = b) < c` in AST,
|
||||
// parens are required since the parser would interpret `let a = b < c` as
|
||||
// `let a = (b < c)`. To achieve this, we force parens.
|
||||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
|
||||
parser::PREC_FORCE_PAREN
|
||||
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(binop_prec) => {
|
||||
left_needs_paren = true;
|
||||
}
|
||||
_ => left_prec,
|
||||
};
|
||||
|
||||
self.print_expr_maybe_paren(lhs, left_prec, fixup.leftmost_subexpression());
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
|
||||
self.space();
|
||||
self.word_space(op.node.as_str());
|
||||
|
||||
self.print_expr_maybe_paren(rhs, right_prec, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(
|
||||
|
|
@ -334,7 +337,11 @@ impl<'a> State<'a> {
|
|||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) {
|
||||
|
|
@ -416,8 +423,11 @@ impl<'a> State<'a> {
|
|||
self.print_token_literal(lit, expr.span)
|
||||
}
|
||||
ast::ExprKind::Cast(expr, ty) => {
|
||||
let prec = AssocOp::As.precedence() as i8;
|
||||
self.print_expr_maybe_paren(expr, prec, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Cast,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
self.word_space("as");
|
||||
self.print_type(ty);
|
||||
|
|
@ -490,7 +500,11 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
}
|
||||
MatchKind::Postfix => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word_nbsp(".match");
|
||||
}
|
||||
}
|
||||
|
|
@ -550,33 +564,57 @@ impl<'a> State<'a> {
|
|||
self.print_block_with_attrs(blk, attrs);
|
||||
}
|
||||
ast::ExprKind::Await(expr, _) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word(".await");
|
||||
}
|
||||
ast::ExprKind::Assign(lhs, rhs, _) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
lhs,
|
||||
// Ranges are allowed on the right-hand side of assignment,
|
||||
// but not the left. `(a..b) = c` needs parentheses.
|
||||
lhs.precedence() <= ExprPrecedence::Range,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
let prec = AssocOp::Assign.precedence() as i8;
|
||||
self.print_expr_maybe_paren(lhs, prec + 1, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
lhs,
|
||||
lhs.precedence() <= ExprPrecedence::Range,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.space();
|
||||
self.word(op.node.as_str());
|
||||
self.word_space("=");
|
||||
self.print_expr_maybe_paren(rhs, prec, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup,
|
||||
);
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
self.print_expr_maybe_paren(
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
parser::PREC_UNAMBIGUOUS,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
self.word("[");
|
||||
|
|
@ -588,16 +626,24 @@ impl<'a> State<'a> {
|
|||
// than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
|
||||
// Here we use a fake precedence value so that any child with lower precedence than
|
||||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = AssocOp::LOr.precedence() as i8;
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.leftmost_subexpression(),
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
ast::RangeLimits::Closed => self.word("..="),
|
||||
}
|
||||
if let Some(e) = end {
|
||||
self.print_expr_maybe_paren(e, fake_prec, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Underscore => self.word("_"),
|
||||
|
|
@ -615,7 +661,7 @@ impl<'a> State<'a> {
|
|||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence() < parser::PREC_JUMP
|
||||
expr.precedence() < ExprPrecedence::Jump
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
|
|
@ -632,9 +678,9 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
|
@ -645,9 +691,9 @@ impl<'a> State<'a> {
|
|||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
|
@ -655,9 +701,9 @@ impl<'a> State<'a> {
|
|||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_maybe_paren(
|
||||
self.print_expr_cond_paren(
|
||||
result,
|
||||
parser::PREC_JUMP,
|
||||
result.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
|
|
@ -709,15 +755,15 @@ impl<'a> State<'a> {
|
|||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_maybe_paren(
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
parser::PREC_JUMP,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Try(e) => {
|
||||
self.print_expr_maybe_paren(e, parser::PREC_UNAMBIGUOUS, fixup);
|
||||
self.print_expr_cond_paren(e, e.precedence() < ExprPrecedence::Unambiguous, fixup);
|
||||
self.word("?")
|
||||
}
|
||||
ast::ExprKind::TryBlock(blk) => {
|
||||
|
|
|
|||
|
|
@ -1151,7 +1151,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
expr: &hir::Expr<'_>,
|
||||
) {
|
||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return };
|
||||
let hir::ExprKind::Struct(struct_qpath, fields, hir::StructTailExpr::Base(base)) =
|
||||
expr.kind
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let hir::QPath::Resolved(_, path) = struct_qpath else { return };
|
||||
let hir::def::Res::Def(_, def_id) = path.res else { return };
|
||||
let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return };
|
||||
|
|
@ -1239,7 +1243,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
expr: &'tcx hir::Expr<'tcx>,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) {
|
||||
if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind {
|
||||
if let hir::ExprKind::Struct(_, _, hir::StructTailExpr::Base(_)) = expr.kind {
|
||||
// We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single
|
||||
// `Location` that covers both the `S { ... }` literal, all of its fields and the
|
||||
// `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr`
|
||||
|
|
@ -1450,6 +1454,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
ty::Param(param_ty) => Ok((
|
||||
generics.type_param(param_ty, tcx),
|
||||
predicate.trait_ref.print_trait_sugared().to_string(),
|
||||
Some(predicate.trait_ref.def_id),
|
||||
)),
|
||||
_ => Err(()),
|
||||
}
|
||||
|
|
@ -1463,9 +1468,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
tcx,
|
||||
hir_generics,
|
||||
err,
|
||||
predicates
|
||||
.iter()
|
||||
.map(|(param, constraint)| (param.name.as_str(), &**constraint, None)),
|
||||
predicates.iter().map(|(param, constraint, def_id)| {
|
||||
(param.name.as_str(), &**constraint, *def_id)
|
||||
}),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_data_structures::graph::dominators::Dominators;
|
|||
use rustc_errors::Diag;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
|
||||
use rustc_index::bit_set::{BitSet, MixedBitSet};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
|
|
@ -34,6 +34,7 @@ use rustc_infer::infer::{
|
|||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
|
|
@ -502,7 +503,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
|
|||
for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) {
|
||||
// HIR typeck did not infer the regions of the opaque, so we instantiate
|
||||
// them with fresh inference variables.
|
||||
let (key, hidden_ty) = tcx.fold_regions(data, |_, _| {
|
||||
let (key, hidden_ty) = fold_regions(tcx, data, |_, _| {
|
||||
self.next_nll_region_var_in_universe(
|
||||
NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
ty::UniverseIndex::ROOT,
|
||||
|
|
@ -1796,7 +1797,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
maybe_uninits: &ChunkedBitSet<MovePathIndex>,
|
||||
maybe_uninits: &MixedBitSet<MovePathIndex>,
|
||||
from: u64,
|
||||
to: u64,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_middle::mir::{
|
|||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -972,25 +973,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
) -> bool {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
let TypeTest { generic_kind, lower_bound, span: _, verify_bound: _ } = type_test;
|
||||
let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
debug!("subject = {:?}", subject);
|
||||
|
||||
let r_scc = self.constraint_sccs.scc(*lower_bound);
|
||||
|
||||
let r_scc = self.constraint_sccs.scc(lower_bound);
|
||||
debug!(
|
||||
"lower_bound = {:?} r_scc={:?} universe={:?}",
|
||||
lower_bound,
|
||||
r_scc,
|
||||
self.constraint_sccs.annotation(r_scc).min_universe()
|
||||
);
|
||||
|
||||
// If the type test requires that `T: 'a` where `'a` is a
|
||||
// placeholder from another universe, that effectively requires
|
||||
// `T: 'static`, so we have to propagate that requirement.
|
||||
|
|
@ -1003,7 +999,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject,
|
||||
outlived_free_region: static_r,
|
||||
blame_span: type_test.span,
|
||||
blame_span,
|
||||
category: ConstraintCategory::Boring,
|
||||
});
|
||||
|
||||
|
|
@ -1030,12 +1026,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// where `ur` is a local bound -- we are sometimes in a
|
||||
// position to prove things that our caller cannot. See
|
||||
// #53570 for an example.
|
||||
if self.eval_verify_bound(infcx, generic_ty, ur, &type_test.verify_bound) {
|
||||
if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
|
||||
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
|
||||
debug!(?non_local_ub);
|
||||
|
||||
// This is slightly too conservative. To show T: '1, given `'2: '1`
|
||||
// and `'3: '1` we only need to prove that T: '2 *or* T: '3, but to
|
||||
|
|
@ -1048,10 +1044,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let requirement = ClosureOutlivesRequirement {
|
||||
subject,
|
||||
outlived_free_region: upper_bound,
|
||||
blame_span: type_test.span,
|
||||
blame_span,
|
||||
category: ConstraintCategory::Boring,
|
||||
};
|
||||
debug!("try_promote_type_test: pushing {:#?}", requirement);
|
||||
debug!(?requirement, "adding closure requirement");
|
||||
propagated_outlives_requirements.push(requirement);
|
||||
}
|
||||
}
|
||||
|
|
@ -1062,45 +1058,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// variables in the type `T` with an equal universal region from the
|
||||
/// closure signature.
|
||||
/// This is not always possible, so this is a fallible process.
|
||||
#[instrument(level = "debug", skip(self, infcx))]
|
||||
#[instrument(level = "debug", skip(self, infcx), ret)]
|
||||
fn try_promote_type_test_subject(
|
||||
&self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<ClosureOutlivesSubject<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
// Opaque types' args may include useless lifetimes.
|
||||
// We will replace them with ReStatic.
|
||||
struct OpaqueFolder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
use ty::TypeSuperFoldable as _;
|
||||
let tcx = self.tcx;
|
||||
let &ty::Alias(ty::Opaque, ty::AliasTy { args, def_id, .. }) = t.kind() else {
|
||||
return t.super_fold_with(self);
|
||||
};
|
||||
let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| {
|
||||
match (arg.unpack(), v) {
|
||||
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => {
|
||||
tcx.lifetimes.re_static.into()
|
||||
}
|
||||
_ => arg.fold_with(self),
|
||||
}
|
||||
});
|
||||
Ty::new_opaque(tcx, def_id, tcx.mk_args_from_iter(args))
|
||||
}
|
||||
}
|
||||
|
||||
let ty = ty.fold_with(&mut OpaqueFolder { tcx });
|
||||
let mut failed = false;
|
||||
|
||||
let ty = tcx.fold_regions(ty, |r, _depth| {
|
||||
let ty = fold_regions(tcx, ty, |r, _depth| {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
let r_scc = self.constraint_sccs.scc(r_vid);
|
||||
|
||||
|
|
@ -1273,7 +1239,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
tcx.fold_regions(value, |r, _db| {
|
||||
fold_regions(tcx, value, |r, _db| {
|
||||
let vid = self.to_region_vid(r);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
let repr = self.scc_representative(scc);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
|
||||
|
|
@ -117,7 +118,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
});
|
||||
debug!(?opaque_type_key, ?arg_regions);
|
||||
|
||||
let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| {
|
||||
let concrete_type = fold_regions(infcx.tcx, concrete_type, |region, _| {
|
||||
arg_regions
|
||||
.iter()
|
||||
.find(|&&(arg_vid, _)| self.eval_equal(region.as_var(), arg_vid))
|
||||
|
|
@ -204,7 +205,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
tcx.fold_regions(ty, |region, _| match *region {
|
||||
fold_regions(tcx, ty, |region, _| match *region {
|
||||
ty::ReVar(vid) => {
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
|
||||
|
|
@ -442,7 +443,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
|
|||
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
|
||||
|
||||
let mut seen = vec![tcx.lifetimes.re_static];
|
||||
let canonical_args = tcx.fold_regions(args, |r1, _| {
|
||||
let canonical_args = fold_regions(tcx, args, |r1, _| {
|
||||
if r1.is_error() {
|
||||
r1
|
||||
} else if let Some(&r2) = seen.iter().find(|&&r2| {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use rustc_index::IndexSlice;
|
|||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Symbol;
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -68,7 +69,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
|
|||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
|
||||
self.infcx.tcx.fold_regions(value, |_region, _depth| {
|
||||
fold_regions(self.infcx.tcx, value, |_region, _depth| {
|
||||
self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::ScrubbedTraitError;
|
||||
|
|
@ -216,7 +217,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
/// are dealt with during trait solving.
|
||||
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
|
||||
if value.has_placeholders() {
|
||||
self.tcx.fold_regions(value, |r, _| match *r {
|
||||
fold_regions(self.tcx, value, |r, _| match *r {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
|
||||
|
|
@ -213,7 +214,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
|
||||
// Convert all regions to nll vars.
|
||||
let (opaque_type_key, hidden_type) =
|
||||
infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| {
|
||||
fold_regions(infcx.tcx, (opaque_type_key, hidden_type), |region, _| {
|
||||
match region.kind() {
|
||||
ty::ReVar(_) => region,
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
|
|
@ -2073,7 +2074,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
|
||||
let is_implicit_coercion = coercion_source == CoercionSource::Implicit;
|
||||
let unsize_to = tcx.fold_regions(ty, |r, _| {
|
||||
let unsize_to = fold_regions(tcx, ty, |r, _| {
|
||||
if let ty::ReVar(_) = r.kind() { tcx.lifetimes.re_erased } else { r }
|
||||
});
|
||||
self.prove_trait_ref(
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, fold_regions};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty,
|
||||
TyCtxt, TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{ErrorGuaranteed, Symbol};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
|
|
@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
|
||||
let reg_vid = self
|
||||
.infcx
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("c-variadic")))
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(sym::c_dash_variadic))
|
||||
.as_var();
|
||||
|
||||
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
|
||||
|
|
@ -540,10 +540,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let fr_fn_body = self
|
||||
.infcx
|
||||
.next_nll_region_var(FR, || RegionCtxt::Free(Symbol::intern("fn_body")))
|
||||
.as_var();
|
||||
let fr_fn_body =
|
||||
self.infcx.next_nll_region_var(FR, || RegionCtxt::Free(sym::fn_body)).as_var();
|
||||
|
||||
let num_universals = self.infcx.num_region_vars();
|
||||
|
||||
|
|
@ -824,7 +822,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.infcx.tcx.fold_regions(value, |region, _depth| {
|
||||
fold_regions(self.infcx.tcx, value, |region, _depth| {
|
||||
let name = region.get_name_or_anon();
|
||||
debug!(?region, ?name);
|
||||
|
||||
|
|
@ -906,7 +904,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
tcx.fold_regions(value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region)))
|
||||
fold_regions(tcx, value, |region, _| ty::Region::new_var(tcx, self.to_region_vid(region)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,21 @@ builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path
|
|||
builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
|
||||
builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
|
||||
builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
|
||||
|
||||
builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_generic = `CoercePointee` can only be derived on `struct`s that are generic over at least one type
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_pointee = exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
|
||||
|
||||
builtin_macros_coerce_pointee_requires_transparent = `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
|
||||
|
||||
builtin_macros_coerce_pointee_too_many_pointees = only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
|
||||
.label = here another type parameter is marked as `#[pointee]`
|
||||
|
||||
|
||||
builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
|
||||
.note = byte strings are treated as arrays of bytes
|
||||
.help = try flattening the array
|
||||
|
|
@ -246,7 +261,7 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
|||
|
||||
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants{$post}
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_only_one_argument = {$name} takes 1 argument
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_ast::{
|
|||
use rustc_attr as attr;
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_span::symbol::{Ident, sym};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
|
@ -38,12 +39,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
.any(|r| matches!(r, attr::ReprTransparent))
|
||||
});
|
||||
if !is_transparent {
|
||||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
)
|
||||
.emit();
|
||||
cx.dcx().emit_err(RequireTransparent { span });
|
||||
return;
|
||||
}
|
||||
if !matches!(
|
||||
|
|
@ -51,22 +47,12 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
|
||||
if !fields.is_empty())
|
||||
{
|
||||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`CoercePointee` can only be derived on `struct`s with at least one field",
|
||||
)
|
||||
.emit();
|
||||
cx.dcx().emit_err(RequireOneField { span });
|
||||
return;
|
||||
}
|
||||
(aitem.ident, g)
|
||||
} else {
|
||||
cx.dcx()
|
||||
.struct_span_err(
|
||||
span,
|
||||
"`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
|
||||
)
|
||||
.emit();
|
||||
cx.dcx().emit_err(RequireTransparent { span });
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -95,10 +81,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
|
||||
let pointee_param_idx = if type_params.is_empty() {
|
||||
// `#[derive(CoercePointee)]` requires at least one generic type on the target `struct`
|
||||
cx.dcx().struct_span_err(
|
||||
span,
|
||||
"`CoercePointee` can only be derived on `struct`s that are generic over at least one type",
|
||||
).emit();
|
||||
cx.dcx().emit_err(RequireOneGeneric { span });
|
||||
return;
|
||||
} else if type_params.len() == 1 {
|
||||
// Regardless of the only type param being designed as `#[pointee]` or not, we can just use it as such
|
||||
|
|
@ -111,19 +94,11 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
match (pointees.next(), pointees.next()) {
|
||||
(Some((idx, _span)), None) => idx,
|
||||
(None, _) => {
|
||||
cx.dcx().struct_span_err(
|
||||
span,
|
||||
"exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits",
|
||||
).emit();
|
||||
cx.dcx().emit_err(RequireOnePointee { span });
|
||||
return;
|
||||
}
|
||||
(Some((_, one)), Some((_, another))) => {
|
||||
cx.dcx()
|
||||
.struct_span_err(
|
||||
vec![one, another],
|
||||
"only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits",
|
||||
)
|
||||
.emit();
|
||||
cx.dcx().emit_err(TooManyPointees { one, another });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -181,15 +156,10 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
pointee_ty_ident.name,
|
||||
)
|
||||
{
|
||||
cx.dcx()
|
||||
.struct_span_err(
|
||||
pointee_ty_ident.span,
|
||||
format!(
|
||||
"`derive(CoercePointee)` requires {} to be marked `?Sized`",
|
||||
pointee_ty_ident.name
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
cx.dcx().emit_err(RequiresMaybeSized {
|
||||
span: pointee_ty_ident.span,
|
||||
name: pointee_ty_ident.name.to_ident_string(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
let arg = GenericArg::Type(s_ty.clone());
|
||||
|
|
@ -459,3 +429,48 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_transparent)]
|
||||
struct RequireTransparent {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_field)]
|
||||
struct RequireOneField {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_generic)]
|
||||
struct RequireOneGeneric {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_pointee)]
|
||||
struct RequireOnePointee {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_too_many_pointees)]
|
||||
struct TooManyPointees {
|
||||
#[primary_span]
|
||||
one: Span,
|
||||
#[label]
|
||||
another: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized)]
|
||||
struct RequiresMaybeSized {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ where
|
|||
let fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, &(ident, span))| {
|
||||
.map(|(i, &(ident, span, _))| {
|
||||
let arg = getarg(cx, span, ident.name, i);
|
||||
cx.field_imm(span, ident, arg)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -54,26 +54,38 @@ pub(crate) fn expand_deriving_default(
|
|||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
fn default_call(cx: &ExtCtxt<'_>, span: Span) -> ast::ptr::P<ast::Expr> {
|
||||
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
|
||||
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
|
||||
cx.expr_call_global(span, default_ident, ThinVec::new())
|
||||
}
|
||||
|
||||
fn default_struct_substructure(
|
||||
cx: &ExtCtxt<'_>,
|
||||
trait_span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
summary: &StaticFields,
|
||||
) -> BlockOrExpr {
|
||||
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
|
||||
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
|
||||
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new());
|
||||
|
||||
let expr = match summary {
|
||||
Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident),
|
||||
Unnamed(fields, IsTuple::Yes) => {
|
||||
let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
|
||||
let exprs = fields.iter().map(|sp| default_call(cx, *sp)).collect();
|
||||
cx.expr_call_ident(trait_span, substr.type_ident, exprs)
|
||||
}
|
||||
Named(fields) => {
|
||||
let default_fields = fields
|
||||
.iter()
|
||||
.map(|&(ident, span)| cx.field_imm(span, ident, default_call(span)))
|
||||
.map(|(ident, span, default_val)| {
|
||||
let value = match default_val {
|
||||
// We use `Default::default()`.
|
||||
None => default_call(cx, *span),
|
||||
// We use the field default const expression.
|
||||
Some(val) => {
|
||||
cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone()))
|
||||
}
|
||||
};
|
||||
cx.field_imm(*span, *ident, value)
|
||||
})
|
||||
.collect();
|
||||
cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
|
||||
}
|
||||
|
|
@ -93,10 +105,38 @@ fn default_enum_substructure(
|
|||
} {
|
||||
Ok(default_variant) => {
|
||||
// We now know there is exactly one unit variant with exactly one `#[default]` attribute.
|
||||
cx.expr_path(cx.path(default_variant.span, vec![
|
||||
Ident::new(kw::SelfUpper, default_variant.span),
|
||||
default_variant.ident,
|
||||
]))
|
||||
match &default_variant.data {
|
||||
VariantData::Unit(_) => cx.expr_path(cx.path(default_variant.span, vec![
|
||||
Ident::new(kw::SelfUpper, default_variant.span),
|
||||
default_variant.ident,
|
||||
])),
|
||||
VariantData::Struct { fields, .. } => {
|
||||
// This only happens if `#![feature(default_field_values)]`. We have validated
|
||||
// all fields have default values in the definition.
|
||||
let default_fields = fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
cx.field_imm(field.span, field.ident.unwrap(), match &field.default {
|
||||
// We use `Default::default()`.
|
||||
None => default_call(cx, field.span),
|
||||
// We use the field default const expression.
|
||||
Some(val) => {
|
||||
cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone()))
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let path = cx.path(default_variant.span, vec![
|
||||
Ident::new(kw::SelfUpper, default_variant.span),
|
||||
default_variant.ident,
|
||||
]);
|
||||
cx.expr_struct(default_variant.span, path, default_fields)
|
||||
}
|
||||
// Logic error in `extract_default_variant`.
|
||||
VariantData::Tuple(..) => {
|
||||
cx.dcx().bug("encountered tuple variant annotated with `#[default]`")
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)),
|
||||
};
|
||||
|
|
@ -156,8 +196,20 @@ fn extract_default_variant<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
if !matches!(variant.data, VariantData::Unit(..)) {
|
||||
let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
|
||||
if cx.ecfg.features.default_field_values()
|
||||
&& let VariantData::Struct { fields, .. } = &variant.data
|
||||
&& fields.iter().all(|f| f.default.is_some())
|
||||
// Disallow `#[default] Variant {}`
|
||||
&& !fields.is_empty()
|
||||
{
|
||||
// Allowed
|
||||
} else if !matches!(variant.data, VariantData::Unit(..)) {
|
||||
let post = if cx.ecfg.features.default_field_values() {
|
||||
" or variants where every field has a default value"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span, post });
|
||||
return Err(guar);
|
||||
}
|
||||
|
||||
|
|
@ -216,7 +268,12 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
|
|||
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
|
||||
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
|
||||
if attr.has_name(kw::Default) {
|
||||
self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span });
|
||||
let post = if self.cx.ecfg.features.default_field_values() {
|
||||
" or variants where every field has a default value"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span, post });
|
||||
}
|
||||
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ pub(crate) use StaticFields::*;
|
|||
pub(crate) use SubstructureFields::*;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
||||
Mutability, PatKind, VariantData,
|
||||
self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
|
||||
Generics, Mutability, PatKind, VariantData,
|
||||
};
|
||||
use rustc_attr as attr;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
|
|
@ -296,7 +296,7 @@ pub(crate) enum StaticFields {
|
|||
/// Tuple and unit structs/enum variants like this.
|
||||
Unnamed(Vec<Span>, IsTuple),
|
||||
/// Normal structs/struct variants.
|
||||
Named(Vec<(Ident, Span)>),
|
||||
Named(Vec<(Ident, Span, Option<AnonConst>)>),
|
||||
}
|
||||
|
||||
/// A summary of the possible sets of fields.
|
||||
|
|
@ -1435,7 +1435,7 @@ impl<'a> TraitDef<'a> {
|
|||
for field in struct_def.fields() {
|
||||
let sp = field.span.with_ctxt(self.span.ctxt());
|
||||
match field.ident {
|
||||
Some(ident) => named_idents.push((ident, sp)),
|
||||
Some(ident) => named_idents.push((ident, sp, field.default.clone())),
|
||||
_ => just_spans.push(sp),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@ pub(crate) struct MultipleDefaultsSugg {
|
|||
pub(crate) struct NonUnitDefault {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) post: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(not(bootstrap), feature(autodiff))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(autodiff)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
|
|||
|
|
@ -46,24 +46,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5e7afe85cadb55c4c1176268a2ac046fdff8dfaeca39e18581b9dc319ca9e"
|
||||
checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ab25ef3be935a80680e393183e1f94ef507e93a24a8369494d2c6818aedb3e3"
|
||||
checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900a19b84545924f1851cbfe386962edfc4ecbc3366a254825cf1ecbcda8ba08"
|
||||
checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-bforest",
|
||||
|
|
@ -78,48 +78,49 @@ dependencies = [
|
|||
"log",
|
||||
"regalloc2",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c73b2395ffe9e7b4fdf7e2ebc052e7e27af13f68a964985346be4da477a5fc"
|
||||
checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d9ed0854e96a4ff0879bff39d078de8dea7f002721c9494c1fdb4e1baa86ccc"
|
||||
checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4aca921dd422e781409de0129c255768fec5dec1dae83239b497fb9138abb89"
|
||||
checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d770e6605eccee15b49decdd82cd26f2b6404767802471459ea49c57379a98"
|
||||
checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29268711cb889cb39215b10faf88b9087d4c9e1d2633581e4f722a2bf4bb4ef9"
|
||||
checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
|
@ -129,15 +130,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc65156f010aed1985767ad1bff0eb8d186743b7b03e23d0c17604a253e3f356"
|
||||
checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ba6b46367a4f466cfb1abe32793fa1a0f96d862251491b01a44726b8ed9445"
|
||||
checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -155,9 +156,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "007607022a4883ebdffc46c0925e2e10babf2a565ae78518034ade722aa825d2"
|
||||
checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -166,9 +167,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8bf9b361eaf5a7627647270fabf1dc910d993edbeaf272a652c107861ebe9c2"
|
||||
checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
|
|
@ -177,9 +178,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ca5c38fa00c0cd943035391bdcc84ed00748f17c66c682e410f5a62f234d44"
|
||||
checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -363,6 +364,26 @@ dependencies = [
|
|||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slice-group-by"
|
||||
version = "0.3.1"
|
||||
|
|
@ -412,9 +433,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||
|
||||
[[package]]
|
||||
name = "wasmtime-jit-icache-coherence"
|
||||
version = "26.0.0"
|
||||
version = "27.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e458e6a1a010a53f86ac8d75837c0c6b2ce3e54b7503b2f1dc5629a4a541f5a"
|
||||
checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.113.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.113.0" }
|
||||
cranelift-module = { version = "0.113.0" }
|
||||
cranelift-native = { version = "0.113.0" }
|
||||
cranelift-jit = { version = "0.113.0", optional = true }
|
||||
cranelift-object = { version = "0.113.0" }
|
||||
cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.114.0" }
|
||||
cranelift-module = { version = "0.114.0" }
|
||||
cranelift-native = { version = "0.114.0" }
|
||||
cranelift-jit = { version = "0.114.0", optional = true }
|
||||
cranelift-object = { version = "0.114.0" }
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.31", default-features = false, features = ["write"] }
|
||||
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::path::{Dirs, RelPath};
|
||||
use crate::path::Dirs;
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::utils::{CargoProject, Compiler, spawn_and_wait};
|
||||
use crate::{CodegenBackend, SysrootKind, build_sysroot};
|
||||
|
|
@ -20,7 +20,7 @@ pub(crate) fn run(
|
|||
rustup_toolchain_name: Option<&str>,
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
) {
|
||||
RelPath::DOWNLOAD.ensure_exists(dirs);
|
||||
std::fs::create_dir_all(&dirs.download_dir).unwrap();
|
||||
ABI_CAFE_REPO.fetch(dirs);
|
||||
ABI_CAFE_REPO.patch(dirs);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::io::Write;
|
|||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::path::{Dirs, RelPath};
|
||||
use crate::path::Dirs;
|
||||
use crate::prepare::GitRepo;
|
||||
use crate::rustc_info::get_file_name;
|
||||
use crate::utils::{Compiler, spawn_and_wait};
|
||||
|
|
@ -39,11 +39,11 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
};
|
||||
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif = RelPath::DIST
|
||||
.to_path(dirs)
|
||||
let cargo_clif = dirs
|
||||
.dist_dir
|
||||
.join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
|
||||
let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
|
||||
let target_dir = RelPath::BUILD.join("simple_raytracer").to_path(dirs);
|
||||
let target_dir = dirs.build_dir.join("simple_raytracer");
|
||||
|
||||
let clean_cmd = format!(
|
||||
"RUSTC=rustc cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
|
|
@ -68,7 +68,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let bench_compile_markdown = RelPath::DIST.to_path(dirs).join("bench_compile.md");
|
||||
let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md");
|
||||
|
||||
let bench_compile = hyperfine_command(
|
||||
1,
|
||||
|
|
@ -92,7 +92,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
|
||||
let bench_run_markdown = RelPath::DIST.to_path(dirs).join("bench_run.md");
|
||||
let bench_run_markdown = dirs.dist_dir.join("bench_run.md");
|
||||
|
||||
let raytracer_cg_llvm = Path::new(".").join(get_file_name(
|
||||
&bootstrap_host_compiler.rustc,
|
||||
|
|
@ -120,7 +120,7 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
],
|
||||
&bench_run_markdown,
|
||||
);
|
||||
bench_run.current_dir(RelPath::BUILD.to_path(dirs));
|
||||
bench_run.current_dir(&dirs.build_dir);
|
||||
spawn_and_wait(bench_run);
|
||||
|
||||
if let Some(gha_step_summary) = gha_step_summary.as_mut() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::rustc_info::get_file_name;
|
|||
use crate::shared_utils::{rustflags_from_env, rustflags_to_cmd_env};
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup};
|
||||
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::source("."), "cg_clif");
|
||||
|
||||
pub(crate) fn build_backend(
|
||||
dirs: &Dirs,
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ pub(crate) fn build_sysroot(
|
|||
|
||||
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
|
||||
|
||||
let dist_dir = RelPath::DIST.to_path(dirs);
|
||||
let dist_dir = &dirs.dist_dir;
|
||||
|
||||
ensure_empty_dir(&dist_dir);
|
||||
ensure_empty_dir(dist_dir);
|
||||
fs::create_dir_all(dist_dir.join("bin")).unwrap();
|
||||
fs::create_dir_all(dist_dir.join("lib")).unwrap();
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ pub(crate) fn build_sysroot(
|
|||
let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
|
||||
let wrapper_path = dist_dir.join(&wrapper_name);
|
||||
build_cargo_wrapper_cmd
|
||||
.arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
|
||||
.arg(dirs.source_dir.join("scripts").join(&format!("{wrapper}.rs")))
|
||||
.arg("-o")
|
||||
.arg(&wrapper_path)
|
||||
.arg("-Cstrip=debuginfo");
|
||||
|
|
@ -85,7 +85,7 @@ pub(crate) fn build_sysroot(
|
|||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
);
|
||||
host.install_into_sysroot(&dist_dir);
|
||||
host.install_into_sysroot(dist_dir);
|
||||
|
||||
if !is_native {
|
||||
build_sysroot_for_triple(
|
||||
|
|
@ -99,7 +99,7 @@ pub(crate) fn build_sysroot(
|
|||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
)
|
||||
.install_into_sysroot(&dist_dir);
|
||||
.install_into_sysroot(dist_dir);
|
||||
}
|
||||
|
||||
let mut target_compiler = {
|
||||
|
|
@ -143,10 +143,10 @@ impl SysrootTarget {
|
|||
}
|
||||
}
|
||||
|
||||
static STDLIB_SRC: RelPath = RelPath::BUILD.join("stdlib");
|
||||
static STDLIB_SRC: RelPath = RelPath::build("stdlib");
|
||||
static STANDARD_LIBRARY: CargoProject =
|
||||
CargoProject::new(&STDLIB_SRC.join("library/sysroot"), "stdlib_target");
|
||||
static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
|
||||
CargoProject::new(&RelPath::build("stdlib/library/sysroot"), "stdlib_target");
|
||||
static RTSTARTUP_SYSROOT: RelPath = RelPath::build("rtstartup");
|
||||
|
||||
fn build_sysroot_for_triple(
|
||||
dirs: &Dirs,
|
||||
|
|
@ -247,6 +247,7 @@ fn build_clif_sysroot_for_triple(
|
|||
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
|
||||
build_cmd.arg("--release");
|
||||
build_cmd.arg("--features").arg("backtrace panic-unwind compiler-builtins-no-f16-f128");
|
||||
build_cmd.arg(format!("-Zroot-dir={}", STDLIB_SRC.to_path(dirs).display()));
|
||||
build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
|
||||
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
|
||||
if compiler.triple.contains("apple") {
|
||||
|
|
@ -281,13 +282,14 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
|
|||
return None;
|
||||
}
|
||||
|
||||
RTSTARTUP_SYSROOT.ensure_fresh(dirs);
|
||||
let rtstartup_sysroot = RTSTARTUP_SYSROOT.to_path(dirs);
|
||||
ensure_empty_dir(&rtstartup_sysroot);
|
||||
|
||||
let rtstartup_src = STDLIB_SRC.to_path(dirs).join("library").join("rtstartup");
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
|
||||
|
||||
for file in ["rsbegin", "rsend"] {
|
||||
let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
|
||||
let obj = rtstartup_sysroot.join(format!("{file}.o"));
|
||||
let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
|
||||
build_rtstartup_cmd
|
||||
.arg("--target")
|
||||
|
|
|
|||
|
|
@ -185,12 +185,11 @@ fn main() {
|
|||
frozen,
|
||||
};
|
||||
|
||||
path::RelPath::BUILD.ensure_exists(&dirs);
|
||||
std::fs::create_dir_all(&dirs.build_dir).unwrap();
|
||||
|
||||
{
|
||||
// Make sure we always explicitly specify the target dir
|
||||
let target =
|
||||
path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
|
||||
let target = dirs.build_dir.join("target_dir_should_be_set_explicitly");
|
||||
env::set_var("CARGO_TARGET_DIR", &target);
|
||||
let _ = std::fs::remove_file(&target);
|
||||
std::fs::File::create(target).unwrap();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::utils::ensure_empty_dir;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Dirs {
|
||||
pub(crate) source_dir: PathBuf,
|
||||
|
|
@ -16,54 +13,34 @@ pub(crate) struct Dirs {
|
|||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum PathBase {
|
||||
Source,
|
||||
Download,
|
||||
Build,
|
||||
Dist,
|
||||
}
|
||||
|
||||
impl PathBase {
|
||||
fn to_path(self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
PathBase::Source => dirs.source_dir.clone(),
|
||||
PathBase::Download => dirs.download_dir.clone(),
|
||||
PathBase::Build => dirs.build_dir.clone(),
|
||||
PathBase::Dist => dirs.dist_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum RelPath {
|
||||
Base(PathBase),
|
||||
Join(&'static RelPath, &'static str),
|
||||
pub(crate) struct RelPath {
|
||||
base: PathBase,
|
||||
suffix: &'static str,
|
||||
}
|
||||
|
||||
impl RelPath {
|
||||
pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
|
||||
pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
|
||||
pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
|
||||
pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
|
||||
pub(crate) const fn source(suffix: &'static str) -> RelPath {
|
||||
RelPath { base: PathBase::Source, suffix }
|
||||
}
|
||||
|
||||
pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
|
||||
pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
|
||||
|
||||
pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
|
||||
RelPath::Join(self, suffix)
|
||||
pub(crate) const fn build(suffix: &'static str) -> RelPath {
|
||||
RelPath { base: PathBase::Build, suffix }
|
||||
}
|
||||
|
||||
pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
RelPath::Base(base) => base.to_path(dirs),
|
||||
RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
|
||||
fs::create_dir_all(self.to_path(dirs)).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
|
||||
let path = self.to_path(dirs);
|
||||
ensure_empty_dir(&path);
|
||||
self.base.to_path(dirs).join(self.suffix)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::path::{Dirs, RelPath};
|
|||
use crate::utils::{copy_dir_recursively, ensure_empty_dir, spawn_and_wait};
|
||||
|
||||
pub(crate) fn prepare(dirs: &Dirs) {
|
||||
RelPath::DOWNLOAD.ensure_exists(dirs);
|
||||
std::fs::create_dir_all(&dirs.download_dir).unwrap();
|
||||
crate::tests::RAND_REPO.fetch(dirs);
|
||||
crate::tests::REGEX_REPO.fetch(dirs);
|
||||
}
|
||||
|
|
@ -79,13 +79,13 @@ impl GitRepo {
|
|||
|
||||
fn download_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo).to_path(dirs),
|
||||
GitRepoUrl::Github { user: _, repo } => dirs.download_dir.join(repo),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn source_dir(&self) -> RelPath {
|
||||
match self.url {
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::BUILD.join(repo),
|
||||
GitRepoUrl::Github { user: _, repo } => RelPath::build(repo),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ impl GitRepo {
|
|||
}
|
||||
|
||||
let source_lockfile =
|
||||
RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name));
|
||||
dirs.source_dir.join("patches").join(format!("{}-lock.toml", self.patch_name));
|
||||
let target_lockfile = download_dir.join("Cargo.lock");
|
||||
if source_lockfile.exists() {
|
||||
assert!(!target_lockfile.exists());
|
||||
|
|
@ -191,7 +191,7 @@ fn init_git_repo(repo_dir: &Path) {
|
|||
}
|
||||
|
||||
fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
|
||||
let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
|
||||
let mut patches: Vec<_> = fs::read_dir(dirs.source_dir.join("patches"))
|
||||
.unwrap()
|
||||
.map(|entry| entry.unwrap().path())
|
||||
.filter(|path| path.extension() == Some(OsStr::new("patch")))
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ use crate::path::{Dirs, RelPath};
|
|||
use crate::prepare::{GitRepo, apply_patches};
|
||||
use crate::rustc_info::get_default_sysroot;
|
||||
use crate::shared_utils::rustflags_from_env;
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup, spawn_and_wait};
|
||||
use crate::utils::{CargoProject, Compiler, LogGroup, ensure_empty_dir, spawn_and_wait};
|
||||
use crate::{CodegenBackend, SysrootKind, build_sysroot, config};
|
||||
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
|
||||
static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::build("example");
|
||||
|
||||
struct TestCase {
|
||||
config: &'static str,
|
||||
|
|
@ -92,10 +92,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
|
||||
TestCase::custom("aot.polymorphize_coroutine", &|runner| {
|
||||
runner.run_rustc(&["example/polymorphize_coroutine.rs", "-Zpolymorphize"]);
|
||||
runner.run_out_command("polymorphize_coroutine", &[]);
|
||||
}),
|
||||
TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
|
||||
TestCase::custom("aot.gen_block_iterate", &|runner| {
|
||||
runner.run_rustc([
|
||||
|
|
@ -129,11 +125,11 @@ pub(crate) static REGEX_REPO: GitRepo = GitRepo::github(
|
|||
|
||||
static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex_target");
|
||||
|
||||
static PORTABLE_SIMD_SRC: RelPath = RelPath::BUILD.join("portable-simd");
|
||||
static PORTABLE_SIMD_SRC: RelPath = RelPath::build("portable-simd");
|
||||
|
||||
static PORTABLE_SIMD: CargoProject = CargoProject::new(&PORTABLE_SIMD_SRC, "portable-simd_target");
|
||||
|
||||
static LIBCORE_TESTS_SRC: RelPath = RelPath::BUILD.join("coretests");
|
||||
static LIBCORE_TESTS_SRC: RelPath = RelPath::build("coretests");
|
||||
|
||||
static LIBCORE_TESTS: CargoProject = CargoProject::new(&LIBCORE_TESTS_SRC, "coretests_target");
|
||||
|
||||
|
|
@ -162,7 +158,7 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
&LIBCORE_TESTS_SRC.to_path(&runner.dirs),
|
||||
);
|
||||
|
||||
let source_lockfile = RelPath::PATCHES.to_path(&runner.dirs).join("coretests-lock.toml");
|
||||
let source_lockfile = runner.dirs.source_dir.join("patches/coretests-lock.toml");
|
||||
let target_lockfile = LIBCORE_TESTS_SRC.to_path(&runner.dirs).join("Cargo.lock");
|
||||
fs::copy(source_lockfile, target_lockfile).unwrap();
|
||||
|
||||
|
|
@ -267,7 +263,9 @@ pub(crate) fn run_tests(
|
|||
stdlib_source.clone(),
|
||||
);
|
||||
|
||||
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
|
||||
let path = BUILD_EXAMPLE_OUT_DIR.to_path(dirs);
|
||||
ensure_empty_dir(&path);
|
||||
|
||||
runner.run_testsuite(NO_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] no_sysroot tests");
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ impl CargoProject {
|
|||
}
|
||||
|
||||
pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
|
||||
RelPath::BUILD.join(self.target).to_path(dirs)
|
||||
dirs.build_dir.join(self.target)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ aot.float-minmax-pass
|
|||
aot.mod_bench
|
||||
aot.issue-72793
|
||||
aot.issue-59326
|
||||
aot.polymorphize_coroutine
|
||||
aot.neon
|
||||
aot.gen_block_iterate
|
||||
aot.raw-dylib
|
||||
|
|
|
|||
|
|
@ -55,26 +55,26 @@ impl<T: ?Sized> LegacyReceiver for &mut T {}
|
|||
impl<T: ?Sized> LegacyReceiver for Box<T> {}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub unsafe trait Copy {}
|
||||
pub trait Copy {}
|
||||
|
||||
unsafe impl Copy for bool {}
|
||||
unsafe impl Copy for u8 {}
|
||||
unsafe impl Copy for u16 {}
|
||||
unsafe impl Copy for u32 {}
|
||||
unsafe impl Copy for u64 {}
|
||||
unsafe impl Copy for u128 {}
|
||||
unsafe impl Copy for usize {}
|
||||
unsafe impl Copy for i8 {}
|
||||
unsafe impl Copy for i16 {}
|
||||
unsafe impl Copy for i32 {}
|
||||
unsafe impl Copy for isize {}
|
||||
unsafe impl Copy for f32 {}
|
||||
unsafe impl Copy for f64 {}
|
||||
unsafe impl Copy for char {}
|
||||
unsafe impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
unsafe impl<T: ?Sized> Copy for *const T {}
|
||||
unsafe impl<T: ?Sized> Copy for *mut T {}
|
||||
unsafe impl<T: Copy> Copy for Option<T> {}
|
||||
impl Copy for bool {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for u16 {}
|
||||
impl Copy for u32 {}
|
||||
impl Copy for u64 {}
|
||||
impl Copy for u128 {}
|
||||
impl Copy for usize {}
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for isize {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for char {}
|
||||
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
impl<T: ?Sized> Copy for *const T {}
|
||||
impl<T: ?Sized> Copy for *mut T {}
|
||||
impl<T: Copy> Copy for Option<T> {}
|
||||
|
||||
#[lang = "sync"]
|
||||
pub unsafe trait Sync {}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
|
||||
|
||||
use std::ops::Coroutine;
|
||||
use std::pin::Pin;
|
||||
|
||||
fn main() {
|
||||
run_coroutine::<i32>();
|
||||
}
|
||||
|
||||
fn run_coroutine<T>() {
|
||||
let mut coroutine = #[coroutine]
|
||||
|| {
|
||||
yield;
|
||||
return;
|
||||
};
|
||||
Pin::new(&mut coroutine).resume(());
|
||||
}
|
||||
|
|
@ -8,6 +8,9 @@
|
|||
unboxed_closures
|
||||
)]
|
||||
#![allow(internal_features)]
|
||||
// FIXME once abi_unsupported_vector_types is a hard error disable the foo test when the respective
|
||||
// target feature is not enabled.
|
||||
#![allow(abi_unsupported_vector_types)]
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64::*;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644
|
|||
@@ -1,3 +1,4 @@
|
||||
+#![cfg(test)]
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_match))]
|
||||
--
|
||||
2.21.0 (Apple Git-122)
|
||||
|
|
|
|||
|
|
@ -14,10 +14,9 @@ diff --git a/lib.rs b/lib.rs
|
|||
index 1e336bf..35e6f54 100644
|
||||
--- a/lib.rs
|
||||
+++ b/lib.rs
|
||||
@@ -2,7 +2,6 @@
|
||||
#![cfg_attr(bootstrap, feature(const_three_way_compare))]
|
||||
#![cfg_attr(bootstrap, feature(strict_provenance))]
|
||||
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
|
||||
@@ -2,6 +2,5 @@
|
||||
#![cfg(test)]
|
||||
// tidy-alphabetical-start
|
||||
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_match))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
|
|
|
|||
|
|
@ -4,22 +4,23 @@ Date: Fri, 9 Aug 2024 15:44:51 +0000
|
|||
Subject: [PATCH] Disable f16 and f128 in compiler-builtins
|
||||
|
||||
---
|
||||
library/sysroot/Cargo.toml | 2 +-
|
||||
library/liballoc/Cargo.toml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
|
||||
diff --git a/library/liballoc/Cargo.toml b/library/liballoc/Cargo.toml
|
||||
index 7165c3e48af..968552ad435 100644
|
||||
--- a/library/sysroot/Cargo.toml
|
||||
+++ b/library/sysroot/Cargo.toml
|
||||
--- a/library/alloc/Cargo.toml
|
||||
+++ b/library/alloc/Cargo.toml
|
||||
@@ -11,7 +11,7 @@ test = { path = "../test" }
|
||||
edition = "2021"
|
||||
|
||||
# Forward features to the `std` crate as necessary
|
||||
[features]
|
||||
-default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
|
||||
+default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind", "compiler-builtins-no-f16-f128"]
|
||||
backtrace = ["std/backtrace"]
|
||||
compiler-builtins-c = ["std/compiler-builtins-c"]
|
||||
compiler-builtins-mem = ["std/compiler-builtins-mem"]
|
||||
[dependencies]
|
||||
core = { path = "../core" }
|
||||
-compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.138", features = ['rustc-dep-of-std', 'no-f16-f128'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-11-09"
|
||||
channel = "nightly-2024-12-06"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ fn main() {
|
|||
args.push(OsString::from("--sysroot"));
|
||||
args.push(OsString::from(sysroot.to_str().unwrap()));
|
||||
}
|
||||
if passed_args.is_empty() {
|
||||
// Don't pass any arguments when the user didn't pass any arguments
|
||||
// either to ensure the help message is shown.
|
||||
args.clear();
|
||||
}
|
||||
args.extend(passed_args);
|
||||
|
||||
let rustc = if let Some(rustc) = option_env!("RUSTC") {
|
||||
|
|
|
|||
|
|
@ -35,13 +35,14 @@ full-bootstrap = true
|
|||
local-rebuild = true
|
||||
|
||||
[rust]
|
||||
download-rustc = false
|
||||
codegen-backends = ["cranelift"]
|
||||
deny-warnings = false
|
||||
verbose-tests = false
|
||||
# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is
|
||||
# disabled bootstrap will crash trying to copy llvm tools for the bootstrap
|
||||
# compiler.
|
||||
llvm_tools = false
|
||||
llvm-tools = false
|
||||
|
||||
EOF
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -11,22 +11,5 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
|||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||
|
||||
# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch
|
||||
cat <<EOF | git apply -
|
||||
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
index 3394f2a84a0..cb980dd4d7c 100644
|
||||
--- a/src/bootstrap/src/core/build_steps/compile.rs
|
||||
+++ b/src/bootstrap/src/core/build_steps/compile.rs
|
||||
@@ -1976,7 +1976,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
- {
|
||||
+ if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
|
||||
// \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`,
|
||||
// so copy and rename \`llvm-objcopy\`.
|
||||
let src_exe = exe("llvm-objcopy", target_compiler.host);
|
||||
EOF
|
||||
|
||||
./x.py build --stage 1 library/std
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't
|
|||
rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
|
||||
rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes
|
||||
rm -r tests/run-make/embed-source-dwarf # embedding sources in debuginfo
|
||||
rm tests/ui/simd-abi-checks.rs # vector types >128bits not yet supported
|
||||
|
||||
# requires LTO
|
||||
rm -r tests/run-make/cdylib
|
||||
|
|
@ -75,6 +76,8 @@ rm -r tests/ui/instrument-coverage/
|
|||
rm tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
|
||||
rm tests/ui/asm/aarch64/type-f16.rs
|
||||
rm tests/ui/float/conv-bits-runtime-const.rs
|
||||
rm tests/ui/consts/const-eval/float_methods.rs
|
||||
rm tests/ui/match/match-float.rs
|
||||
|
||||
# optimization tests
|
||||
# ==================
|
||||
|
|
|
|||
|
|
@ -125,8 +125,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
returns: Vec<AbiParam>,
|
||||
args: &[Value],
|
||||
) -> Cow<'_, [Value]> {
|
||||
if self.tcx.sess.target.is_like_windows {
|
||||
let (mut params, mut args): (Vec<_>, Vec<_>) = params
|
||||
// Pass i128 arguments by-ref on Windows.
|
||||
let (params, args): (Vec<_>, Cow<'_, [_]>) = if self.tcx.sess.target.is_like_windows {
|
||||
let (params, args): (Vec<_>, Vec<_>) = params
|
||||
.into_iter()
|
||||
.zip(args)
|
||||
.map(|(param, &arg)| {
|
||||
|
|
@ -140,29 +141,42 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
})
|
||||
.unzip();
|
||||
|
||||
let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
|
||||
(params, args.into())
|
||||
} else {
|
||||
(params, args.into())
|
||||
};
|
||||
|
||||
if indirect_ret_val {
|
||||
params.insert(0, AbiParam::new(self.pointer_type));
|
||||
let ret_ptr = self.create_stack_slot(16, 16);
|
||||
args.insert(0, ret_ptr.get_addr(self));
|
||||
self.lib_call_unadjusted(name, params, vec![], &args);
|
||||
return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);
|
||||
// Return i128 using a return area pointer on Windows and s390x.
|
||||
let adjust_ret_param =
|
||||
if self.tcx.sess.target.is_like_windows || self.tcx.sess.target.arch == "s390x" {
|
||||
returns.len() == 1 && returns[0].value_type == types::I128
|
||||
} else {
|
||||
return self.lib_call_unadjusted(name, params, returns, &args);
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
self.lib_call_unadjusted(name, params, returns, args)
|
||||
if adjust_ret_param {
|
||||
let mut params = params;
|
||||
let mut args = args.to_vec();
|
||||
|
||||
params.insert(0, AbiParam::new(self.pointer_type));
|
||||
let ret_ptr = self.create_stack_slot(16, 16);
|
||||
args.insert(0, ret_ptr.get_addr(self));
|
||||
|
||||
self.lib_call_unadjusted(name, params, vec![], &args);
|
||||
|
||||
Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())])
|
||||
} else {
|
||||
Cow::Borrowed(self.lib_call_unadjusted(name, params, returns, &args))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lib_call_unadjusted(
|
||||
fn lib_call_unadjusted(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: Vec<AbiParam>,
|
||||
returns: Vec<AbiParam>,
|
||||
args: &[Value],
|
||||
) -> Cow<'_, [Value]> {
|
||||
) -> &[Value] {
|
||||
let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
|
||||
let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
|
||||
let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
|
||||
|
|
@ -175,7 +189,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
|
|||
}
|
||||
let results = self.bcx.inst_results(call_inst);
|
||||
assert!(results.len() <= 2, "{}", results.len());
|
||||
Cow::Borrowed(results)
|
||||
results
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,8 +394,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
def_id,
|
||||
fn_args,
|
||||
source_info.span,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
if target.is_some() {
|
||||
|
|
@ -684,7 +697,7 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
target: BasicBlock,
|
||||
) {
|
||||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty);
|
||||
|
||||
if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
|
||||
drop_instance.def
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
|||
use cranelift_module::ModuleError;
|
||||
use rustc_ast::InlineAsmOptions;
|
||||
use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::InlineAsmMacro;
|
||||
|
|
@ -16,6 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
|
||||
use crate::constant::ConstantCx;
|
||||
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
|
||||
use crate::enable_verifier;
|
||||
use crate::inline_asm::codegen_naked_asm;
|
||||
use crate::prelude::*;
|
||||
use crate::pretty_clif::CommentWriter;
|
||||
|
|
@ -169,12 +171,13 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
|
||||
pub(crate) fn compile_fn(
|
||||
cx: &mut crate::CodegenCx,
|
||||
profiler: &SelfProfilerRef,
|
||||
cached_context: &mut Context,
|
||||
module: &mut dyn Module,
|
||||
codegened_func: CodegenedFunction,
|
||||
) {
|
||||
let _timer =
|
||||
cx.profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name);
|
||||
profiler.generic_activity_with_arg("compile function", &*codegened_func.symbol_name);
|
||||
|
||||
let clif_comments = codegened_func.clif_comments;
|
||||
|
||||
|
|
@ -212,7 +215,7 @@ pub(crate) fn compile_fn(
|
|||
};
|
||||
|
||||
// Define function
|
||||
cx.profiler.generic_activity("define function").run(|| {
|
||||
profiler.generic_activity("define function").run(|| {
|
||||
context.want_disasm = cx.should_write_ir;
|
||||
match module.define_function(codegened_func.func_id, context) {
|
||||
Ok(()) => {}
|
||||
|
|
@ -253,7 +256,7 @@ pub(crate) fn compile_fn(
|
|||
|
||||
// Define debuginfo for function
|
||||
let debug_context = &mut cx.debug_context;
|
||||
cx.profiler.generic_activity("generate debug info").run(|| {
|
||||
profiler.generic_activity("generate debug info").run(|| {
|
||||
if let Some(debug_context) = debug_context {
|
||||
codegened_func.func_debug_cx.unwrap().finalize(
|
||||
debug_context,
|
||||
|
|
@ -264,11 +267,11 @@ pub(crate) fn compile_fn(
|
|||
});
|
||||
}
|
||||
|
||||
pub(crate) fn verify_func(
|
||||
tcx: TyCtxt<'_>,
|
||||
writer: &crate::pretty_clif::CommentWriter,
|
||||
func: &Function,
|
||||
) {
|
||||
fn verify_func(tcx: TyCtxt<'_>, writer: &crate::pretty_clif::CommentWriter, func: &Function) {
|
||||
if !enable_verifier(tcx.sess) {
|
||||
return;
|
||||
}
|
||||
|
||||
tcx.prof.generic_activity("verify clif ir").run(|| {
|
||||
let flags = cranelift_codegen::settings::Flags::new(cranelift_codegen::settings::builder());
|
||||
match cranelift_codegen::verify_function(&func, &flags) {
|
||||
|
|
@ -670,8 +673,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap()
|
||||
.polymorphize(fx.tcx),
|
||||
.unwrap(),
|
||||
);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, to_layout));
|
||||
|
|
@ -757,8 +759,7 @@ fn codegen_stmt<'tcx>(
|
|||
def_id,
|
||||
args,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
.polymorphize(fx.tcx);
|
||||
);
|
||||
let func_ref = fx.get_function_ref(instance);
|
||||
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
|
||||
lval.write_cvalue(fx, CValue::by_val(func_addr, lval.layout()));
|
||||
|
|
@ -1084,7 +1085,7 @@ fn codegen_panic_inner<'tcx>(
|
|||
|
||||
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
let instance = Instance::mono(fx.tcx, def_id);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
fx.bcx.ins().trap(TrapCode::user(2).unwrap());
|
||||
|
|
|
|||
|
|
@ -81,26 +81,6 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
match bin_op {
|
||||
BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
|
||||
BinOp::Add | BinOp::Sub => None,
|
||||
BinOp::Mul if is_signed => {
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
|
||||
let lhs = lhs.load_scalar(fx);
|
||||
let rhs = rhs.load_scalar(fx);
|
||||
let oflow_ptr = oflow.to_ptr().get_addr(fx);
|
||||
let res = fx.lib_call_unadjusted(
|
||||
"__muloti4",
|
||||
vec![
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(fx.pointer_type),
|
||||
],
|
||||
vec![AbiParam::new(types::I128)],
|
||||
&[lhs, rhs, oflow_ptr],
|
||||
)[0];
|
||||
let oflow = oflow.to_cvalue(fx).load_scalar(fx);
|
||||
let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
|
||||
Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
|
||||
}
|
||||
BinOp::Mul => {
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
|
||||
|
|
@ -110,7 +90,12 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
AbiParam::new(types::I128),
|
||||
];
|
||||
let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
fx.lib_call("__rust_u128_mulo", param_types, vec![], &args);
|
||||
fx.lib_call(
|
||||
if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
|
||||
param_types,
|
||||
vec![],
|
||||
&args,
|
||||
);
|
||||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
use std::env;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn bool_env_var(key: &str) -> bool {
|
||||
env::var(key).as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
/// The mode to use for compilation.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CodegenMode {
|
||||
|
|
@ -16,19 +9,6 @@ pub enum CodegenMode {
|
|||
JitLazy,
|
||||
}
|
||||
|
||||
impl FromStr for CodegenMode {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"aot" => Ok(CodegenMode::Aot),
|
||||
"jit" => Ok(CodegenMode::Jit),
|
||||
"jit-lazy" => Ok(CodegenMode::JitLazy),
|
||||
_ => Err(format!("Unknown codegen mode `{}`", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BackendConfig {
|
||||
|
|
@ -41,51 +21,22 @@ pub struct BackendConfig {
|
|||
///
|
||||
/// Defaults to the value of `CG_CLIF_JIT_ARGS`.
|
||||
pub jit_args: Vec<String>,
|
||||
|
||||
/// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
|
||||
/// once before passing the clif ir to Cranelift for compilation.
|
||||
///
|
||||
/// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
|
||||
/// compiled with debug assertions enabled or false otherwise. Can be set using
|
||||
/// `-Cllvm-args=enable_verifier=...`.
|
||||
pub enable_verifier: bool,
|
||||
|
||||
/// Don't cache object files in the incremental cache. Useful during development of cg_clif
|
||||
/// to make it possible to use incremental mode for all analyses performed by rustc without
|
||||
/// caching object files when their content should have been changed by a change to cg_clif.
|
||||
///
|
||||
/// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
|
||||
/// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
|
||||
pub disable_incr_cache: bool,
|
||||
}
|
||||
|
||||
impl Default for BackendConfig {
|
||||
fn default() -> Self {
|
||||
BackendConfig {
|
||||
codegen_mode: CodegenMode::Aot,
|
||||
jit_args: {
|
||||
match std::env::var("CG_CLIF_JIT_ARGS") {
|
||||
Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
|
||||
Err(std::env::VarError::NotPresent) => vec![],
|
||||
Err(std::env::VarError::NotUnicode(s)) => {
|
||||
panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
|
||||
}
|
||||
}
|
||||
},
|
||||
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
|
||||
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BackendConfig {
|
||||
/// Parse the configuration passed in using `-Cllvm-args`.
|
||||
pub fn from_opts(opts: &[String]) -> Result<Self, String> {
|
||||
fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
|
||||
value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
|
||||
}
|
||||
let mut config = BackendConfig {
|
||||
codegen_mode: CodegenMode::Aot,
|
||||
jit_args: match std::env::var("CG_CLIF_JIT_ARGS") {
|
||||
Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
|
||||
Err(std::env::VarError::NotPresent) => vec![],
|
||||
Err(std::env::VarError::NotUnicode(s)) => {
|
||||
panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut config = BackendConfig::default();
|
||||
for opt in opts {
|
||||
if opt.starts_with("-import-instr-limit") {
|
||||
// Silently ignore -import-instr-limit. It is set by rust's build system even when
|
||||
|
|
@ -94,9 +45,14 @@ impl BackendConfig {
|
|||
}
|
||||
if let Some((name, value)) = opt.split_once('=') {
|
||||
match name {
|
||||
"mode" => config.codegen_mode = value.parse()?,
|
||||
"enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
|
||||
"disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
|
||||
"mode" => {
|
||||
config.codegen_mode = match value {
|
||||
"aot" => CodegenMode::Aot,
|
||||
"jit" => CodegenMode::Jit,
|
||||
"jit-lazy" => CodegenMode::JitLazy,
|
||||
_ => return Err(format!("Unknown codegen mode `{}`", value)),
|
||||
};
|
||||
}
|
||||
_ => return Err(format!("Unknown option `{}`", name)),
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -452,8 +452,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
let data_id = match reloc_target_alloc {
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
assert_eq!(addend, 0);
|
||||
let func_id =
|
||||
crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
|
||||
let func_id = crate::abi::import_function(tcx, module, instance);
|
||||
let local_func_id = module.declare_func_in_data(func_id, &mut data);
|
||||
data.write_function_addr(offset.bytes() as u32, local_func_id);
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
|
||||
//! standalone executable.
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufWriter;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -25,13 +26,18 @@ use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType};
|
||||
|
||||
use crate::BackendConfig;
|
||||
use crate::CodegenCx;
|
||||
use crate::base::CodegenedFunction;
|
||||
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
||||
use crate::debuginfo::TypeDebugContext;
|
||||
use crate::global_asm::GlobalAsmConfig;
|
||||
use crate::prelude::*;
|
||||
use crate::unwind_module::UnwindModule;
|
||||
|
||||
fn disable_incr_cache() -> bool {
|
||||
env::var("CG_CLIF_DISABLE_INCR_CACHE").as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
struct ModuleCodegenResult {
|
||||
module_regular: CompiledModule,
|
||||
module_global_asm: Option<CompiledModule>,
|
||||
|
|
@ -63,10 +69,10 @@ impl OngoingCodegen {
|
|||
self,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
backend_config: &BackendConfig,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let mut work_products = FxIndexMap::default();
|
||||
let mut modules = vec![];
|
||||
let disable_incr_cache = disable_incr_cache();
|
||||
|
||||
for module_codegen in self.modules {
|
||||
let module_codegen_result = match module_codegen {
|
||||
|
|
@ -87,7 +93,7 @@ impl OngoingCodegen {
|
|||
if let Some((work_product_id, work_product)) = existing_work_product {
|
||||
work_products.insert(work_product_id, work_product);
|
||||
} else {
|
||||
let work_product = if backend_config.disable_incr_cache {
|
||||
let work_product = if disable_incr_cache {
|
||||
None
|
||||
} else if let Some(module_global_asm) = &module_global_asm {
|
||||
rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||
|
|
@ -322,12 +328,8 @@ fn produce_final_output_artifacts(
|
|||
// These are used in linking steps and will be cleaned up afterward.
|
||||
}
|
||||
|
||||
fn make_module(
|
||||
sess: &Session,
|
||||
backend_config: &BackendConfig,
|
||||
name: String,
|
||||
) -> UnwindModule<ObjectModule> {
|
||||
let isa = crate::build_isa(sess, backend_config);
|
||||
fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
|
||||
let isa = crate::build_isa(sess);
|
||||
|
||||
let mut builder =
|
||||
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
|
||||
|
|
@ -412,7 +414,13 @@ fn emit_module(
|
|||
Err(err) => return Err(format!("error writing object file: {}", err)),
|
||||
};
|
||||
|
||||
prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
|
||||
if prof.enabled() {
|
||||
prof.artifact_size(
|
||||
"object_file",
|
||||
tmp_file.file_name().unwrap().to_string_lossy(),
|
||||
file.metadata().unwrap().len(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(CompiledModule {
|
||||
name,
|
||||
|
|
@ -486,91 +494,101 @@ fn reuse_workproduct_for_cgu(
|
|||
})
|
||||
}
|
||||
|
||||
fn codegen_cgu_content(
|
||||
tcx: TyCtxt<'_>,
|
||||
module: &mut dyn Module,
|
||||
cgu_name: rustc_span::Symbol,
|
||||
) -> (CodegenCx, Vec<CodegenedFunction>) {
|
||||
let _timer = tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str());
|
||||
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
let mono_items = cgu.items_in_deterministic_order(tcx);
|
||||
|
||||
let mut cx = crate::CodegenCx::new(
|
||||
tcx,
|
||||
module.isa(),
|
||||
tcx.sess.opts.debuginfo != DebugInfo::None,
|
||||
cgu_name,
|
||||
);
|
||||
let mut type_dbg = TypeDebugContext::default();
|
||||
super::predefine_mono_items(tcx, module, &mono_items);
|
||||
let mut codegened_functions = vec![];
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => {
|
||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
||||
tcx,
|
||||
&mut cx,
|
||||
&mut type_dbg,
|
||||
Function::new(),
|
||||
module,
|
||||
inst,
|
||||
) {
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
}
|
||||
MonoItem::Static(def_id) => {
|
||||
let data_id = crate::constant::codegen_static(tcx, module, def_id);
|
||||
if let Some(debug_context) = &mut cx.debug_context {
|
||||
debug_context.define_static(tcx, &mut type_dbg, def_id, data_id);
|
||||
}
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::main_shim::maybe_create_entry_wrapper(tcx, module, false, cgu.is_primary());
|
||||
|
||||
(cx, codegened_functions)
|
||||
}
|
||||
|
||||
fn module_codegen(
|
||||
tcx: TyCtxt<'_>,
|
||||
(backend_config, global_asm_config, cgu_name, token): (
|
||||
BackendConfig,
|
||||
(global_asm_config, cgu_name, token): (
|
||||
Arc<GlobalAsmConfig>,
|
||||
rustc_span::Symbol,
|
||||
ConcurrencyLimiterToken,
|
||||
),
|
||||
) -> OngoingModuleCodegen {
|
||||
let (cgu_name, mut cx, mut module, codegened_functions) =
|
||||
tcx.prof.generic_activity_with_arg("codegen cgu", cgu_name.as_str()).run(|| {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
let mono_items = cgu.items_in_deterministic_order(tcx);
|
||||
let mut module = make_module(tcx.sess, cgu_name.as_str().to_string());
|
||||
|
||||
let mut module = make_module(tcx.sess, &backend_config, cgu_name.as_str().to_string());
|
||||
let (mut cx, codegened_functions) = codegen_cgu_content(tcx, &mut module, cgu_name);
|
||||
|
||||
let mut cx = crate::CodegenCx::new(
|
||||
tcx,
|
||||
module.isa(),
|
||||
tcx.sess.opts.debuginfo != DebugInfo::None,
|
||||
cgu_name,
|
||||
);
|
||||
let mut type_dbg = TypeDebugContext::default();
|
||||
super::predefine_mono_items(tcx, &mut module, &mono_items);
|
||||
let mut codegened_functions = vec![];
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => {
|
||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
||||
tcx,
|
||||
&mut cx,
|
||||
&mut type_dbg,
|
||||
Function::new(),
|
||||
&mut module,
|
||||
inst,
|
||||
) {
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
}
|
||||
MonoItem::Static(def_id) => {
|
||||
let data_id = crate::constant::codegen_static(tcx, &mut module, def_id);
|
||||
if let Some(debug_context) = &mut cx.debug_context {
|
||||
debug_context.define_static(tcx, &mut type_dbg, def_id, data_id);
|
||||
}
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
crate::global_asm::codegen_global_asm_item(
|
||||
tcx,
|
||||
&mut cx.global_asm,
|
||||
item_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, false, cgu.is_primary());
|
||||
|
||||
let cgu_name = cgu.name().as_str().to_owned();
|
||||
|
||||
(cgu_name, cx, module, codegened_functions)
|
||||
});
|
||||
let cgu_name = cgu_name.as_str().to_owned();
|
||||
|
||||
let producer = crate::debuginfo::producer(tcx.sess);
|
||||
|
||||
let profiler = tcx.prof.clone();
|
||||
|
||||
OngoingModuleCodegen::Async(std::thread::spawn(move || {
|
||||
cx.profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| {
|
||||
profiler.clone().generic_activity_with_arg("compile functions", &*cgu_name).run(|| {
|
||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||
cx.profiler.clone(),
|
||||
profiler.clone(),
|
||||
)));
|
||||
|
||||
let mut cached_context = Context::new();
|
||||
for codegened_func in codegened_functions {
|
||||
crate::base::compile_fn(&mut cx, &mut cached_context, &mut module, codegened_func);
|
||||
crate::base::compile_fn(
|
||||
&mut cx,
|
||||
&profiler,
|
||||
&mut cached_context,
|
||||
&mut module,
|
||||
codegened_func,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let global_asm_object_file =
|
||||
cx.profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
|
||||
profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
|
||||
crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm)
|
||||
})?;
|
||||
|
||||
let codegen_result =
|
||||
cx.profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
|
||||
profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
|
||||
emit_cgu(
|
||||
&global_asm_config.output_filenames,
|
||||
&cx.profiler,
|
||||
&profiler,
|
||||
cgu_name,
|
||||
module,
|
||||
cx.debug_context,
|
||||
|
|
@ -583,9 +601,63 @@ 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(OutputType::Metadata, Some(&metadata_cgu_name));
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if created_alloc_shim {
|
||||
let product = allocator_module.finish();
|
||||
|
||||
match emit_module(
|
||||
tcx.output_filenames(()),
|
||||
&tcx.sess.prof,
|
||||
product.object,
|
||||
ModuleKind::Allocator,
|
||||
"allocator_shim".to_owned(),
|
||||
&crate::debuginfo::producer(tcx.sess),
|
||||
) {
|
||||
Ok(allocator_module) => Some(allocator_module),
|
||||
Err(err) => tcx.dcx().fatal(err),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_aot(
|
||||
tcx: TyCtxt<'_>,
|
||||
backend_config: BackendConfig,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<OngoingCodegen> {
|
||||
|
|
@ -631,9 +703,10 @@ pub(crate) fn run_aot(
|
|||
|
||||
let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
|
||||
|
||||
let disable_incr_cache = disable_incr_cache();
|
||||
let (todo_cgus, done_cgus) =
|
||||
cgus.into_iter().enumerate().partition::<Vec<_>, _>(|&(i, _)| match cgu_reuse[i] {
|
||||
_ if backend_config.disable_incr_cache => true,
|
||||
_ if disable_incr_cache => true,
|
||||
CguReuse::No => true,
|
||||
CguReuse::PreLto | CguReuse::PostLto => false,
|
||||
});
|
||||
|
|
@ -647,12 +720,7 @@ pub(crate) fn run_aot(
|
|||
.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
(
|
||||
backend_config.clone(),
|
||||
global_asm_config.clone(),
|
||||
cgu.name(),
|
||||
concurrency_limiter.acquire(tcx.dcx()),
|
||||
),
|
||||
(global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())),
|
||||
module_codegen,
|
||||
Some(rustc_middle::dep_graph::hash_result),
|
||||
)
|
||||
|
|
@ -666,62 +734,10 @@ pub(crate) fn run_aot(
|
|||
modules
|
||||
});
|
||||
|
||||
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
|
||||
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
|
||||
let allocator_module = emit_allocator_module(tcx);
|
||||
|
||||
let allocator_module = if created_alloc_shim {
|
||||
let product = allocator_module.finish();
|
||||
|
||||
match emit_module(
|
||||
tcx.output_filenames(()),
|
||||
&tcx.sess.prof,
|
||||
product.object,
|
||||
ModuleKind::Allocator,
|
||||
"allocator_shim".to_owned(),
|
||||
&crate::debuginfo::producer(tcx.sess),
|
||||
) {
|
||||
Ok(allocator_module) => Some(allocator_module),
|
||||
Err(err) => tcx.dcx().fatal(err),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let metadata_module = if need_metadata_module {
|
||||
let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
|
||||
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(OutputType::Metadata, Some(&metadata_cgu_name));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
(metadata_cgu_name, tmp_file)
|
||||
});
|
||||
|
||||
Some(CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(tmp_file),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let metadata_module =
|
||||
if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None };
|
||||
|
||||
Box::new(OngoingCodegen {
|
||||
modules,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ use cranelift_jit::{JITBuilder, JITModule};
|
|||
use rustc_codegen_ssa::CrateInfo;
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::debuginfo::TypeDebugContext;
|
||||
use crate::prelude::*;
|
||||
use crate::unwind_module::UnwindModule;
|
||||
use crate::{BackendConfig, CodegenCx, CodegenMode};
|
||||
use crate::{CodegenCx, CodegenMode};
|
||||
|
||||
struct JitState {
|
||||
jit_module: UnwindModule<JITModule>,
|
||||
|
|
@ -59,14 +59,10 @@ impl UnsafeMessage {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_jit_module(
|
||||
tcx: TyCtxt<'_>,
|
||||
backend_config: &BackendConfig,
|
||||
hotswap: bool,
|
||||
) -> (UnwindModule<JITModule>, CodegenCx) {
|
||||
fn create_jit_module(tcx: TyCtxt<'_>, hotswap: bool) -> (UnwindModule<JITModule>, CodegenCx) {
|
||||
let crate_info = CrateInfo::new(tcx, "dummy_target_cpu".to_string());
|
||||
|
||||
let isa = crate::build_isa(tcx.sess, backend_config);
|
||||
let isa = crate::build_isa(tcx.sess);
|
||||
let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
jit_builder.hotswap(hotswap);
|
||||
crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
|
||||
|
|
@ -74,14 +70,14 @@ fn create_jit_module(
|
|||
jit_builder.symbol("__clif_jit_fn", clif_jit_fn as *const u8);
|
||||
let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false);
|
||||
|
||||
let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, Symbol::intern("dummy_cgu_name"));
|
||||
let cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name);
|
||||
|
||||
crate::allocator::codegen(tcx, &mut jit_module);
|
||||
|
||||
(jit_module, cx)
|
||||
}
|
||||
|
||||
pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
||||
pub(crate) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode, jit_args: Vec<String>) -> ! {
|
||||
if !tcx.sess.opts.output_types.should_codegen() {
|
||||
tcx.dcx().fatal("JIT mode doesn't work with `cargo check`");
|
||||
}
|
||||
|
|
@ -90,11 +86,8 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
tcx.dcx().fatal("can't jit non-executable crate");
|
||||
}
|
||||
|
||||
let (mut jit_module, mut cx) = create_jit_module(
|
||||
tcx,
|
||||
&backend_config,
|
||||
matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
|
||||
);
|
||||
let (mut jit_module, mut cx) =
|
||||
create_jit_module(tcx, matches!(codegen_mode, CodegenMode::JitLazy));
|
||||
let mut cached_context = Context::new();
|
||||
|
||||
let (_, cgus) = tcx.collect_and_partition_mono_items(());
|
||||
|
|
@ -110,7 +103,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
|
||||
for (mono_item, _) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => match backend_config.codegen_mode {
|
||||
MonoItem::Fn(inst) => match codegen_mode {
|
||||
CodegenMode::Aot => unreachable!(),
|
||||
CodegenMode::Jit => {
|
||||
codegen_and_compile_fn(
|
||||
|
|
@ -151,7 +144,7 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
|
|||
);
|
||||
|
||||
let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
|
||||
.chain(backend_config.jit_args.iter().map(|arg| &**arg))
|
||||
.chain(jit_args.iter().map(|arg| &**arg))
|
||||
.map(|arg| CString::new(arg).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
@ -211,7 +204,7 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
instance: Instance<'tcx>,
|
||||
) {
|
||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||
cx.profiler.clone(),
|
||||
tcx.prof.clone(),
|
||||
)));
|
||||
|
||||
tcx.prof.generic_activity("codegen and compile fn").run(|| {
|
||||
|
|
@ -227,7 +220,7 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
module,
|
||||
instance,
|
||||
) {
|
||||
crate::base::compile_fn(cx, cached_context, module, codegened_func);
|
||||
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -276,12 +269,7 @@ fn jit_fn(instance_ptr: *const Instance<'static>, trampoline_ptr: *const u8) ->
|
|||
|
||||
jit_module.module.prepare_for_function_redefine(func_id).unwrap();
|
||||
|
||||
let mut cx = crate::CodegenCx::new(
|
||||
tcx,
|
||||
jit_module.isa(),
|
||||
false,
|
||||
Symbol::intern("dummy_cgu_name"),
|
||||
);
|
||||
let mut cx = crate::CodegenCx::new(tcx, jit_module.isa(), false, sym::dummy_cgu_name);
|
||||
codegen_and_compile_fn(tcx, &mut cx, &mut Context::new(), jit_module, instance);
|
||||
|
||||
assert!(cx.global_asm.is_empty());
|
||||
|
|
|
|||
|
|
@ -102,13 +102,12 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
|
|||
// Pass a wrapper rather than the function itself as the function itself may not
|
||||
// be exported from the main codegen unit and may thus be unreachable from the
|
||||
// object file created by an external assembler.
|
||||
let inline_asm_index = fx.cx.inline_asm_index.get();
|
||||
fx.cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let wrapper_name = format!(
|
||||
"__inline_asm_{}_wrapper_n{}",
|
||||
fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
fx.cx.inline_asm_index
|
||||
);
|
||||
fx.cx.inline_asm_index += 1;
|
||||
let sig =
|
||||
get_function_sig(fx.tcx, fx.target_config.default_call_conv, instance);
|
||||
create_wrapper_function(fx.module, sig, &wrapper_name, symbol.name);
|
||||
|
|
@ -167,13 +166,12 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||
asm_gen.allocate_registers();
|
||||
asm_gen.allocate_stack_slots();
|
||||
|
||||
let inline_asm_index = fx.cx.inline_asm_index.get();
|
||||
fx.cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let asm_name = format!(
|
||||
"__inline_asm_{}_n{}",
|
||||
fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
fx.cx.inline_asm_index
|
||||
);
|
||||
fx.cx.inline_asm_index += 1;
|
||||
|
||||
let generated_asm = asm_gen.generate_asm_wrapper(&asm_name);
|
||||
fx.cx.global_asm.push_str(&generated_asm);
|
||||
|
|
@ -266,13 +264,12 @@ pub(crate) fn codegen_naked_asm<'tcx>(
|
|||
// Pass a wrapper rather than the function itself as the function itself may not
|
||||
// be exported from the main codegen unit and may thus be unreachable from the
|
||||
// object file created by an external assembler.
|
||||
let inline_asm_index = cx.inline_asm_index.get();
|
||||
cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let wrapper_name = format!(
|
||||
"__inline_asm_{}_wrapper_n{}",
|
||||
cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
cx.inline_asm_index
|
||||
);
|
||||
cx.inline_asm_index += 1;
|
||||
let sig =
|
||||
get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||
create_wrapper_function(module, sig, &wrapper_name, symbol.name);
|
||||
|
|
|
|||
|
|
@ -1270,8 +1270,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
}
|
||||
|
||||
sym::cold_path => {
|
||||
// This is a no-op. The intrinsic is just a hint to the optimizer.
|
||||
// We still have an impl here to avoid it being turned into a call.
|
||||
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
|
||||
}
|
||||
|
||||
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
|
||||
|
|
|
|||
|
|
@ -415,7 +415,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
});
|
||||
}
|
||||
|
||||
sym::simd_fma => {
|
||||
// FIXME: simd_relaxed_fma doesn't relax to non-fused multiply-add
|
||||
sym::simd_fma | sym::simd_relaxed_fma => {
|
||||
intrinsic_args!(fx, args => (a, b, c); intrinsic);
|
||||
|
||||
if !a.layout().ty.is_simd() {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ extern crate rustc_target;
|
|||
extern crate rustc_driver;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
|
|
@ -42,7 +42,6 @@ use cranelift_codegen::settings::{self, Configurable};
|
|||
use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc_codegen_ssa::back::versioned_llvm_target;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -123,11 +122,10 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
|
|||
/// The codegen context holds any information shared between the codegen of individual functions
|
||||
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
|
||||
struct CodegenCx {
|
||||
profiler: SelfProfilerRef,
|
||||
output_filenames: Arc<OutputFilenames>,
|
||||
should_write_ir: bool,
|
||||
global_asm: String,
|
||||
inline_asm_index: Cell<usize>,
|
||||
inline_asm_index: usize,
|
||||
debug_context: Option<DebugContext>,
|
||||
cgu_name: Symbol,
|
||||
}
|
||||
|
|
@ -142,11 +140,10 @@ impl CodegenCx {
|
|||
None
|
||||
};
|
||||
CodegenCx {
|
||||
profiler: tcx.prof.clone(),
|
||||
output_filenames: tcx.output_filenames(()).clone(),
|
||||
should_write_ir: crate::pretty_clif::should_write_ir(tcx),
|
||||
global_asm: String::new(),
|
||||
inline_asm_index: Cell::new(0),
|
||||
inline_asm_index: 0,
|
||||
debug_context,
|
||||
cgu_name,
|
||||
}
|
||||
|
|
@ -154,7 +151,7 @@ impl CodegenCx {
|
|||
}
|
||||
|
||||
pub struct CraneliftCodegenBackend {
|
||||
pub config: RefCell<Option<BackendConfig>>,
|
||||
pub config: Option<BackendConfig>,
|
||||
}
|
||||
|
||||
impl CodegenBackend for CraneliftCodegenBackend {
|
||||
|
|
@ -176,31 +173,19 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
sess.dcx()
|
||||
.fatal("`-Cinstrument-coverage` is LLVM specific and not supported by Cranelift");
|
||||
}
|
||||
|
||||
let mut config = self.config.borrow_mut();
|
||||
if config.is_none() {
|
||||
let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)
|
||||
.unwrap_or_else(|err| sess.dcx().fatal(err));
|
||||
*config = Some(new_config);
|
||||
}
|
||||
}
|
||||
|
||||
fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
|
||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||
if sess.target.arch == "x86_64" && sess.target.os != "none" {
|
||||
// x86_64 mandates SSE2 support
|
||||
vec![Symbol::intern("fxsr"), sym::sse, Symbol::intern("sse2")]
|
||||
vec![sym::fsxr, sym::sse, sym::sse2]
|
||||
} else if sess.target.arch == "aarch64" {
|
||||
match &*sess.target.os {
|
||||
"none" => vec![],
|
||||
// On macOS the aes, sha2 and sha3 features are enabled by default and ring
|
||||
// fails to compile on macOS when they are not present.
|
||||
"macos" => vec![
|
||||
sym::neon,
|
||||
Symbol::intern("aes"),
|
||||
Symbol::intern("sha2"),
|
||||
Symbol::intern("sha3"),
|
||||
],
|
||||
"macos" => vec![sym::neon, sym::aes, sym::sha2, sym::sha3],
|
||||
// AArch64 mandates Neon support
|
||||
_ => vec![sym::neon],
|
||||
}
|
||||
|
|
@ -220,12 +205,15 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
tcx.dcx().abort_if_errors();
|
||||
let config = self.config.borrow().clone().unwrap();
|
||||
let config = self.config.clone().unwrap_or_else(|| {
|
||||
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
|
||||
.unwrap_or_else(|err| tcx.sess.dcx().fatal(err))
|
||||
});
|
||||
match config.codegen_mode {
|
||||
CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
|
||||
CodegenMode::Aot => driver::aot::run_aot(tcx, metadata, need_metadata_module),
|
||||
CodegenMode::Jit | CodegenMode::JitLazy => {
|
||||
#[cfg(feature = "jit")]
|
||||
driver::jit::run_jit(tcx, config);
|
||||
driver::jit::run_jit(tcx, config.codegen_mode, config.jit_args);
|
||||
|
||||
#[cfg(not(feature = "jit"))]
|
||||
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
|
||||
|
|
@ -239,16 +227,20 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let _timer = sess.timer("finish_ongoing_codegen");
|
||||
|
||||
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(
|
||||
sess,
|
||||
outputs,
|
||||
self.config.borrow().as_ref().unwrap(),
|
||||
)
|
||||
ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(sess, outputs)
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine if the Cranelift ir verifier should run.
|
||||
///
|
||||
/// Returns true when `-Zverify-llvm-ir` is passed, the `CG_CLIF_ENABLE_VERIFIER` env var is set to
|
||||
/// 1 or when cg_clif is compiled with debug assertions enabled or false otherwise.
|
||||
fn enable_verifier(sess: &Session) -> bool {
|
||||
sess.verify_llvm_ir()
|
||||
|| cfg!(debug_assertions)
|
||||
|| env::var("CG_CLIF_ENABLE_VERIFIER").as_deref() == Ok("1")
|
||||
}
|
||||
|
||||
fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
||||
// FIXME(madsmtm): Use `sess.target.llvm_target` once target-lexicon supports unversioned macOS.
|
||||
// See <https://github.com/bytecodealliance/target-lexicon/pull/113>
|
||||
|
|
@ -258,14 +250,14 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
|
|||
}
|
||||
}
|
||||
|
||||
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIsa + 'static> {
|
||||
fn build_isa(sess: &Session) -> Arc<dyn TargetIsa + 'static> {
|
||||
use target_lexicon::BinaryFormat;
|
||||
|
||||
let target_triple = crate::target_triple(sess);
|
||||
|
||||
let mut flags_builder = settings::builder();
|
||||
flags_builder.enable("is_pic").unwrap();
|
||||
let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
|
||||
let enable_verifier = if enable_verifier(sess) { "true" } else { "false" };
|
||||
flags_builder.set("enable_verifier", enable_verifier).unwrap();
|
||||
flags_builder.set("regalloc_checker", enable_verifier).unwrap();
|
||||
|
||||
|
|
@ -300,6 +292,16 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs
|
|||
}
|
||||
}
|
||||
|
||||
if let target_lexicon::OperatingSystem::Windows = target_triple.operating_system {
|
||||
// FIXME remove dependency on this from the Rust ABI. cc bytecodealliance/wasmtime#9510
|
||||
flags_builder.enable("enable_multi_ret_implicit_sret").unwrap();
|
||||
}
|
||||
|
||||
if let target_lexicon::Architecture::S390x = target_triple.architecture {
|
||||
// FIXME remove dependency on this from the Rust ABI. cc bytecodealliance/wasmtime#9510
|
||||
flags_builder.enable("enable_multi_ret_implicit_sret").unwrap();
|
||||
}
|
||||
|
||||
if let target_lexicon::Architecture::Aarch64(_)
|
||||
| target_lexicon::Architecture::Riscv64(_)
|
||||
| target_lexicon::Architecture::X86_64 = target_triple.architecture
|
||||
|
|
@ -352,5 +354,5 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs
|
|||
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
|
||||
#[no_mangle]
|
||||
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
|
||||
Box::new(CraneliftCodegenBackend { config: RefCell::new(None) })
|
||||
Box::new(CraneliftCodegenBackend { config: None })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
};
|
||||
|
||||
if main_def_id.is_local() {
|
||||
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, main_def_id);
|
||||
if module.get_name(tcx.symbol_name(instance).name).is_none() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
}
|
||||
};
|
||||
|
||||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||
let instance = Instance::mono(tcx, rust_main_def_id);
|
||||
|
||||
let main_name = tcx.symbol_name(instance).name;
|
||||
let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
|
||||
|
|
@ -117,8 +117,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
report.def_id,
|
||||
tcx.mk_args(&[GenericArg::from(main_ret_ty)]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
|
||||
let report_name = tcx.symbol_name(report).name;
|
||||
let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
|
||||
|
|
@ -143,8 +142,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
start_def_id,
|
||||
tcx.mk_args(&[main_ret_ty.into()]),
|
||||
DUMMY_SP,
|
||||
)
|
||||
.polymorphize(tcx);
|
||||
);
|
||||
let start_func_id = import_function(tcx, m, start_instance);
|
||||
|
||||
let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
|
||||
|
|
|
|||
|
|
@ -1005,9 +1005,6 @@ pub(crate) fn assert_assignable<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
(ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => {
|
||||
// No way to check if it is correct or not with polymorphization enabled
|
||||
}
|
||||
_ => {
|
||||
assert_eq!(
|
||||
from_ty,
|
||||
|
|
|
|||
|
|
@ -52,24 +52,24 @@ impl<T: ?Sized> LegacyReceiver for &mut T {}
|
|||
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub unsafe trait Copy {}
|
||||
pub trait Copy {}
|
||||
|
||||
unsafe impl Copy for bool {}
|
||||
unsafe impl Copy for u8 {}
|
||||
unsafe impl Copy for u16 {}
|
||||
unsafe impl Copy for u32 {}
|
||||
unsafe impl Copy for u64 {}
|
||||
unsafe impl Copy for usize {}
|
||||
unsafe impl Copy for i8 {}
|
||||
unsafe impl Copy for i16 {}
|
||||
unsafe impl Copy for i32 {}
|
||||
unsafe impl Copy for isize {}
|
||||
unsafe impl Copy for f32 {}
|
||||
unsafe impl Copy for f64 {}
|
||||
unsafe impl Copy for char {}
|
||||
unsafe impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
unsafe impl<T: ?Sized> Copy for *const T {}
|
||||
unsafe impl<T: ?Sized> Copy for *mut T {}
|
||||
impl Copy for bool {}
|
||||
impl Copy for u8 {}
|
||||
impl Copy for u16 {}
|
||||
impl Copy for u32 {}
|
||||
impl Copy for u64 {}
|
||||
impl Copy for usize {}
|
||||
impl Copy for i8 {}
|
||||
impl Copy for i16 {}
|
||||
impl Copy for i32 {}
|
||||
impl Copy for isize {}
|
||||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for char {}
|
||||
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
impl<T: ?Sized> Copy for *const T {}
|
||||
impl<T: ?Sized> Copy for *mut T {}
|
||||
|
||||
#[lang = "sync"]
|
||||
pub unsafe trait Sync {}
|
||||
|
|
|
|||
|
|
@ -656,9 +656,9 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
|||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
|
|
@ -736,9 +736,11 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
|
||||
cx.type_vector(cx.type_i32(), 4)
|
||||
}
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => {
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
|
|
|
|||
|
|
@ -544,7 +544,10 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
|
|||
|
||||
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
|
||||
X86Abi {
|
||||
regparm: self.tcx.sess.opts.unstable_opts.regparm,
|
||||
reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -772,6 +772,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
|
|||
sym::simd_flog => "log",
|
||||
sym::simd_floor => "floor",
|
||||
sym::simd_fma => "fma",
|
||||
sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary
|
||||
sym::simd_fpowi => "__builtin_powi",
|
||||
sym::simd_fpow => "pow",
|
||||
sym::simd_fsin => "sin",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ tests/ui/functions-closures/parallel-codegen-closures.rs
|
|||
tests/ui/linkage-attr/linkage1.rs
|
||||
tests/ui/lto/dylib-works.rs
|
||||
tests/ui/numbers-arithmetic/saturating-float-casts.rs
|
||||
tests/ui/polymorphization/promoted-function.rs
|
||||
tests/ui/sepcomp/sepcomp-cci.rs
|
||||
tests/ui/sepcomp/sepcomp-extern.rs
|
||||
tests/ui/sepcomp/sepcomp-fns-backwards.rs
|
||||
|
|
|
|||
|
|
@ -656,9 +656,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
|
|||
PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
|
||||
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
|
||||
PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| PowerPC(PowerPCInlineAsmRegClass::xer)
|
||||
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
|
||||
PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
|
||||
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
|
|
@ -825,9 +824,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
|
|||
PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
|
||||
PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| PowerPC(PowerPCInlineAsmRegClass::xer)
|
||||
| PowerPC(PowerPCInlineAsmRegClass::vreg) => {
|
||||
PowerPC(PowerPCInlineAsmRegClass::vreg) => cx.type_vector(cx.type_i32(), 4),
|
||||
PowerPC(PowerPCInlineAsmRegClass::cr) | PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
|
|
@ -1042,6 +1040,26 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
let value = bx.or(value, bx.const_u32(0xFFFF_0000));
|
||||
bx.bitcast(value, bx.type_f32())
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F32) =>
|
||||
{
|
||||
let value = bx.insert_element(
|
||||
bx.const_undef(bx.type_vector(bx.type_f32(), 4)),
|
||||
value,
|
||||
bx.const_usize(0),
|
||||
);
|
||||
bx.bitcast(value, bx.type_vector(bx.type_f32(), 4))
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F64) =>
|
||||
{
|
||||
let value = bx.insert_element(
|
||||
bx.const_undef(bx.type_vector(bx.type_f64(), 2)),
|
||||
value,
|
||||
bx.const_usize(0),
|
||||
);
|
||||
bx.bitcast(value, bx.type_vector(bx.type_f64(), 2))
|
||||
}
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
|
@ -1177,6 +1195,18 @@ fn llvm_fixup_output<'ll, 'tcx>(
|
|||
let value = bx.trunc(value, bx.type_i16());
|
||||
bx.bitcast(value, bx.type_f16())
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F32) =>
|
||||
{
|
||||
let value = bx.bitcast(value, bx.type_vector(bx.type_f32(), 4));
|
||||
bx.extract_element(value, bx.const_usize(0))
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F64) =>
|
||||
{
|
||||
let value = bx.bitcast(value, bx.type_vector(bx.type_f64(), 2));
|
||||
bx.extract_element(value, bx.const_usize(0))
|
||||
}
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
|
@ -1301,6 +1331,16 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
|
|||
{
|
||||
cx.type_f32()
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F32) =>
|
||||
{
|
||||
cx.type_vector(cx.type_f32(), 4)
|
||||
}
|
||||
(PowerPC(PowerPCInlineAsmRegClass::vreg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F64) =>
|
||||
{
|
||||
cx.type_vector(cx.type_f64(), 2)
|
||||
}
|
||||
_ => layout.llvm_type(cx),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ fn prepare_lto(
|
|||
// __llvm_profile_counter_bias is pulled in at link time by an undefined reference to
|
||||
// __llvm_profile_runtime, therefore we won't know until link time if this symbol
|
||||
// should have default visibility.
|
||||
symbols_below_threshold.push(CString::new("__llvm_profile_counter_bias").unwrap());
|
||||
symbols_below_threshold.push(c"__llvm_profile_counter_bias".to_owned());
|
||||
Ok((symbols_below_threshold, upstream_modules))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ fn write_output_file<'ll>(
|
|||
dwo_output: Option<&Path>,
|
||||
file_type: llvm::FileType,
|
||||
self_profiler_ref: &SelfProfilerRef,
|
||||
verify_llvm_ir: bool,
|
||||
) -> Result<(), FatalError> {
|
||||
debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output);
|
||||
unsafe {
|
||||
|
|
@ -79,6 +80,7 @@ fn write_output_file<'ll>(
|
|||
output_c.as_ptr(),
|
||||
dwo_output_ptr,
|
||||
file_type,
|
||||
verify_llvm_ir,
|
||||
);
|
||||
|
||||
// Record artifact sizes for self-profiling
|
||||
|
|
@ -507,7 +509,7 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
|
|||
}
|
||||
|
||||
fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
|
||||
config.instrument_coverage.then(|| CString::new("default_%m_%p.profraw").unwrap())
|
||||
config.instrument_coverage.then(|| c"default_%m_%p.profraw".to_owned())
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn llvm_optimize(
|
||||
|
|
@ -840,6 +842,7 @@ pub(crate) unsafe fn codegen(
|
|||
None,
|
||||
llvm::FileType::AssemblyFile,
|
||||
&cgcx.prof,
|
||||
config.verify_llvm_ir,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
|
@ -877,6 +880,7 @@ pub(crate) unsafe fn codegen(
|
|||
dwo_out,
|
||||
llvm::FileType::ObjectFile,
|
||||
&cgcx.prof,
|
||||
config.verify_llvm_ir,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,10 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
|||
|
||||
let is_hidden = if is_generic {
|
||||
// This is a monomorphization of a generic function.
|
||||
if !cx.tcx.sess.opts.share_generics() {
|
||||
if !(cx.tcx.sess.opts.share_generics()
|
||||
|| tcx.codegen_fn_attrs(instance_def_id).inline
|
||||
== rustc_attr::InlineAttr::Never)
|
||||
{
|
||||
// When not sharing generics, all instances are in the same
|
||||
// crate and have hidden visibility.
|
||||
true
|
||||
|
|
|
|||
|
|
@ -302,10 +302,9 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
(value, AddressSpace::DATA)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Function { instance, .. } => (
|
||||
self.get_fn_addr(instance.polymorphize(self.tcx)),
|
||||
self.data_layout().instruction_address_space,
|
||||
),
|
||||
GlobalAlloc::Function { instance, .. } => {
|
||||
(self.get_fn_addr(instance), self.data_layout().instruction_address_space)
|
||||
}
|
||||
GlobalAlloc::VTable(ty, dyn_ty) => {
|
||||
let alloc = self
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ pub(crate) struct CodegenCx<'ll, 'tcx> {
|
|||
|
||||
pub isize_ty: &'ll Type,
|
||||
|
||||
/// Extra codegen state needed when coverage instrumentation is enabled.
|
||||
pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
|
||||
/// Extra per-CGU codegen state needed when coverage instrumentation is enabled.
|
||||
pub coverage_cx: Option<coverageinfo::CguCoverageContext<'ll, 'tcx>>,
|
||||
pub dbg_cx: Option<debuginfo::CodegenUnitDebugContext<'ll, 'tcx>>,
|
||||
|
||||
eh_personality: Cell<Option<&'ll Value>>,
|
||||
|
|
@ -159,6 +159,11 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
// See https://github.com/llvm/llvm-project/pull/112084
|
||||
target_data_layout = target_data_layout.replace("-i128:128", "");
|
||||
}
|
||||
if sess.target.arch.starts_with("powerpc64") {
|
||||
// LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit.
|
||||
// See https://github.com/llvm/llvm-project/pull/118004
|
||||
target_data_layout = target_data_layout.replace("-i128:128", "");
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
|
|
@ -525,7 +530,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
||||
|
||||
let coverage_cx =
|
||||
tcx.sess.instrument_coverage().then(coverageinfo::CrateCoverageContext::new);
|
||||
tcx.sess.instrument_coverage().then(coverageinfo::CguCoverageContext::new);
|
||||
|
||||
let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None {
|
||||
let dctx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
||||
|
|
@ -576,7 +581,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
/// Extra state that is only available when coverage instrumentation is enabled.
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub(crate) fn coverage_cx(&self) -> &coverageinfo::CrateCoverageContext<'ll, 'tcx> {
|
||||
pub(crate) fn coverage_cx(&self) -> &coverageinfo::CguCoverageContext<'ll, 'tcx> {
|
||||
self.coverage_cx.as_ref().expect("only called when coverage instrumentation is enabled")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId};
|
||||
use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
|
||||
|
||||
use crate::coverageinfo::mapgen::LocalFileId;
|
||||
|
||||
/// Must match the layout of `LLVMRustCounterKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -124,23 +126,37 @@ pub(crate) struct CoverageSpan {
|
|||
/// Local index into the function's local-to-global file ID table.
|
||||
/// The value at that index is itself an index into the coverage filename
|
||||
/// table in the CGU's `__llvm_covmap` section.
|
||||
pub(crate) file_id: u32,
|
||||
file_id: u32,
|
||||
|
||||
/// 1-based starting line of the source code span.
|
||||
pub(crate) start_line: u32,
|
||||
start_line: u32,
|
||||
/// 1-based starting column of the source code span.
|
||||
pub(crate) start_col: u32,
|
||||
start_col: u32,
|
||||
/// 1-based ending line of the source code span.
|
||||
pub(crate) end_line: u32,
|
||||
end_line: u32,
|
||||
/// 1-based ending column of the source code span. High bit must be unset.
|
||||
pub(crate) end_col: u32,
|
||||
end_col: u32,
|
||||
}
|
||||
|
||||
impl CoverageSpan {
|
||||
pub(crate) fn from_source_region(
|
||||
local_file_id: LocalFileId,
|
||||
code_region: &SourceRegion,
|
||||
) -> Self {
|
||||
let file_id = local_file_id.as_u32();
|
||||
let &SourceRegion { start_line, start_col, end_line, end_col } = code_region;
|
||||
// Internally, LLVM uses the high bit of `end_col` to distinguish between
|
||||
// code regions and gap regions, so it can't be used by the column number.
|
||||
assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
|
||||
Self { file_id, start_line, start_col, end_line, end_col }
|
||||
}
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageCodeRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct CodeRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) counter: Counter,
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +164,7 @@ pub(crate) struct CodeRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct BranchRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
}
|
||||
|
|
@ -157,7 +173,7 @@ pub(crate) struct BranchRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCBranchRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
pub(crate) mcdc_branch_params: mcdc::BranchParameters,
|
||||
|
|
@ -167,6 +183,6 @@ pub(crate) struct MCDCBranchRegion {
|
|||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCDecisionRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) span: CoverageSpan,
|
||||
pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,201 +1,38 @@
|
|||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, MappingKind, Op,
|
||||
CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
|
||||
SourceRegion,
|
||||
};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
|
||||
|
||||
/// Holds all of the coverage mapping data associated with a function instance,
|
||||
/// collected during traversal of `Coverage` statements in the function's MIR.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct FunctionCoverageCollector<'tcx> {
|
||||
/// Coverage info that was attached to this function by the instrumentor.
|
||||
function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
is_used: bool,
|
||||
|
||||
/// Tracks which counters have been seen, so that we can identify mappings
|
||||
/// to counters that were optimized out, and set them to zero.
|
||||
counters_seen: BitSet<CounterId>,
|
||||
/// Contains all expression IDs that have been seen in an `ExpressionUsed`
|
||||
/// coverage statement, plus all expression IDs that aren't directly used
|
||||
/// by any mappings (and therefore do not have expression-used statements).
|
||||
/// After MIR traversal is finished, we can conclude that any IDs missing
|
||||
/// from this set must have had their statements deleted by MIR opts.
|
||||
expressions_seen: BitSet<ExpressionId>,
|
||||
}
|
||||
|
||||
impl<'tcx> FunctionCoverageCollector<'tcx> {
|
||||
/// Creates a new set of coverage data for a used (called) function.
|
||||
pub(crate) fn new(
|
||||
instance: Instance<'tcx>,
|
||||
function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
) -> Self {
|
||||
Self::create(instance, function_coverage_info, true)
|
||||
}
|
||||
|
||||
/// Creates a new set of coverage data for an unused (never called) function.
|
||||
pub(crate) fn unused(
|
||||
instance: Instance<'tcx>,
|
||||
function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
) -> Self {
|
||||
Self::create(instance, function_coverage_info, false)
|
||||
}
|
||||
|
||||
fn create(
|
||||
instance: Instance<'tcx>,
|
||||
function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
is_used: bool,
|
||||
) -> Self {
|
||||
let num_counters = function_coverage_info.num_counters;
|
||||
let num_expressions = function_coverage_info.expressions.len();
|
||||
debug!(
|
||||
"FunctionCoverage::create(instance={instance:?}) has \
|
||||
num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
|
||||
);
|
||||
|
||||
// Create a filled set of expression IDs, so that expressions not
|
||||
// directly used by mappings will be treated as "seen".
|
||||
// (If they end up being unused, LLVM will delete them for us.)
|
||||
let mut expressions_seen = BitSet::new_filled(num_expressions);
|
||||
// For each expression ID that is directly used by one or more mappings,
|
||||
// mark it as not-yet-seen. This indicates that we expect to see a
|
||||
// corresponding `ExpressionUsed` statement during MIR traversal.
|
||||
for mapping in function_coverage_info.mappings.iter() {
|
||||
// Currently we only worry about ordinary code mappings.
|
||||
// For branch and MC/DC mappings, expressions might not correspond
|
||||
// to any particular point in the control-flow graph.
|
||||
// (Keep this in sync with the injection of `ExpressionUsed`
|
||||
// statements in the `InstrumentCoverage` MIR pass.)
|
||||
if let MappingKind::Code(term) = mapping.kind
|
||||
&& let CovTerm::Expression(id) = term
|
||||
{
|
||||
expressions_seen.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
function_coverage_info,
|
||||
is_used,
|
||||
counters_seen: BitSet::new_empty(num_counters),
|
||||
expressions_seen,
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks a counter ID as having been seen in a counter-increment statement.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mark_counter_id_seen(&mut self, id: CounterId) {
|
||||
self.counters_seen.insert(id);
|
||||
}
|
||||
|
||||
/// Marks an expression ID as having been seen in an expression-used statement.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mark_expression_id_seen(&mut self, id: ExpressionId) {
|
||||
self.expressions_seen.insert(id);
|
||||
}
|
||||
|
||||
/// Identify expressions that will always have a value of zero, and note
|
||||
/// their IDs in [`ZeroExpressions`]. Mappings that refer to a zero expression
|
||||
/// can instead become mappings to a constant zero value.
|
||||
///
|
||||
/// This method mainly exists to preserve the simplifications that were
|
||||
/// already being performed by the Rust-side expression renumbering, so that
|
||||
/// the resulting coverage mappings don't get worse.
|
||||
fn identify_zero_expressions(&self) -> ZeroExpressions {
|
||||
// The set of expressions that either were optimized out entirely, or
|
||||
// have zero as both of their operands, and will therefore always have
|
||||
// a value of zero. Other expressions that refer to these as operands
|
||||
// can have those operands replaced with `CovTerm::Zero`.
|
||||
let mut zero_expressions = ZeroExpressions::default();
|
||||
|
||||
// Simplify a copy of each expression based on lower-numbered expressions,
|
||||
// and then update the set of always-zero expressions if necessary.
|
||||
// (By construction, expressions can only refer to other expressions
|
||||
// that have lower IDs, so one pass is sufficient.)
|
||||
for (id, expression) in self.function_coverage_info.expressions.iter_enumerated() {
|
||||
if !self.expressions_seen.contains(id) {
|
||||
// If an expression was not seen, it must have been optimized away,
|
||||
// so any operand that refers to it can be replaced with zero.
|
||||
zero_expressions.insert(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't need to simplify the actual expression data in the
|
||||
// expressions list; we can just simplify a temporary copy and then
|
||||
// use that to update the set of always-zero expressions.
|
||||
let Expression { mut lhs, op, mut rhs } = *expression;
|
||||
|
||||
// If an expression has an operand that is also an expression, the
|
||||
// operand's ID must be strictly lower. This is what lets us find
|
||||
// all zero expressions in one pass.
|
||||
let assert_operand_expression_is_lower = |operand_id: ExpressionId| {
|
||||
assert!(
|
||||
operand_id < id,
|
||||
"Operand {operand_id:?} should be less than {id:?} in {expression:?}",
|
||||
)
|
||||
};
|
||||
|
||||
// If an operand refers to a counter or expression that is always
|
||||
// zero, then that operand can be replaced with `CovTerm::Zero`.
|
||||
let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
|
||||
if let CovTerm::Expression(id) = *operand {
|
||||
assert_operand_expression_is_lower(id);
|
||||
}
|
||||
|
||||
if is_zero_term(&self.counters_seen, &zero_expressions, *operand) {
|
||||
*operand = CovTerm::Zero;
|
||||
}
|
||||
};
|
||||
maybe_set_operand_to_zero(&mut lhs);
|
||||
maybe_set_operand_to_zero(&mut rhs);
|
||||
|
||||
// Coverage counter values cannot be negative, so if an expression
|
||||
// involves subtraction from zero, assume that its RHS must also be zero.
|
||||
// (Do this after simplifications that could set the LHS to zero.)
|
||||
if lhs == CovTerm::Zero && op == Op::Subtract {
|
||||
rhs = CovTerm::Zero;
|
||||
}
|
||||
|
||||
// After the above simplifications, if both operands are zero, then
|
||||
// we know that this expression is always zero too.
|
||||
if lhs == CovTerm::Zero && rhs == CovTerm::Zero {
|
||||
zero_expressions.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
zero_expressions
|
||||
}
|
||||
|
||||
pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
|
||||
let zero_expressions = self.identify_zero_expressions();
|
||||
let FunctionCoverageCollector { function_coverage_info, is_used, counters_seen, .. } = self;
|
||||
|
||||
FunctionCoverage { function_coverage_info, is_used, counters_seen, zero_expressions }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct FunctionCoverage<'tcx> {
|
||||
pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
is_used: bool,
|
||||
|
||||
counters_seen: BitSet<CounterId>,
|
||||
zero_expressions: ZeroExpressions,
|
||||
/// If `None`, the corresponding function is unused.
|
||||
ids_info: Option<&'tcx CoverageIdsInfo>,
|
||||
}
|
||||
|
||||
impl<'tcx> FunctionCoverage<'tcx> {
|
||||
pub(crate) fn new_used(
|
||||
function_coverage_info: &'tcx FunctionCoverageInfo,
|
||||
ids_info: &'tcx CoverageIdsInfo,
|
||||
) -> Self {
|
||||
Self { function_coverage_info, ids_info: Some(ids_info) }
|
||||
}
|
||||
|
||||
pub(crate) fn new_unused(function_coverage_info: &'tcx FunctionCoverageInfo) -> Self {
|
||||
Self { function_coverage_info, ids_info: None }
|
||||
}
|
||||
|
||||
/// Returns true for a used (called) function, and false for an unused function.
|
||||
pub(crate) fn is_used(&self) -> bool {
|
||||
self.is_used
|
||||
self.ids_info.is_some()
|
||||
}
|
||||
|
||||
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
|
||||
/// or not the source code structure changed between different compilations.
|
||||
pub(crate) fn source_hash(&self) -> u64 {
|
||||
if self.is_used { self.function_coverage_info.function_source_hash } else { 0 }
|
||||
if self.is_used() { self.function_coverage_info.function_source_hash } else { 0 }
|
||||
}
|
||||
|
||||
/// Convert this function's coverage expression data into a form that can be
|
||||
|
|
@ -220,16 +57,16 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Yields all this function's coverage mappings, after simplifying away
|
||||
/// unused counters and counter expressions.
|
||||
pub(crate) fn mapping_spans(
|
||||
/// Converts this function's coverage mappings into an intermediate form
|
||||
/// that will be used by `mapgen` when preparing for FFI.
|
||||
pub(crate) fn counter_regions(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (MappingKind, Span)> + ExactSizeIterator + Captures<'_> {
|
||||
) -> impl Iterator<Item = (MappingKind, &SourceRegion)> + ExactSizeIterator {
|
||||
self.function_coverage_info.mappings.iter().map(move |mapping| {
|
||||
let &Mapping { ref kind, span } = mapping;
|
||||
let Mapping { kind, source_region } = mapping;
|
||||
let kind =
|
||||
kind.map_terms(|term| if self.is_zero_term(term) { CovTerm::Zero } else { term });
|
||||
(kind, span)
|
||||
(kind, source_region)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -238,37 +75,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
|||
}
|
||||
|
||||
fn is_zero_term(&self, term: CovTerm) -> bool {
|
||||
is_zero_term(&self.counters_seen, &self.zero_expressions, term)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set of expression IDs that are known to always evaluate to zero.
|
||||
/// Any mapping or expression operand that refers to these expressions can have
|
||||
/// that reference replaced with a constant zero value.
|
||||
#[derive(Default)]
|
||||
struct ZeroExpressions(FxIndexSet<ExpressionId>);
|
||||
|
||||
impl ZeroExpressions {
|
||||
fn insert(&mut self, id: ExpressionId) {
|
||||
self.0.insert(id);
|
||||
}
|
||||
|
||||
fn contains(&self, id: ExpressionId) -> bool {
|
||||
self.0.contains(&id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given term is known to have a value of zero, taking
|
||||
/// into account knowledge of which counters are unused and which expressions
|
||||
/// are always zero.
|
||||
fn is_zero_term(
|
||||
counters_seen: &BitSet<CounterId>,
|
||||
zero_expressions: &ZeroExpressions,
|
||||
term: CovTerm,
|
||||
) -> bool {
|
||||
match term {
|
||||
CovTerm::Zero => true,
|
||||
CovTerm::Counter(id) => !counters_seen.contains(id),
|
||||
CovTerm::Expression(id) => zero_expressions.contains(id),
|
||||
match self.ids_info {
|
||||
Some(ids_info) => ids_info.is_zero_term(term),
|
||||
// This function is unused, so all coverage counters/expressions are zero.
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
mod spans;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::sync::Arc;
|
||||
use std::iter;
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::MappingKind;
|
||||
|
|
@ -17,12 +15,12 @@ use rustc_middle::{bug, mir};
|
|||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
use rustc_span::def_id::DefIdSet;
|
||||
use rustc_span::{SourceFile, StableSourceFileId};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
|
||||
use crate::coverageinfo::map_data::FunctionCoverage;
|
||||
use crate::coverageinfo::{ffi, llvm_cov};
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -65,20 +63,15 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
None => return,
|
||||
};
|
||||
if function_coverage_map.is_empty() {
|
||||
// This module has no functions with coverage instrumentation
|
||||
// This CGU has no functions with coverage instrumentation.
|
||||
return;
|
||||
}
|
||||
|
||||
let function_coverage_entries = function_coverage_map
|
||||
.into_iter()
|
||||
.map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let all_files = function_coverage_entries
|
||||
let all_file_names = function_coverage_map
|
||||
.iter()
|
||||
.map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span)
|
||||
.map(|span| tcx.sess.source_map().lookup_source_file(span.lo()));
|
||||
let global_file_table = GlobalFileTable::new(all_files);
|
||||
.map(|span| span_file_name(tcx, span));
|
||||
let global_file_table = GlobalFileTable::new(all_file_names);
|
||||
|
||||
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||
|
|
@ -94,7 +87,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
let mut unused_function_names = Vec::new();
|
||||
|
||||
// Encode coverage mappings and generate function records
|
||||
for (instance, function_coverage) in function_coverage_entries {
|
||||
for (instance, function_coverage) in function_coverage_map {
|
||||
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
|
||||
|
||||
let mangled_function_name = tcx.symbol_name(instance).name;
|
||||
|
|
@ -105,8 +98,15 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
encode_mappings_for_function(tcx, &global_file_table, &function_coverage);
|
||||
|
||||
if coverage_mapping_buffer.is_empty() {
|
||||
debug!("function has no mappings to embed; skipping");
|
||||
continue;
|
||||
if function_coverage.is_used() {
|
||||
bug!(
|
||||
"A used function should have had coverage mapping data but did not: {}",
|
||||
mangled_function_name
|
||||
);
|
||||
} else {
|
||||
debug!("unused function had no coverage mapping data: {}", mangled_function_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !is_used {
|
||||
|
|
@ -143,34 +143,29 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying source files.
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
|
||||
struct GlobalFileTable {
|
||||
/// This "raw" table doesn't include the working dir, so a file's
|
||||
/// This "raw" table doesn't include the working dir, so a filename's
|
||||
/// global ID is its index in this set **plus one**.
|
||||
raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
|
||||
raw_file_table: FxIndexSet<Symbol>,
|
||||
}
|
||||
|
||||
impl GlobalFileTable {
|
||||
fn new(all_files: impl IntoIterator<Item = Arc<SourceFile>>) -> Self {
|
||||
// Collect all of the files into a set. Files usually come in contiguous
|
||||
// runs, so we can dedup adjacent ones to save work.
|
||||
let mut raw_file_table = all_files
|
||||
.into_iter()
|
||||
.dedup_by(|a, b| a.stable_id == b.stable_id)
|
||||
.map(|f| (f.stable_id, f))
|
||||
.collect::<FxIndexMap<StableSourceFileId, Arc<SourceFile>>>();
|
||||
fn new(all_file_names: impl IntoIterator<Item = Symbol>) -> Self {
|
||||
// Collect all of the filenames into a set. Filenames usually come in
|
||||
// contiguous runs, so we can dedup adjacent ones to save work.
|
||||
let mut raw_file_table = all_file_names.into_iter().dedup().collect::<FxIndexSet<Symbol>>();
|
||||
|
||||
// Sort the file table by its underlying filenames.
|
||||
raw_file_table.sort_unstable_by(|_, a, _, b| {
|
||||
Ord::cmp(&a.name, &b.name).then_with(|| Ord::cmp(&a.stable_id, &b.stable_id))
|
||||
});
|
||||
// Sort the file table by its actual string values, not the arbitrary
|
||||
// ordering of its symbols.
|
||||
raw_file_table.sort_unstable_by(|a, b| a.as_str().cmp(b.as_str()));
|
||||
|
||||
Self { raw_file_table }
|
||||
}
|
||||
|
||||
fn global_file_id_for_file(&self, file: &SourceFile) -> GlobalFileId {
|
||||
let raw_id = self.raw_file_table.get_index_of(&file.stable_id).unwrap_or_else(|| {
|
||||
bug!("file not found in prepared global file table: {:?}", file.name);
|
||||
fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId {
|
||||
let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| {
|
||||
bug!("file name not found in prepared global file table: {file_name}");
|
||||
});
|
||||
// The raw file table doesn't include an entry for the working dir
|
||||
// (which has ID 0), so add 1 to get the correct ID.
|
||||
|
|
@ -178,27 +173,24 @@ impl GlobalFileTable {
|
|||
}
|
||||
|
||||
fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
|
||||
let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
|
||||
|
||||
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
|
||||
// requires setting the first filename to the compilation directory.
|
||||
// Since rustc generates coverage maps with relative paths, the
|
||||
// compilation directory can be combined with the relative paths
|
||||
// to get absolute paths, if needed.
|
||||
table.push(
|
||||
tcx.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy(),
|
||||
);
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
let working_dir: &str = &tcx
|
||||
.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy();
|
||||
|
||||
// Add the regular entries after the base directory.
|
||||
table.extend(self.raw_file_table.values().map(|file| {
|
||||
file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
|
||||
}));
|
||||
|
||||
llvm_cov::write_filenames_to_buffer(table.iter().map(|f| f.as_ref()))
|
||||
// Insert the working dir at index 0, before the other filenames.
|
||||
let filenames =
|
||||
iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str));
|
||||
llvm_cov::write_filenames_to_buffer(filenames)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +203,7 @@ rustc_index::newtype_index! {
|
|||
/// An index into a function's list of global file IDs. That underlying list
|
||||
/// of local-to-global mappings will be embedded in the function's record in
|
||||
/// the `__llvm_covfun` linker section.
|
||||
struct LocalFileId {}
|
||||
pub(crate) struct LocalFileId {}
|
||||
}
|
||||
|
||||
/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
|
||||
|
|
@ -237,6 +229,13 @@ impl VirtualFileMapping {
|
|||
}
|
||||
}
|
||||
|
||||
fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
|
||||
let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
|
||||
let name =
|
||||
source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
|
||||
Symbol::intern(&name)
|
||||
}
|
||||
|
||||
/// Using the expressions and counter regions collected for a single function,
|
||||
/// generate the variable-sized payload of its corresponding `__llvm_covfun`
|
||||
/// entry. The payload is returned as a vector of bytes.
|
||||
|
|
@ -247,13 +246,11 @@ fn encode_mappings_for_function(
|
|||
global_file_table: &GlobalFileTable,
|
||||
function_coverage: &FunctionCoverage<'_>,
|
||||
) -> Vec<u8> {
|
||||
let mapping_spans = function_coverage.mapping_spans();
|
||||
if mapping_spans.is_empty() {
|
||||
let counter_regions = function_coverage.counter_regions();
|
||||
if counter_regions.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let fn_cov_info = function_coverage.function_coverage_info;
|
||||
|
||||
let expressions = function_coverage.counter_expressions().collect::<Vec<_>>();
|
||||
|
||||
let mut virtual_file_mapping = VirtualFileMapping::default();
|
||||
|
|
@ -263,39 +260,34 @@ fn encode_mappings_for_function(
|
|||
let mut mcdc_decision_regions = vec![];
|
||||
|
||||
// Currently a function's mappings must all be in the same file as its body span.
|
||||
let source_map = tcx.sess.source_map();
|
||||
let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo());
|
||||
let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
|
||||
|
||||
// Look up the global file ID for that file.
|
||||
let global_file_id = global_file_table.global_file_id_for_file(&source_file);
|
||||
// Look up the global file ID for that filename.
|
||||
let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
|
||||
|
||||
// Associate that global file ID with a local file ID for this function.
|
||||
let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
|
||||
debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
|
||||
|
||||
let make_cov_span = |span| {
|
||||
spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
|
||||
};
|
||||
|
||||
// For each coverage mapping span in this function+file, convert it to a
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
// form suitable for FFI.
|
||||
for (mapping_kind, span) in mapping_spans {
|
||||
debug!("Adding counter {mapping_kind:?} to map for {span:?}");
|
||||
let Some(cov_span) = make_cov_span(span) else { continue };
|
||||
for (mapping_kind, region) in counter_regions {
|
||||
debug!("Adding counter {mapping_kind:?} to map for {region:?}");
|
||||
let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
|
||||
match mapping_kind {
|
||||
MappingKind::Code(term) => {
|
||||
code_regions
|
||||
.push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
|
||||
code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
|
||||
}
|
||||
MappingKind::Branch { true_term, false_term } => {
|
||||
branch_regions.push(ffi::BranchRegion {
|
||||
cov_span,
|
||||
span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
cov_span,
|
||||
span,
|
||||
true_counter: ffi::Counter::from_term(true_term),
|
||||
false_counter: ffi::Counter::from_term(false_term),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
|
|
@ -303,7 +295,7 @@ fn encode_mappings_for_function(
|
|||
}
|
||||
MappingKind::MCDCDecision(mcdc_decision_params) => {
|
||||
mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
|
||||
cov_span,
|
||||
span,
|
||||
mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
|
||||
});
|
||||
}
|
||||
|
|
@ -538,9 +530,7 @@ fn add_unused_function_coverage<'tcx>(
|
|||
}),
|
||||
);
|
||||
|
||||
// An unused function's mappings will automatically be rewritten to map to
|
||||
// zero, because none of its counters/expressions are marked as seen.
|
||||
let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info);
|
||||
|
||||
// An unused function's mappings will all be rewritten to map to zero.
|
||||
let function_coverage = FunctionCoverage::new_unused(function_coverage_info);
|
||||
cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
use rustc_middle::mir::coverage::FunctionCoverageInfo;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, Pos, SourceFile, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::coverageinfo::ffi;
|
||||
use crate::coverageinfo::mapgen::LocalFileId;
|
||||
|
||||
/// Converts the span into its start line and column, and end line and column.
|
||||
///
|
||||
/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
|
||||
/// the compiler, these column numbers are denoted in **bytes**, because that's what
|
||||
/// LLVM's `llvm-cov` tool expects to see in coverage maps.
|
||||
///
|
||||
/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
|
||||
/// but it's hard to rule out entirely (especially in the presence of complex macros
|
||||
/// or other expansions), and if it does happen then skipping a span or function is
|
||||
/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
|
||||
pub(crate) fn make_coverage_span(
|
||||
file_id: LocalFileId,
|
||||
source_map: &SourceMap,
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
file: &SourceFile,
|
||||
span: Span,
|
||||
) -> Option<ffi::CoverageSpan> {
|
||||
let span = ensure_non_empty_span(source_map, fn_cov_info, span)?;
|
||||
|
||||
let lo = span.lo();
|
||||
let hi = span.hi();
|
||||
|
||||
// Column numbers need to be in bytes, so we can't use the more convenient
|
||||
// `SourceMap` methods for looking up file coordinates.
|
||||
let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
|
||||
let rpos = file.relative_position(pos);
|
||||
let line_index = file.lookup_line(rpos)?;
|
||||
let line_start = file.lines()[line_index];
|
||||
// Line numbers and column numbers are 1-based, so add 1 to each.
|
||||
Some((line_index + 1, (rpos - line_start).to_usize() + 1))
|
||||
};
|
||||
|
||||
let (mut start_line, start_col) = line_and_byte_column(lo)?;
|
||||
let (mut end_line, end_col) = line_and_byte_column(hi)?;
|
||||
|
||||
// Apply an offset so that code in doctests has correct line numbers.
|
||||
// FIXME(#79417): Currently we have no way to offset doctest _columns_.
|
||||
start_line = source_map.doctest_offset_line(&file.name, start_line);
|
||||
end_line = source_map.doctest_offset_line(&file.name, end_line);
|
||||
|
||||
check_coverage_span(ffi::CoverageSpan {
|
||||
file_id: file_id.as_u32(),
|
||||
start_line: start_line as u32,
|
||||
start_col: start_col as u32,
|
||||
end_line: end_line as u32,
|
||||
end_col: end_col as u32,
|
||||
})
|
||||
}
|
||||
|
||||
fn ensure_non_empty_span(
|
||||
source_map: &SourceMap,
|
||||
fn_cov_info: &FunctionCoverageInfo,
|
||||
span: Span,
|
||||
) -> Option<Span> {
|
||||
if !span.is_empty() {
|
||||
return Some(span);
|
||||
}
|
||||
|
||||
let lo = span.lo();
|
||||
let hi = span.hi();
|
||||
|
||||
// The span is empty, so try to expand it to cover an adjacent '{' or '}',
|
||||
// but only within the bounds of the body span.
|
||||
let try_next = hi < fn_cov_info.body_span.hi();
|
||||
let try_prev = fn_cov_info.body_span.lo() < lo;
|
||||
if !(try_next || try_prev) {
|
||||
return None;
|
||||
}
|
||||
|
||||
source_map
|
||||
.span_to_source(span, |src, start, end| try {
|
||||
// We're only checking for specific ASCII characters, so we don't
|
||||
// have to worry about multi-byte code points.
|
||||
if try_next && src.as_bytes()[end] == b'{' {
|
||||
Some(span.with_hi(hi + BytePos(1)))
|
||||
} else if try_prev && src.as_bytes()[start - 1] == b'}' {
|
||||
Some(span.with_lo(lo - BytePos(1)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok()?
|
||||
}
|
||||
|
||||
/// If `llvm-cov` sees a source region that is improperly ordered (end < start),
|
||||
/// it will immediately exit with a fatal error. To prevent that from happening,
|
||||
/// discard regions that are improperly ordered, or might be interpreted in a
|
||||
/// way that makes them improperly ordered.
|
||||
fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan> {
|
||||
let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span;
|
||||
|
||||
// Line/column coordinates are supposed to be 1-based. If we ever emit
|
||||
// coordinates of 0, `llvm-cov` might misinterpret them.
|
||||
let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
|
||||
// Coverage mappings use the high bit of `end_col` to indicate that a
|
||||
// region is actually a "gap" region, so make sure it's unset.
|
||||
let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
|
||||
// If a region is improperly ordered (end < start), `llvm-cov` will exit
|
||||
// with a fatal error, which is inconvenient for users and hard to debug.
|
||||
let is_ordered = (start_line, start_col) <= (end_line, end_col);
|
||||
|
||||
if all_nonzero && end_col_has_high_bit_unset && is_ordered {
|
||||
Some(cov_span)
|
||||
} else {
|
||||
debug!(
|
||||
?cov_span,
|
||||
?all_nonzero,
|
||||
?end_col_has_high_bit_unset,
|
||||
?is_ordered,
|
||||
"Skipping source region that would be misinterpreted or rejected by LLVM"
|
||||
);
|
||||
// If this happens in a debug build, ICE to make it easier to notice.
|
||||
debug_assert!(false, "Improper source region: {cov_span:?}");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::builder::Builder;
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::map_data::FunctionCoverageCollector;
|
||||
use crate::coverageinfo::map_data::FunctionCoverage;
|
||||
use crate::llvm;
|
||||
|
||||
pub(crate) mod ffi;
|
||||
|
|
@ -21,18 +21,17 @@ mod llvm_cov;
|
|||
pub(crate) mod map_data;
|
||||
mod mapgen;
|
||||
|
||||
/// A context object for maintaining all state needed by the coverageinfo module.
|
||||
pub(crate) struct CrateCoverageContext<'ll, 'tcx> {
|
||||
/// Extra per-CGU context/state needed for coverage instrumentation.
|
||||
pub(crate) struct CguCoverageContext<'ll, 'tcx> {
|
||||
/// Coverage data for each instrumented function identified by DefId.
|
||||
pub(crate) function_coverage_map:
|
||||
RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>,
|
||||
pub(crate) function_coverage_map: RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverage<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
|
||||
|
||||
covfun_section_name: OnceCell<CString>,
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
||||
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
function_coverage_map: Default::default(),
|
||||
|
|
@ -42,9 +41,7 @@ impl<'ll, 'tcx> CrateCoverageContext<'ll, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn take_function_coverage_map(
|
||||
&self,
|
||||
) -> FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> {
|
||||
fn take_function_coverage_map(&self) -> FxIndexMap<Instance<'tcx>, FunctionCoverage<'tcx>> {
|
||||
self.function_coverage_map.replace(FxIndexMap::default())
|
||||
}
|
||||
|
||||
|
|
@ -143,6 +140,13 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
|
||||
let bx = self;
|
||||
|
||||
// Due to LocalCopy instantiation or MIR inlining, coverage statements
|
||||
// can end up in a crate that isn't doing coverage instrumentation.
|
||||
// When that happens, we currently just discard those statements, so
|
||||
// the corresponding code will be undercounted.
|
||||
// FIXME(Zalathar): Find a better solution for mixed-coverage builds.
|
||||
let Some(coverage_cx) = &bx.cx.coverage_cx else { return };
|
||||
|
||||
let Some(function_coverage_info) =
|
||||
bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
|
||||
else {
|
||||
|
|
@ -150,32 +154,27 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
// FIXME(#132395): Unwrapping `coverage_cx` here has led to ICEs in the
|
||||
// wild, so keep this early-return until we understand why.
|
||||
let mut coverage_map = match bx.coverage_cx {
|
||||
Some(ref cx) => cx.function_coverage_map.borrow_mut(),
|
||||
None => return,
|
||||
};
|
||||
let func_coverage = coverage_map
|
||||
.entry(instance)
|
||||
.or_insert_with(|| FunctionCoverageCollector::new(instance, function_coverage_info));
|
||||
// Mark the instance as used in this CGU, for coverage purposes.
|
||||
// This includes functions that were not partitioned into this CGU,
|
||||
// but were MIR-inlined into one of this CGU's functions.
|
||||
coverage_cx.function_coverage_map.borrow_mut().entry(instance).or_insert_with(|| {
|
||||
FunctionCoverage::new_used(
|
||||
function_coverage_info,
|
||||
bx.tcx.coverage_ids_info(instance.def),
|
||||
)
|
||||
});
|
||||
|
||||
match *kind {
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
|
||||
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
|
||||
),
|
||||
CoverageKind::CounterIncrement { id } => {
|
||||
func_coverage.mark_counter_id_seen(id);
|
||||
// We need to explicitly drop the `RefMut` before calling into
|
||||
// `instrprof_increment`, as that needs an exclusive borrow.
|
||||
drop(coverage_map);
|
||||
|
||||
// The number of counters passed to `llvm.instrprof.increment` might
|
||||
// be smaller than the number originally inserted by the instrumentor,
|
||||
// if some high-numbered counters were removed by MIR optimizations.
|
||||
// If so, LLVM's profiler runtime will use fewer physical counters.
|
||||
let num_counters =
|
||||
bx.tcx().coverage_ids_info(instance.def).max_counter_id.as_u32() + 1;
|
||||
bx.tcx().coverage_ids_info(instance.def).num_counters_after_mir_opts();
|
||||
assert!(
|
||||
num_counters as usize <= function_coverage_info.num_counters,
|
||||
"num_counters disagreement: query says {num_counters} but function info only has {}",
|
||||
|
|
@ -192,23 +191,23 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
);
|
||||
bx.instrprof_increment(fn_name, hash, num_counters, index);
|
||||
}
|
||||
CoverageKind::ExpressionUsed { id } => {
|
||||
func_coverage.mark_expression_id_seen(id);
|
||||
CoverageKind::ExpressionUsed { id: _ } => {
|
||||
// Expression-used statements are markers that are handled by
|
||||
// `coverage_ids_info`, so there's nothing to codegen here.
|
||||
}
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
let cond_bitmap = bx
|
||||
.coverage_cx()
|
||||
let cond_bitmap = coverage_cx
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for updating");
|
||||
let cond_index = bx.const_i32(index as i32);
|
||||
bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
|
||||
}
|
||||
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
|
||||
drop(coverage_map);
|
||||
let cond_bitmap = bx.coverage_cx()
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
|
||||
let cond_bitmap =
|
||||
coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect(
|
||||
"mcdc cond bitmap should have been allocated for merging \
|
||||
into the global bitmap",
|
||||
);
|
||||
assert!(
|
||||
bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
|
||||
"bitmap index of the decision out of range"
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&ptr_type_debuginfo_name,
|
||||
None,
|
||||
cx.size_and_align_of(ptr_type),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -259,6 +260,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
layout.fields.offset(abi::WIDE_PTR_ADDR),
|
||||
DIFlags::FlagZero,
|
||||
data_ptr_type_di_node,
|
||||
None,
|
||||
),
|
||||
build_field_di_node(
|
||||
cx,
|
||||
|
|
@ -268,6 +270,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
|||
layout.fields.offset(abi::WIDE_PTR_EXTRA),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, extra_field.ty),
|
||||
None,
|
||||
),
|
||||
]
|
||||
},
|
||||
|
|
@ -369,6 +372,7 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&type_name,
|
||||
None,
|
||||
cx.size_and_align_of(dyn_type),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -467,8 +471,6 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
|
|||
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
|
||||
},
|
||||
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
||||
// Type parameters from polymorphized functions.
|
||||
ty::Param(_) => build_param_type_di_node(cx, t),
|
||||
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
|
||||
};
|
||||
|
||||
|
|
@ -722,6 +724,14 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
|
|||
// `f16`'s value to be displayed using a Natvis visualiser in `intrinsic.natvis`.
|
||||
let float_ty = cx.tcx.types.f16;
|
||||
let bits_ty = cx.tcx.types.u16;
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
match float_ty.kind() {
|
||||
ty::Adt(def, _) => Some(file_metadata_from_def_id(cx, Some(def.did()))),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
type_map::stub(
|
||||
|
|
@ -729,12 +739,21 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
|
|||
Stub::Struct,
|
||||
UniqueTypeId::for_ty(cx.tcx, float_ty),
|
||||
"f16",
|
||||
def_location,
|
||||
cx.size_and_align_of(float_ty),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagZero,
|
||||
),
|
||||
// Fields:
|
||||
|cx, float_di_node| {
|
||||
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
match bits_ty.kind() {
|
||||
ty::Adt(def, _) => Some(def.did()),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
smallvec![build_field_di_node(
|
||||
cx,
|
||||
float_di_node,
|
||||
|
|
@ -743,6 +762,7 @@ fn build_cpp_f16_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> DINodeCreation
|
|||
Size::ZERO,
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, bits_ty),
|
||||
def_id,
|
||||
)]
|
||||
},
|
||||
NO_GENERICS,
|
||||
|
|
@ -839,6 +859,7 @@ fn build_foreign_type_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&compute_debuginfo_type_name(cx.tcx, t, false),
|
||||
None,
|
||||
cx.size_and_align_of(t),
|
||||
Some(get_namespace_for_item(cx, def_id)),
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -848,26 +869,6 @@ fn build_foreign_type_di_node<'ll, 'tcx>(
|
|||
)
|
||||
}
|
||||
|
||||
fn build_param_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
debug!("build_param_type_di_node: {:?}", t);
|
||||
let name = format!("{t:?}");
|
||||
DINodeCreationResult {
|
||||
di_node: unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateBasicType(
|
||||
DIB(cx),
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
Size::ZERO.bits(),
|
||||
DW_ATE_unsigned,
|
||||
)
|
||||
},
|
||||
already_stored_in_typemap: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
codegen_unit_name: &str,
|
||||
|
|
@ -989,15 +990,22 @@ fn build_field_di_node<'ll, 'tcx>(
|
|||
offset: Size,
|
||||
flags: DIFlags,
|
||||
type_di_node: &'ll DIType,
|
||||
def_id: Option<DefId>,
|
||||
) -> &'ll DIType {
|
||||
let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
|
||||
{
|
||||
file_metadata_from_def_id(cx, def_id)
|
||||
} else {
|
||||
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
||||
};
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateMemberType(
|
||||
DIB(cx),
|
||||
owner,
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
file_metadata,
|
||||
line_number,
|
||||
size_and_align.0.bits(),
|
||||
size_and_align.1.bits() as u32,
|
||||
offset.bits(),
|
||||
|
|
@ -1041,6 +1049,11 @@ fn build_struct_type_di_node<'ll, 'tcx>(
|
|||
let containing_scope = get_namespace_for_item(cx, adt_def.did());
|
||||
let struct_type_and_layout = cx.layout_of(struct_type);
|
||||
let variant_def = adt_def.non_enum_variant();
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
|
|
@ -1049,6 +1062,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&compute_debuginfo_type_name(cx.tcx, struct_type, false),
|
||||
def_location,
|
||||
size_and_align_of(struct_type_and_layout),
|
||||
Some(containing_scope),
|
||||
visibility_di_flags(cx, adt_def.did(), adt_def.did()),
|
||||
|
|
@ -1068,6 +1082,11 @@ fn build_struct_type_di_node<'ll, 'tcx>(
|
|||
Cow::Borrowed(f.name.as_str())
|
||||
};
|
||||
let field_layout = struct_type_and_layout.field(cx, i);
|
||||
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(f.did)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
build_field_di_node(
|
||||
cx,
|
||||
owner,
|
||||
|
|
@ -1076,6 +1095,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
|
|||
struct_type_and_layout.fields.offset(i),
|
||||
visibility_di_flags(cx, f.did, adt_def.did()),
|
||||
type_di_node(cx, field_layout.ty),
|
||||
def_id,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -1125,6 +1145,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
|||
layout.fields.offset(index),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, up_var_ty),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -1150,6 +1171,7 @@ fn build_tuple_type_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&type_name,
|
||||
None,
|
||||
size_and_align_of(tuple_type_and_layout),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -1168,6 +1190,7 @@ fn build_tuple_type_di_node<'ll, 'tcx>(
|
|||
tuple_type_and_layout.fields.offset(index),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, component_type),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -1189,6 +1212,12 @@ fn build_closure_env_di_node<'ll, 'tcx>(
|
|||
let containing_scope = get_namespace_for_item(cx, def_id);
|
||||
let type_name = compute_debuginfo_type_name(cx.tcx, closure_env_type, false);
|
||||
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(def_id)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
type_map::stub(
|
||||
|
|
@ -1196,6 +1225,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&type_name,
|
||||
def_location,
|
||||
cx.size_and_align_of(closure_env_type),
|
||||
Some(containing_scope),
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -1219,6 +1249,11 @@ fn build_union_type_di_node<'ll, 'tcx>(
|
|||
let containing_scope = get_namespace_for_item(cx, union_def_id);
|
||||
let union_ty_and_layout = cx.layout_of(union_type);
|
||||
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
|
|
@ -1227,6 +1262,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
|
|||
Stub::Union,
|
||||
unique_type_id,
|
||||
&type_name,
|
||||
def_location,
|
||||
size_and_align_of(union_ty_and_layout),
|
||||
Some(containing_scope),
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -1239,6 +1275,11 @@ fn build_union_type_di_node<'ll, 'tcx>(
|
|||
.enumerate()
|
||||
.map(|(i, f)| {
|
||||
let field_layout = union_ty_and_layout.field(cx, i);
|
||||
let def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(f.did)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
build_field_di_node(
|
||||
cx,
|
||||
owner,
|
||||
|
|
@ -1247,6 +1288,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
|
|||
Size::ZERO,
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, field_layout.ty),
|
||||
def_id,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -1321,14 +1363,7 @@ pub(crate) fn build_global_var_di_node<'ll>(
|
|||
// We may want to remove the namespace scope if we're in an extern block (see
|
||||
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
|
||||
let var_scope = get_namespace_for_item(cx, def_id);
|
||||
let span = hygiene::walk_chain_collapsed(tcx.def_span(def_id), DUMMY_SP);
|
||||
|
||||
let (file_metadata, line_number) = if !span.is_dummy() {
|
||||
let loc = cx.lookup_debug_loc(span.lo());
|
||||
(file_metadata(cx, &loc.file), loc.line)
|
||||
} else {
|
||||
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
||||
};
|
||||
let (file_metadata, line_number) = file_metadata_from_def_id(cx, Some(def_id));
|
||||
|
||||
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
|
||||
|
||||
|
|
@ -1418,6 +1453,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
|
|||
Stub::VTableTy { vtable_holder },
|
||||
unique_type_id,
|
||||
&vtable_type_name,
|
||||
None,
|
||||
(size, pointer_align),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagArtificial,
|
||||
|
|
@ -1455,6 +1491,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
|
|||
field_offset,
|
||||
DIFlags::FlagZero,
|
||||
field_type_di_node,
|
||||
None,
|
||||
))
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -1606,3 +1643,20 @@ fn tuple_field_name(field_index: usize) -> Cow<'static, str> {
|
|||
.map(|s| Cow::from(*s))
|
||||
.unwrap_or_else(|| Cow::from(format!("__{field_index}")))
|
||||
}
|
||||
|
||||
pub(crate) type DefinitionLocation<'ll> = (&'ll DIFile, c_uint);
|
||||
|
||||
pub(crate) fn file_metadata_from_def_id<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
def_id: Option<DefId>,
|
||||
) -> DefinitionLocation<'ll> {
|
||||
if let Some(def_id) = def_id
|
||||
&& let span = hygiene::walk_chain_collapsed(cx.tcx.def_span(def_id), DUMMY_SP)
|
||||
&& !span.is_dummy()
|
||||
{
|
||||
let loc = cx.lookup_debug_loc(span.lo());
|
||||
(file_metadata(cx, &loc.file), loc.line)
|
||||
} else {
|
||||
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use libc::c_uint;
|
|||
use rustc_abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
|
||||
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
|
||||
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
|
||||
use rustc_codegen_ssa::traits::ConstCodegenMethods;
|
||||
use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
|
|
@ -16,8 +16,8 @@ use crate::debuginfo::metadata::enums::DiscrResult;
|
|||
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
|
||||
use crate::debuginfo::metadata::{
|
||||
DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
|
||||
build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata,
|
||||
visibility_di_flags,
|
||||
build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
|
||||
unknown_file_metadata, visibility_di_flags,
|
||||
};
|
||||
use crate::debuginfo::utils::DIB;
|
||||
use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
|
||||
|
|
@ -192,6 +192,12 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
|
|||
|
||||
assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
|
||||
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(enum_adt_def.did())))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
type_map::stub(
|
||||
|
|
@ -199,6 +205,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
|
|||
type_map::Stub::Union,
|
||||
unique_type_id,
|
||||
&enum_type_name,
|
||||
def_location,
|
||||
cx.size_and_align_of(enum_type),
|
||||
NO_SCOPE_METADATA,
|
||||
visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did()),
|
||||
|
|
@ -262,6 +269,14 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
|
|||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let coroutine_type = unique_type_id.expect_ty();
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
|
||||
bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
|
||||
};
|
||||
Some(file_metadata_from_def_id(cx, Some(coroutine_def_id)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
|
||||
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
|
||||
|
||||
|
|
@ -274,6 +289,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
|
|||
type_map::Stub::Union,
|
||||
unique_type_id,
|
||||
&coroutine_type_name,
|
||||
def_location,
|
||||
size_and_align_of(coroutine_type_and_layout),
|
||||
NO_SCOPE_METADATA,
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -321,6 +337,12 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
|
|||
let tag_base_type_di_node = type_di_node(cx, tag_base_type);
|
||||
let tag_base_type_align = cx.align_of(tag_base_type);
|
||||
|
||||
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(enum_adt_def.did())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let variant_names_type_di_node = build_variant_names_type_di_node(
|
||||
cx,
|
||||
enum_type_di_node,
|
||||
|
|
@ -328,6 +350,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
|
|||
variant_index,
|
||||
Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
|
||||
)),
|
||||
enum_adt_def_id,
|
||||
);
|
||||
|
||||
let variant_struct_type_wrapper_di_node = build_variant_struct_wrapper_type_di_node(
|
||||
|
|
@ -341,6 +364,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
|
|||
tag_base_type_di_node,
|
||||
tag_base_type,
|
||||
DiscrResult::NoDiscriminant,
|
||||
None,
|
||||
);
|
||||
|
||||
smallvec![
|
||||
|
|
@ -354,6 +378,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
|
|||
Size::ZERO,
|
||||
visibility_flags,
|
||||
variant_struct_type_wrapper_di_node,
|
||||
None,
|
||||
),
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateStaticMemberType(
|
||||
|
|
@ -383,6 +408,12 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
|
|||
) -> SmallVec<&'ll DIType> {
|
||||
let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
|
||||
|
||||
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(enum_adt_def.did())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let variant_names_type_di_node = build_variant_names_type_di_node(
|
||||
cx,
|
||||
enum_type_di_node,
|
||||
|
|
@ -390,6 +421,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
|
|||
let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
|
||||
(variant_index, variant_name)
|
||||
}),
|
||||
enum_adt_def_id,
|
||||
);
|
||||
let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
|
||||
|
||||
|
|
@ -447,6 +479,7 @@ fn build_variant_names_type_di_node<'ll, 'tcx>(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
containing_scope: &'ll DIType,
|
||||
variants: impl Iterator<Item = (VariantIdx, Cow<'tcx, str>)>,
|
||||
enum_def_id: Option<rustc_span::def_id::DefId>,
|
||||
) -> &'ll DIType {
|
||||
// Create an enumerator for each variant.
|
||||
super::build_enumeration_type_di_node(
|
||||
|
|
@ -454,6 +487,7 @@ fn build_variant_names_type_di_node<'ll, 'tcx>(
|
|||
"VariantNames",
|
||||
variant_names_enum_base_type(cx),
|
||||
variants.map(|(variant_index, variant_name)| (variant_name, variant_index.as_u32().into())),
|
||||
enum_def_id,
|
||||
containing_scope,
|
||||
)
|
||||
}
|
||||
|
|
@ -469,6 +503,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
|
|||
tag_base_type_di_node: &'ll DIType,
|
||||
tag_base_type: Ty<'tcx>,
|
||||
discr: DiscrResult,
|
||||
source_info: Option<(&'ll DIFile, c_uint)>,
|
||||
) -> &'ll DIType {
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
|
|
@ -481,6 +516,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
|
|||
variant_index,
|
||||
),
|
||||
&variant_struct_wrapper_type_name(variant_index),
|
||||
source_info,
|
||||
// NOTE: We use size and align of enum_type, not from variant_layout:
|
||||
size_and_align_of(enum_or_coroutine_type_and_layout),
|
||||
Some(enum_or_coroutine_type_di_node),
|
||||
|
|
@ -530,6 +566,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
|
|||
Size::ZERO,
|
||||
DIFlags::FlagZero,
|
||||
variant_struct_type_di_node,
|
||||
None,
|
||||
));
|
||||
|
||||
let build_assoc_const =
|
||||
|
|
@ -684,6 +721,11 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
|
|||
variant_range
|
||||
.clone()
|
||||
.map(|variant_index| (variant_index, CoroutineArgs::variant_name(variant_index))),
|
||||
if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(coroutine_def_id)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
);
|
||||
|
||||
let discriminants: IndexVec<VariantIdx, DiscrResult> = {
|
||||
|
|
@ -776,6 +818,11 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
|
|||
tag_base_type_di_node,
|
||||
tag_base_type,
|
||||
variant_member_info.discr,
|
||||
if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
variant_member_info.source_info
|
||||
} else {
|
||||
None
|
||||
},
|
||||
);
|
||||
|
||||
// We use LLVMRustDIBuilderCreateMemberType() member type directly because
|
||||
|
|
@ -831,6 +878,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
|
|||
lo_offset,
|
||||
di_flags,
|
||||
type_di_node,
|
||||
None,
|
||||
));
|
||||
|
||||
unions_fields.push(build_field_di_node(
|
||||
|
|
@ -841,6 +889,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
|
|||
hi_offset,
|
||||
DIFlags::FlagZero,
|
||||
type_di_node,
|
||||
None,
|
||||
));
|
||||
} else {
|
||||
unions_fields.push(build_field_di_node(
|
||||
|
|
@ -851,6 +900,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
|
|||
enum_type_and_layout.fields.offset(tag_field),
|
||||
di_flags,
|
||||
tag_base_type_di_node,
|
||||
None,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::borrow::Cow;
|
|||
use rustc_abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
|
||||
use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
|
||||
use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
|
||||
use rustc_codegen_ssa::traits::MiscCodegenMethods;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::bug;
|
||||
|
|
@ -16,8 +17,8 @@ use super::{SmallVec, size_and_align_of};
|
|||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::metadata::type_map::{self, Stub};
|
||||
use crate::debuginfo::metadata::{
|
||||
UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
|
||||
unknown_file_metadata,
|
||||
UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes,
|
||||
file_metadata_from_def_id, type_di_node, unknown_file_metadata,
|
||||
};
|
||||
use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item};
|
||||
use crate::llvm::debuginfo::{DIFlags, DIType};
|
||||
|
|
@ -68,6 +69,11 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
|
|||
enum_type_and_layout: TyAndLayout<'tcx>,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let containing_scope = get_namespace_for_item(cx, enum_adt_def.did());
|
||||
let enum_adt_def_id = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(enum_adt_def.did())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
DINodeCreationResult {
|
||||
di_node: build_enumeration_type_di_node(
|
||||
cx,
|
||||
|
|
@ -77,6 +83,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
|
|||
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
|
||||
(name, discr.val)
|
||||
}),
|
||||
enum_adt_def_id,
|
||||
containing_scope,
|
||||
),
|
||||
already_stored_in_typemap: false,
|
||||
|
|
@ -92,6 +99,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
|
|||
type_name: &str,
|
||||
base_type: Ty<'tcx>,
|
||||
enumerators: impl Iterator<Item = (Cow<'tcx, str>, u128)>,
|
||||
def_id: Option<rustc_span::def_id::DefId>,
|
||||
containing_scope: &'ll DIType,
|
||||
) -> &'ll DIType {
|
||||
let is_unsigned = match base_type.kind() {
|
||||
|
|
@ -115,14 +123,21 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let (file_metadata, line_number) = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers
|
||||
{
|
||||
file_metadata_from_def_id(cx, def_id)
|
||||
} else {
|
||||
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateEnumerationType(
|
||||
DIB(cx),
|
||||
containing_scope,
|
||||
type_name.as_c_char_ptr(),
|
||||
type_name.len(),
|
||||
unknown_file_metadata(cx),
|
||||
UNKNOWN_LINE_NUMBER,
|
||||
file_metadata,
|
||||
line_number,
|
||||
size.bits(),
|
||||
align.bits() as u32,
|
||||
create_DIArray(DIB(cx), &enumerator_di_nodes[..]),
|
||||
|
|
@ -193,6 +208,12 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
) -> &'ll DIType {
|
||||
assert_eq!(variant_layout.ty, enum_type_and_layout.ty);
|
||||
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(variant_def.def_id)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
type_map::build_type_with_children(
|
||||
cx,
|
||||
type_map::stub(
|
||||
|
|
@ -204,6 +225,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
variant_index,
|
||||
),
|
||||
variant_def.name.as_str(),
|
||||
def_location,
|
||||
// NOTE: We use size and align of enum_type, not from variant_layout:
|
||||
size_and_align_of(enum_type_and_layout),
|
||||
Some(enum_type_di_node),
|
||||
|
|
@ -231,6 +253,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
variant_layout.fields.offset(field_index),
|
||||
di_flags,
|
||||
type_di_node(cx, field_layout.ty),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect::<SmallVec<_>>()
|
||||
|
|
@ -286,6 +309,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
Stub::Struct,
|
||||
unique_type_id,
|
||||
&variant_name,
|
||||
None,
|
||||
size_and_align_of(coroutine_type_and_layout),
|
||||
Some(coroutine_type_di_node),
|
||||
DIFlags::FlagZero,
|
||||
|
|
@ -312,6 +336,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
variant_layout.fields.offset(field_index),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, field_type),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -331,6 +356,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
|
|||
coroutine_type_and_layout.fields.offset(index),
|
||||
DIFlags::FlagZero,
|
||||
type_di_node(cx, upvar_ty),
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
|
|
|||
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