Merge from rustc
This commit is contained in:
commit
560de7e512
1844 changed files with 46923 additions and 47824 deletions
|
|
@ -3757,7 +3757,6 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
|
|
@ -3796,6 +3795,7 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
|
|
@ -4494,7 +4494,6 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_transmute",
|
||||
"rustc_type_ir",
|
||||
"smallvec",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@
|
|||
# Note that this will attempt to download GCC even if there are local
|
||||
# modifications to the `src/gcc` submodule.
|
||||
# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
|
||||
# download-ci-gcc = false
|
||||
#download-ci-gcc = false
|
||||
|
||||
# =============================================================================
|
||||
# General build configuration options
|
||||
|
|
@ -570,6 +570,12 @@
|
|||
# Defaults to rust.debug-assertions value
|
||||
#debug-assertions-std = rust.debug-assertions (boolean)
|
||||
|
||||
# Whether or not debug assertions are enabled for the tools built by bootstrap.
|
||||
# Overrides the `debug-assertions` option, if defined.
|
||||
#
|
||||
# Defaults to rust.debug-assertions value
|
||||
#debug-assertions-tools = rust.debug-assertions (boolean)
|
||||
|
||||
# Whether or not to leave debug! and trace! calls in the rust binary.
|
||||
#
|
||||
# Defaults to rust.debug-assertions value
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@
|
|||
#![feature(decl_macro)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(unwrap_infallible)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::alloc::Layout;
|
||||
|
|
@ -200,6 +202,18 @@ impl<T> TypedArena<T> {
|
|||
/// storing the elements in the arena.
|
||||
#[inline]
|
||||
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
|
||||
self.try_alloc_from_iter(iter.into_iter().map(Ok::<T, !>)).into_ok()
|
||||
}
|
||||
|
||||
/// Allocates the elements of this iterator into a contiguous slice in the `TypedArena`.
|
||||
///
|
||||
/// Note: for reasons of reentrancy and panic safety we collect into a `SmallVec<[_; 8]>` before
|
||||
/// storing the elements in the arena.
|
||||
#[inline]
|
||||
pub fn try_alloc_from_iter<E>(
|
||||
&self,
|
||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||
) -> Result<&mut [T], E> {
|
||||
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
|
||||
// is subtle: these arenas are reentrant. In other words, `iter` may very well be holding a
|
||||
// reference to `self` and adding elements to the arena during iteration.
|
||||
|
|
@ -214,18 +228,19 @@ impl<T> TypedArena<T> {
|
|||
// doesn't need to be hyper-optimized.
|
||||
assert!(size_of::<T>() != 0);
|
||||
|
||||
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
|
||||
let vec: Result<SmallVec<[T; 8]>, E> = iter.into_iter().collect();
|
||||
let mut vec = vec?;
|
||||
if vec.is_empty() {
|
||||
return &mut [];
|
||||
return Ok(&mut []);
|
||||
}
|
||||
// Move the content to the arena by copying and then forgetting it.
|
||||
let len = vec.len();
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
unsafe {
|
||||
Ok(unsafe {
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Grows the arena.
|
||||
|
|
@ -566,27 +581,34 @@ impl DroplessArena {
|
|||
// `drop`.
|
||||
unsafe { self.write_from_iter(iter, len, mem) }
|
||||
}
|
||||
(_, _) => {
|
||||
outline(move || -> &mut [T] {
|
||||
// Takes care of reentrancy.
|
||||
let mut vec: SmallVec<[_; 8]> = iter.collect();
|
||||
if vec.is_empty() {
|
||||
return &mut [];
|
||||
}
|
||||
// Move the content to the arena by copying it and then forgetting
|
||||
// the content of the SmallVec
|
||||
unsafe {
|
||||
let len = vec.len();
|
||||
let start_ptr =
|
||||
self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
}
|
||||
})
|
||||
}
|
||||
(_, _) => outline(move || self.try_alloc_from_iter(iter.map(Ok::<T, !>)).into_ok()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_alloc_from_iter<T, E>(
|
||||
&self,
|
||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||
) -> Result<&mut [T], E> {
|
||||
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
|
||||
// cannot know the minimum length of the iterator in this case.
|
||||
assert!(size_of::<T>() != 0);
|
||||
|
||||
// Takes care of reentrancy.
|
||||
let vec: Result<SmallVec<[T; 8]>, E> = iter.into_iter().collect();
|
||||
let mut vec = vec?;
|
||||
if vec.is_empty() {
|
||||
return Ok(&mut []);
|
||||
}
|
||||
// Move the content to the arena by copying and then forgetting it.
|
||||
let len = vec.len();
|
||||
Ok(unsafe {
|
||||
let start_ptr = self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T;
|
||||
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
|
||||
vec.set_len(0);
|
||||
slice::from_raw_parts_mut(start_ptr, len)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare an `Arena` containing one dropless arena and many typed arenas (the
|
||||
|
|
|
|||
|
|
@ -2469,6 +2469,8 @@ pub enum TyPatKind {
|
|||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||
Range(Option<P<AnonConst>>, Option<P<AnonConst>>, Spanned<RangeEnd>),
|
||||
|
||||
Or(ThinVec<P<TyPat>>),
|
||||
|
||||
/// Placeholder for a pattern that wasn't syntactically well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
test(attr(deny(warnings)))
|
||||
)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(array_windows)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
#![feature(never_type)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod util {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
use std::ops::DerefMut;
|
||||
use std::panic;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
|
|
@ -20,7 +19,6 @@ use thin_vec::ThinVec;
|
|||
|
||||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, Token};
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
|
||||
|
||||
|
|
@ -48,11 +46,6 @@ pub trait WalkItemKind {
|
|||
}
|
||||
|
||||
pub trait MutVisitor: Sized {
|
||||
/// Mutable token visiting only exists for the `macro_rules` token marker and should not be
|
||||
/// used otherwise. Token visitor would be entirely separate from the regular visitor if
|
||||
/// the marker didn't have to visit AST fragments in nonterminal tokens.
|
||||
const VISIT_TOKENS: bool = false;
|
||||
|
||||
// Methods in this trait have one of three forms:
|
||||
//
|
||||
// fn visit_t(&mut self, t: &mut T); // common
|
||||
|
|
@ -360,6 +353,8 @@ pub trait MutVisitor: Sized {
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
// Span visiting is no longer used, but we keep it for now,
|
||||
// in case it's needed for something like #127241.
|
||||
fn visit_span(&mut self, _sp: &mut Span) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
|
@ -473,12 +468,8 @@ fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
|
|||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
|
||||
let DelimArgs { dspan, delim: _, tokens } = args;
|
||||
visit_tts(vis, tokens);
|
||||
visit_delim_span(vis, dspan);
|
||||
}
|
||||
|
||||
pub fn visit_delim_span<T: MutVisitor>(vis: &mut T, DelimSpan { open, close }: &mut DelimSpan) {
|
||||
let DelimArgs { dspan, delim: _, tokens: _ } = args;
|
||||
let DelimSpan { open, close } = dspan;
|
||||
vis.visit_span(open);
|
||||
vis.visit_span(close);
|
||||
}
|
||||
|
|
@ -552,7 +543,7 @@ fn walk_assoc_item_constraint<T: MutVisitor>(
|
|||
}
|
||||
|
||||
pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
||||
let Ty { id, kind, span, tokens } = ty.deref_mut();
|
||||
let Ty { id, kind, span, tokens: _ } = ty.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
TyKind::Err(_guar) => {}
|
||||
|
|
@ -600,21 +591,20 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
}
|
||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_ty_pat<T: MutVisitor>(vis: &mut T, ty: &mut P<TyPat>) {
|
||||
let TyPat { id, kind, span, tokens } = ty.deref_mut();
|
||||
let TyPat { id, kind, span, tokens: _ } = ty.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
TyPatKind::Range(start, end, _include_end) => {
|
||||
visit_opt(start, |c| vis.visit_anon_const(c));
|
||||
visit_opt(end, |c| vis.visit_anon_const(c));
|
||||
}
|
||||
TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)),
|
||||
TyPatKind::Err(_) => {}
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -654,11 +644,10 @@ fn walk_path_segment<T: MutVisitor>(vis: &mut T, segment: &mut PathSegment) {
|
|||
visit_opt(args, |args| vis.visit_generic_args(args));
|
||||
}
|
||||
|
||||
fn walk_path<T: MutVisitor>(vis: &mut T, Path { segments, span, tokens }: &mut Path) {
|
||||
fn walk_path<T: MutVisitor>(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) {
|
||||
for segment in segments {
|
||||
vis.visit_path_segment(segment);
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +693,7 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare
|
|||
}
|
||||
|
||||
fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
|
||||
let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local.deref_mut();
|
||||
visit_opt(super_, |sp| vis.visit_span(sp));
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
|
|
@ -720,7 +709,6 @@ fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
|
|||
vis.visit_block(els);
|
||||
}
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
visit_opt(colon_sp, |sp| vis.visit_span(sp));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
|
@ -729,14 +717,10 @@ fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
|
|||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr {
|
||||
item: AttrItem { unsafety: _, path, args, tokens },
|
||||
tokens: attr_tokens,
|
||||
} = &mut **normal;
|
||||
let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } =
|
||||
&mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(vis, args);
|
||||
visit_lazy_tts(vis, tokens);
|
||||
visit_lazy_tts(vis, attr_tokens);
|
||||
}
|
||||
AttrKind::DocComment(_kind, _sym) => {}
|
||||
}
|
||||
|
|
@ -785,90 +769,6 @@ pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> Smal
|
|||
smallvec![param]
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_attr_tt<T: MutVisitor>(vis: &mut T, tt: &mut AttrTokenTree) {
|
||||
match tt {
|
||||
AttrTokenTree::Token(token, _spacing) => {
|
||||
visit_token(vis, token);
|
||||
}
|
||||
AttrTokenTree::Delimited(dspan, _spacing, _delim, tts) => {
|
||||
visit_attr_tts(vis, tts);
|
||||
visit_delim_span(vis, dspan);
|
||||
}
|
||||
AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => {
|
||||
visit_attrs(vis, attrs);
|
||||
visit_lazy_tts_opt_mut(vis, Some(tokens));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_tt<T: MutVisitor>(vis: &mut T, tt: &mut TokenTree) {
|
||||
match tt {
|
||||
TokenTree::Token(token, _spacing) => {
|
||||
visit_token(vis, token);
|
||||
}
|
||||
TokenTree::Delimited(dspan, _spacing, _delim, tts) => {
|
||||
visit_tts(vis, tts);
|
||||
visit_delim_span(vis, dspan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_tts<T: MutVisitor>(vis: &mut T, TokenStream(tts): &mut TokenStream) {
|
||||
if T::VISIT_TOKENS && !tts.is_empty() {
|
||||
let tts = Arc::make_mut(tts);
|
||||
visit_vec(tts, |tree| visit_tt(vis, tree));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attr_tts<T: MutVisitor>(vis: &mut T, AttrTokenStream(tts): &mut AttrTokenStream) {
|
||||
if T::VISIT_TOKENS && !tts.is_empty() {
|
||||
let tts = Arc::make_mut(tts);
|
||||
visit_vec(tts, |tree| visit_attr_tt(vis, tree));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_lazy_tts_opt_mut<T: MutVisitor>(vis: &mut T, lazy_tts: Option<&mut LazyAttrTokenStream>) {
|
||||
if T::VISIT_TOKENS {
|
||||
if let Some(lazy_tts) = lazy_tts {
|
||||
let mut tts = lazy_tts.to_attr_token_stream();
|
||||
visit_attr_tts(vis, &mut tts);
|
||||
*lazy_tts = LazyAttrTokenStream::new(tts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrTokenStream>) {
|
||||
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
|
||||
}
|
||||
|
||||
/// Applies ident visitor if it's an ident. In practice this is not actually
|
||||
/// used by specific visitors right now, but there's a test below checking that
|
||||
/// it works.
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
|
||||
let Token { kind, span } = t;
|
||||
match kind {
|
||||
token::Ident(name, _is_raw) | token::Lifetime(name, _is_raw) => {
|
||||
let mut ident = Ident::new(*name, *span);
|
||||
vis.visit_ident(&mut ident);
|
||||
*name = ident.name;
|
||||
*span = ident.span;
|
||||
return; // Avoid visiting the span for the second time.
|
||||
}
|
||||
token::NtIdent(ident, _is_raw) => {
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
token::NtLifetime(ident, _is_raw) => {
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
|
||||
match defaultness {
|
||||
|
|
@ -1187,10 +1087,9 @@ fn walk_mt<T: MutVisitor>(vis: &mut T, MutTy { ty, mutbl: _ }: &mut MutTy) {
|
|||
}
|
||||
|
||||
pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
|
||||
let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
|
||||
let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut();
|
||||
vis.visit_id(id);
|
||||
stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -1471,12 +1370,11 @@ fn walk_item_ctxt<K: WalkItemKind>(
|
|||
item: &mut P<Item<K>>,
|
||||
ctxt: K::Ctxt,
|
||||
) {
|
||||
let Item { attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
||||
let Item { attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
kind.walk(*span, *id, vis, ctxt, visitor);
|
||||
visit_lazy_tts(visitor, tokens);
|
||||
visitor.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -1550,7 +1448,7 @@ impl WalkItemKind for ForeignItemKind {
|
|||
}
|
||||
|
||||
pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
||||
let Pat { id, kind, span, tokens } = pat.deref_mut();
|
||||
let Pat { id, kind, span, tokens: _ } = pat.deref_mut();
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
PatKind::Err(_guar) => {}
|
||||
|
|
@ -1592,7 +1490,6 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
|||
PatKind::Paren(inner) => vis.visit_pat(inner),
|
||||
PatKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -1656,7 +1553,7 @@ fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
|
|||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens }: &mut Expr) {
|
||||
pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) {
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
match kind {
|
||||
|
|
@ -1847,7 +1744,6 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
|||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
@ -1889,17 +1785,16 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV
|
|||
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
|
||||
StmtKind::Empty => smallvec![StmtKind::Empty],
|
||||
StmtKind::MacCall(mut mac) => {
|
||||
let MacCallStmt { mac: mac_, style: _, attrs, tokens } = mac.deref_mut();
|
||||
let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut();
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_mac_call(mac_);
|
||||
visit_lazy_tts(vis, tokens);
|
||||
smallvec![StmtKind::MacCall(mac)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
|
||||
let Visibility { kind, span, tokens } = visibility;
|
||||
let Visibility { kind, span, tokens: _ } = visibility;
|
||||
match kind {
|
||||
VisibilityKind::Public | VisibilityKind::Inherited => {}
|
||||
VisibilityKind::Restricted { path, id, shorthand: _ } => {
|
||||
|
|
@ -1907,7 +1802,6 @@ fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
|
|||
vis.visit_path(path);
|
||||
}
|
||||
}
|
||||
visit_lazy_tts(vis, tokens);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,16 @@
|
|||
//! ownership of the original.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use std::{cmp, fmt, iter};
|
||||
use std::{cmp, fmt, iter, mem};
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ast::AttrStyle;
|
||||
use crate::ast_traits::{HasAttrs, HasTokens};
|
||||
|
|
@ -106,25 +108,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync {
|
||||
fn to_attr_token_stream(&self) -> AttrTokenStream;
|
||||
}
|
||||
|
||||
impl ToAttrTokenStream for AttrTokenStream {
|
||||
fn to_attr_token_stream(&self) -> AttrTokenStream {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazy version of [`TokenStream`], which defers creation
|
||||
/// of an actual `TokenStream` until it is needed.
|
||||
/// `Box` is here only to reduce the structure size.
|
||||
/// A lazy version of [`AttrTokenStream`], which defers creation of an actual
|
||||
/// `AttrTokenStream` until it is needed.
|
||||
#[derive(Clone)]
|
||||
pub struct LazyAttrTokenStream(Arc<Box<dyn ToAttrTokenStream>>);
|
||||
pub struct LazyAttrTokenStream(Arc<LazyAttrTokenStreamInner>);
|
||||
|
||||
impl LazyAttrTokenStream {
|
||||
pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream {
|
||||
LazyAttrTokenStream(Arc::new(Box::new(inner)))
|
||||
pub fn new_direct(stream: AttrTokenStream) -> LazyAttrTokenStream {
|
||||
LazyAttrTokenStream(Arc::new(LazyAttrTokenStreamInner::Direct(stream)))
|
||||
}
|
||||
|
||||
pub fn new_pending(
|
||||
start_token: (Token, Spacing),
|
||||
cursor_snapshot: TokenCursor,
|
||||
num_calls: u32,
|
||||
break_last_token: u32,
|
||||
node_replacements: ThinVec<NodeReplacement>,
|
||||
) -> LazyAttrTokenStream {
|
||||
LazyAttrTokenStream(Arc::new(LazyAttrTokenStreamInner::Pending {
|
||||
start_token,
|
||||
cursor_snapshot,
|
||||
num_calls,
|
||||
break_last_token,
|
||||
node_replacements,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn to_attr_token_stream(&self) -> AttrTokenStream {
|
||||
|
|
@ -156,6 +163,184 @@ impl<CTX> HashStable<CTX> for LazyAttrTokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// A token range within a `Parser`'s full token stream.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ParserRange(pub Range<u32>);
|
||||
|
||||
/// A token range within an individual AST node's (lazy) token stream, i.e.
|
||||
/// relative to that node's first token. Distinct from `ParserRange` so the two
|
||||
/// kinds of range can't be mixed up.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NodeRange(pub Range<u32>);
|
||||
|
||||
/// Indicates a range of tokens that should be replaced by an `AttrsTarget`
|
||||
/// (replacement) or be replaced by nothing (deletion). This is used in two
|
||||
/// places during token collection.
|
||||
///
|
||||
/// 1. Replacement. During the parsing of an AST node that may have a
|
||||
/// `#[derive]` attribute, when we parse a nested AST node that has `#[cfg]`
|
||||
/// or `#[cfg_attr]`, we replace the entire inner AST node with
|
||||
/// `FlatToken::AttrsTarget`. This lets us perform eager cfg-expansion on an
|
||||
/// `AttrTokenStream`.
|
||||
///
|
||||
/// 2. Deletion. We delete inner attributes from all collected token streams,
|
||||
/// and instead track them through the `attrs` field on the AST node. This
|
||||
/// lets us manipulate them similarly to outer attributes. When we create a
|
||||
/// `TokenStream`, the inner attributes are inserted into the proper place
|
||||
/// in the token stream.
|
||||
///
|
||||
/// Each replacement starts off in `ParserReplacement` form but is converted to
|
||||
/// `NodeReplacement` form when it is attached to a single AST node, via
|
||||
/// `LazyAttrTokenStreamImpl`.
|
||||
pub type ParserReplacement = (ParserRange, Option<AttrsTarget>);
|
||||
|
||||
/// See the comment on `ParserReplacement`.
|
||||
pub type NodeReplacement = (NodeRange, Option<AttrsTarget>);
|
||||
|
||||
impl NodeRange {
|
||||
// Converts a range within a parser's tokens to a range within a
|
||||
// node's tokens beginning at `start_pos`.
|
||||
//
|
||||
// For example, imagine a parser with 50 tokens in its token stream, a
|
||||
// function that spans `ParserRange(20..40)` and an inner attribute within
|
||||
// that function that spans `ParserRange(30..35)`. We would find the inner
|
||||
// attribute's range within the function's tokens by subtracting 20, which
|
||||
// is the position of the function's start token. This gives
|
||||
// `NodeRange(10..15)`.
|
||||
pub fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange {
|
||||
assert!(!parser_range.is_empty());
|
||||
assert!(parser_range.start >= start_pos);
|
||||
NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos))
|
||||
}
|
||||
}
|
||||
|
||||
enum LazyAttrTokenStreamInner {
|
||||
// The token stream has already been produced.
|
||||
Direct(AttrTokenStream),
|
||||
|
||||
// From a value of this type we can reconstruct the `TokenStream` seen by
|
||||
// the `f` callback passed to a call to `Parser::collect_tokens`, by
|
||||
// replaying the getting of the tokens. This saves us producing a
|
||||
// `TokenStream` if it is never needed, e.g. a captured `macro_rules!`
|
||||
// argument that is never passed to a proc macro. In practice, token stream
|
||||
// creation happens rarely compared to calls to `collect_tokens` (see some
|
||||
// statistics in #78736) so we are doing as little up-front work as
|
||||
// possible.
|
||||
//
|
||||
// This also makes `Parser` very cheap to clone, since there is no
|
||||
// intermediate collection buffer to clone.
|
||||
Pending {
|
||||
start_token: (Token, Spacing),
|
||||
cursor_snapshot: TokenCursor,
|
||||
num_calls: u32,
|
||||
break_last_token: u32,
|
||||
node_replacements: ThinVec<NodeReplacement>,
|
||||
},
|
||||
}
|
||||
|
||||
impl LazyAttrTokenStreamInner {
|
||||
fn to_attr_token_stream(&self) -> AttrTokenStream {
|
||||
match self {
|
||||
LazyAttrTokenStreamInner::Direct(stream) => stream.clone(),
|
||||
LazyAttrTokenStreamInner::Pending {
|
||||
start_token,
|
||||
cursor_snapshot,
|
||||
num_calls,
|
||||
break_last_token,
|
||||
node_replacements,
|
||||
} => {
|
||||
// The token produced by the final call to `{,inlined_}next` was not
|
||||
// actually consumed by the callback. The combination of chaining the
|
||||
// initial token and using `take` produces the desired result - we
|
||||
// produce an empty `TokenStream` if no calls were made, and omit the
|
||||
// final token otherwise.
|
||||
let mut cursor_snapshot = cursor_snapshot.clone();
|
||||
let tokens = iter::once(FlatToken::Token(*start_token))
|
||||
.chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
|
||||
.take(*num_calls as usize);
|
||||
|
||||
if node_replacements.is_empty() {
|
||||
make_attr_token_stream(tokens, *break_last_token)
|
||||
} else {
|
||||
let mut tokens: Vec<_> = tokens.collect();
|
||||
let mut node_replacements = node_replacements.to_vec();
|
||||
node_replacements.sort_by_key(|(range, _)| range.0.start);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for [(node_range, tokens), (next_node_range, next_tokens)] in
|
||||
node_replacements.array_windows()
|
||||
{
|
||||
assert!(
|
||||
node_range.0.end <= next_node_range.0.start
|
||||
|| node_range.0.end >= next_node_range.0.end,
|
||||
"Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})",
|
||||
node_range,
|
||||
tokens,
|
||||
next_node_range,
|
||||
next_tokens,
|
||||
);
|
||||
}
|
||||
|
||||
// Process the replace ranges, starting from the highest start
|
||||
// position and working our way back. If have tokens like:
|
||||
//
|
||||
// `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
|
||||
//
|
||||
// Then we will generate replace ranges for both
|
||||
// the `#[cfg(FALSE)] field: bool` and the entire
|
||||
// `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
|
||||
//
|
||||
// By starting processing from the replace range with the greatest
|
||||
// start position, we ensure that any (outer) replace range which
|
||||
// encloses another (inner) replace range will fully overwrite the
|
||||
// inner range's replacement.
|
||||
for (node_range, target) in node_replacements.into_iter().rev() {
|
||||
assert!(
|
||||
!node_range.0.is_empty(),
|
||||
"Cannot replace an empty node range: {:?}",
|
||||
node_range.0
|
||||
);
|
||||
|
||||
// Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s,
|
||||
// plus enough `FlatToken::Empty`s to fill up the rest of the range. This
|
||||
// keeps the total length of `tokens` constant throughout the replacement
|
||||
// process, allowing us to do all replacements without adjusting indices.
|
||||
let target_len = target.is_some() as usize;
|
||||
tokens.splice(
|
||||
(node_range.0.start as usize)..(node_range.0.end as usize),
|
||||
target.into_iter().map(|target| FlatToken::AttrsTarget(target)).chain(
|
||||
iter::repeat(FlatToken::Empty)
|
||||
.take(node_range.0.len() - target_len),
|
||||
),
|
||||
);
|
||||
}
|
||||
make_attr_token_stream(tokens.into_iter(), *break_last_token)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper struct used when building an `AttrTokenStream` from
|
||||
/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens
|
||||
/// are stored as `FlatToken::Token`. A vector of `FlatToken`s
|
||||
/// is then 'parsed' to build up an `AttrTokenStream` with nested
|
||||
/// `AttrTokenTree::Delimited` tokens.
|
||||
#[derive(Debug, Clone)]
|
||||
enum FlatToken {
|
||||
/// A token - this holds both delimiter (e.g. '{' and '}')
|
||||
/// and non-delimiter tokens
|
||||
Token((Token, Spacing)),
|
||||
/// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted
|
||||
/// directly into the constructed `AttrTokenStream` as an
|
||||
/// `AttrTokenTree::AttrsTarget`.
|
||||
AttrsTarget(AttrsTarget),
|
||||
/// A special 'empty' token that is ignored during the conversion
|
||||
/// to an `AttrTokenStream`. This is used to simplify the
|
||||
/// handling of replace ranges.
|
||||
Empty,
|
||||
}
|
||||
|
||||
/// An `AttrTokenStream` is similar to a `TokenStream`, but with extra
|
||||
/// information about the tokens for attribute targets. This is used
|
||||
/// during expansion to perform early cfg-expansion, and to process attributes
|
||||
|
|
@ -163,6 +348,71 @@ impl<CTX> HashStable<CTX> for LazyAttrTokenStream {
|
|||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
pub struct AttrTokenStream(pub Arc<Vec<AttrTokenTree>>);
|
||||
|
||||
/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an
|
||||
/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and
|
||||
/// close delims.
|
||||
fn make_attr_token_stream(
|
||||
iter: impl Iterator<Item = FlatToken>,
|
||||
break_last_token: u32,
|
||||
) -> AttrTokenStream {
|
||||
#[derive(Debug)]
|
||||
struct FrameData {
|
||||
// This is `None` for the first frame, `Some` for all others.
|
||||
open_delim_sp: Option<(Delimiter, Span, Spacing)>,
|
||||
inner: Vec<AttrTokenTree>,
|
||||
}
|
||||
// The stack always has at least one element. Storing it separately makes for shorter code.
|
||||
let mut stack_top = FrameData { open_delim_sp: None, inner: vec![] };
|
||||
let mut stack_rest = vec![];
|
||||
for flat_token in iter {
|
||||
match flat_token {
|
||||
FlatToken::Token((token @ Token { kind, span }, spacing)) => {
|
||||
if let Some(delim) = kind.open_delim() {
|
||||
stack_rest.push(mem::replace(
|
||||
&mut stack_top,
|
||||
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
||||
));
|
||||
} else if let Some(delim) = kind.close_delim() {
|
||||
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
|
||||
let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
||||
assert!(
|
||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||
"Mismatched open/close delims: open={open_delim:?} close={span:?}"
|
||||
);
|
||||
let dspan = DelimSpan::from_pair(open_sp, span);
|
||||
let dspacing = DelimSpacing::new(open_spacing, spacing);
|
||||
let stream = AttrTokenStream::new(frame_data.inner);
|
||||
let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
|
||||
stack_top.inner.push(delimited);
|
||||
} else {
|
||||
stack_top.inner.push(AttrTokenTree::Token(token, spacing))
|
||||
}
|
||||
}
|
||||
FlatToken::AttrsTarget(target) => {
|
||||
stack_top.inner.push(AttrTokenTree::AttrsTarget(target))
|
||||
}
|
||||
FlatToken::Empty => {}
|
||||
}
|
||||
}
|
||||
|
||||
if break_last_token > 0 {
|
||||
let last_token = stack_top.inner.pop().unwrap();
|
||||
if let AttrTokenTree::Token(last_token, spacing) = last_token {
|
||||
let (unglued, _) = last_token.kind.break_two_token_op(break_last_token).unwrap();
|
||||
|
||||
// Tokens are always ASCII chars, so we can use byte arithmetic here.
|
||||
let mut first_span = last_token.span.shrink_to_lo();
|
||||
first_span =
|
||||
first_span.with_hi(first_span.lo() + rustc_span::BytePos(break_last_token));
|
||||
|
||||
stack_top.inner.push(AttrTokenTree::Token(Token::new(unglued, first_span), spacing));
|
||||
} else {
|
||||
panic!("Unexpected last token {last_token:?}")
|
||||
}
|
||||
}
|
||||
AttrTokenStream::new(stack_top.inner)
|
||||
}
|
||||
|
||||
/// Like `TokenTree`, but for `AttrTokenStream`.
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub enum AttrTokenTree {
|
||||
|
|
@ -641,6 +891,104 @@ impl<'t> Iterator for TokenStreamIter<'t> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TokenTreeCursor {
|
||||
stream: TokenStream,
|
||||
/// Points to the current token tree in the stream. In `TokenCursor::curr`,
|
||||
/// this can be any token tree. In `TokenCursor::stack`, this is always a
|
||||
/// `TokenTree::Delimited`.
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl TokenTreeCursor {
|
||||
#[inline]
|
||||
pub fn new(stream: TokenStream) -> Self {
|
||||
TokenTreeCursor { stream, index: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn curr(&self) -> Option<&TokenTree> {
|
||||
self.stream.get(self.index)
|
||||
}
|
||||
|
||||
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
|
||||
self.stream.get(self.index + n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bump(&mut self) {
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// A `TokenStream` cursor that produces `Token`s. It's a bit odd that
|
||||
/// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b)
|
||||
/// use this type to emit them as a linear sequence. But a linear sequence is
|
||||
/// what the parser expects, for the most part.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TokenCursor {
|
||||
// Cursor for the current (innermost) token stream. The index within the
|
||||
// cursor can point to any token tree in the stream (or one past the end).
|
||||
// The delimiters for this token stream are found in `self.stack.last()`;
|
||||
// if that is `None` we are in the outermost token stream which never has
|
||||
// delimiters.
|
||||
pub curr: TokenTreeCursor,
|
||||
|
||||
// Token streams surrounding the current one. The index within each cursor
|
||||
// always points to a `TokenTree::Delimited`.
|
||||
pub stack: Vec<TokenTreeCursor>,
|
||||
}
|
||||
|
||||
impl TokenCursor {
|
||||
pub fn next(&mut self) -> (Token, Spacing) {
|
||||
self.inlined_next()
|
||||
}
|
||||
|
||||
/// This always-inlined version should only be used on hot code paths.
|
||||
#[inline(always)]
|
||||
pub fn inlined_next(&mut self) -> (Token, Spacing) {
|
||||
loop {
|
||||
// FIXME: we currently don't return `Delimiter::Invisible` open/close delims. To fix
|
||||
// #67062 we will need to, whereupon the `delim != Delimiter::Invisible` conditions
|
||||
// below can be removed.
|
||||
if let Some(tree) = self.curr.curr() {
|
||||
match tree {
|
||||
&TokenTree::Token(token, spacing) => {
|
||||
debug_assert!(!token.kind.is_delim());
|
||||
let res = (token, spacing);
|
||||
self.curr.bump();
|
||||
return res;
|
||||
}
|
||||
&TokenTree::Delimited(sp, spacing, delim, ref tts) => {
|
||||
let trees = TokenTreeCursor::new(tts.clone());
|
||||
self.stack.push(mem::replace(&mut self.curr, trees));
|
||||
if !delim.skip() {
|
||||
return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open);
|
||||
}
|
||||
// No open delimiter to return; continue on to the next iteration.
|
||||
}
|
||||
};
|
||||
} else if let Some(parent) = self.stack.pop() {
|
||||
// We have exhausted this token stream. Move back to its parent token stream.
|
||||
let Some(&TokenTree::Delimited(span, spacing, delim, _)) = parent.curr() else {
|
||||
panic!("parent should be Delimited")
|
||||
};
|
||||
self.curr = parent;
|
||||
self.curr.bump(); // move past the `Delimited`
|
||||
if !delim.skip() {
|
||||
return (Token::new(delim.as_close_token_kind(), span.close), spacing.close);
|
||||
}
|
||||
// No close delimiter to return; continue on to the next iteration.
|
||||
} else {
|
||||
// We have exhausted the outermost token stream. The use of
|
||||
// `Spacing::Alone` is arbitrary and immaterial, because the
|
||||
// `Eof` token's spacing is never used.
|
||||
return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct DelimSpan {
|
||||
pub open: Span,
|
||||
|
|
@ -687,6 +1035,7 @@ mod size_asserts {
|
|||
static_assert_size!(AttrTokenStream, 8);
|
||||
static_assert_size!(AttrTokenTree, 32);
|
||||
static_assert_size!(LazyAttrTokenStream, 8);
|
||||
static_assert_size!(LazyAttrTokenStreamInner, 88);
|
||||
static_assert_size!(Option<LazyAttrTokenStream>, 8); // must be small, used in many AST nodes
|
||||
static_assert_size!(TokenStream, 8);
|
||||
static_assert_size!(TokenTree, 32);
|
||||
|
|
|
|||
|
|
@ -608,6 +608,7 @@ pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Res
|
|||
visit_opt!(visitor, visit_anon_const, start);
|
||||
visit_opt!(visitor, visit_anon_const, end);
|
||||
}
|
||||
TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants),
|
||||
TyPatKind::Err(_) => {}
|
||||
}
|
||||
V::Result::output()
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ use rustc_attr_parsing::{AttributeParser, OmitDoc};
|
|||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::spawn;
|
||||
use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
|
|
@ -454,9 +455,14 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
|||
.lower_node(def_id);
|
||||
}
|
||||
|
||||
// Drop AST to free memory
|
||||
drop(ast_index);
|
||||
sess.time("drop_ast", || drop(krate));
|
||||
|
||||
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
|
||||
let prof = sess.prof.clone();
|
||||
spawn(move || {
|
||||
let _timer = prof.verbose_generic_activity("drop_ast");
|
||||
drop(krate);
|
||||
});
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let opt_hir_hash =
|
||||
|
|
|
|||
|
|
@ -464,6 +464,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
)
|
||||
}),
|
||||
),
|
||||
TyPatKind::Or(variants) => {
|
||||
hir::TyPatKind::Or(self.arena.alloc_from_iter(
|
||||
variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),
|
||||
))
|
||||
}
|
||||
TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(rustdoc_internals)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,38 @@ struct BufEntry {
|
|||
size: isize,
|
||||
}
|
||||
|
||||
// Boxes opened with methods like `Printer::{cbox,ibox}` must be closed with
|
||||
// `Printer::end`. Failure to do so can result in bad indenting, or in extreme
|
||||
// cases, cause no output to be produced at all.
|
||||
//
|
||||
// Box opening and closing used to be entirely implicit, which was hard to
|
||||
// understand and easy to get wrong. This marker type is now returned from the
|
||||
// box opening methods and forgotten by `Printer::end`. Any marker that isn't
|
||||
// forgotten will trigger a panic in `drop`. (Closing a box more than once
|
||||
// isn't possible because `BoxMarker` doesn't implement `Copy` or `Clone`.)
|
||||
//
|
||||
// FIXME(nnethercote): the panic in `drop` is currently disabled because a few
|
||||
// places fail to close their boxes. It can be enabled once they are fixed.
|
||||
//
|
||||
// Note: it would be better to make open/close mismatching impossible and avoid
|
||||
// the need for this marker type altogether by having functions like
|
||||
// `with_ibox` that open a box, call a closure, and then close the box. That
|
||||
// would work for simple cases, but box lifetimes sometimes interact with
|
||||
// complex control flow and across function boundaries in ways that are
|
||||
// difficult to handle with such a technique.
|
||||
#[must_use]
|
||||
pub struct BoxMarker;
|
||||
|
||||
impl !Clone for BoxMarker {}
|
||||
impl !Copy for BoxMarker {}
|
||||
|
||||
impl Drop for BoxMarker {
|
||||
fn drop(&mut self) {
|
||||
// FIXME(nnethercote): enable once the bad cases are fixed
|
||||
//panic!("BoxMarker not ended with `Printer::end()`");
|
||||
}
|
||||
}
|
||||
|
||||
impl Printer {
|
||||
pub fn new() -> Self {
|
||||
Printer {
|
||||
|
|
@ -270,7 +302,8 @@ impl Printer {
|
|||
}
|
||||
}
|
||||
|
||||
fn scan_begin(&mut self, token: BeginToken) {
|
||||
// This is is where `BoxMarker`s are produced.
|
||||
fn scan_begin(&mut self, token: BeginToken) -> BoxMarker {
|
||||
if self.scan_stack.is_empty() {
|
||||
self.left_total = 1;
|
||||
self.right_total = 1;
|
||||
|
|
@ -278,15 +311,18 @@ impl Printer {
|
|||
}
|
||||
let right = self.buf.push(BufEntry { token: Token::Begin(token), size: -self.right_total });
|
||||
self.scan_stack.push_back(right);
|
||||
BoxMarker
|
||||
}
|
||||
|
||||
fn scan_end(&mut self) {
|
||||
// This is is where `BoxMarker`s are consumed.
|
||||
fn scan_end(&mut self, b: BoxMarker) {
|
||||
if self.scan_stack.is_empty() {
|
||||
self.print_end();
|
||||
} else {
|
||||
let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
|
||||
self.scan_stack.push_back(right);
|
||||
}
|
||||
std::mem::forget(b)
|
||||
}
|
||||
|
||||
fn scan_break(&mut self, token: BreakToken) {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,27 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token};
|
||||
use crate::pp::{
|
||||
BeginToken, BoxMarker, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token,
|
||||
};
|
||||
|
||||
impl Printer {
|
||||
/// "raw box"
|
||||
pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
|
||||
pub fn rbox(&mut self, indent: isize, breaks: Breaks) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
|
||||
}
|
||||
|
||||
/// Inconsistent breaking box
|
||||
pub fn ibox(&mut self, indent: isize) {
|
||||
pub fn ibox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Inconsistent)
|
||||
}
|
||||
|
||||
/// Consistent breaking box
|
||||
pub fn cbox(&mut self, indent: isize) {
|
||||
pub fn cbox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Consistent)
|
||||
}
|
||||
|
||||
pub fn visual_align(&mut self) {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
|
||||
pub fn visual_align(&mut self) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent })
|
||||
}
|
||||
|
||||
pub fn break_offset(&mut self, n: usize, off: isize) {
|
||||
|
|
@ -30,8 +32,8 @@ impl Printer {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn end(&mut self) {
|
||||
self.scan_end()
|
||||
pub fn end(&mut self, b: BoxMarker) {
|
||||
self.scan_end(b)
|
||||
}
|
||||
|
||||
pub fn eof(mut self) -> String {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use rustc_span::symbol::IdentPrinter;
|
|||
use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym};
|
||||
|
||||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, Breaks};
|
||||
use crate::pp::{self, BoxMarker, Breaks};
|
||||
use crate::pprust::state::fixup::FixupContext;
|
||||
|
||||
pub enum MacHeader<'a> {
|
||||
|
|
@ -419,7 +419,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
{
|
||||
let mut it = elts.into_iter();
|
||||
|
||||
self.rbox(0, b);
|
||||
let rb = self.rbox(0, b);
|
||||
if let Some(first) = it.next() {
|
||||
op(self, first);
|
||||
for elt in it {
|
||||
|
|
@ -430,7 +430,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
op(self, elt);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(rb);
|
||||
}
|
||||
|
||||
fn commasep<'x, T: 'x, F, I>(&mut self, b: Breaks, elts: I, op: F)
|
||||
|
|
@ -461,7 +461,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.zerobreak();
|
||||
}
|
||||
if let Some((last, lines)) = cmnt.lines.split_last() {
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
|
||||
for line in lines {
|
||||
self.word(line.clone());
|
||||
|
|
@ -471,7 +471,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.word(last.clone());
|
||||
self.space();
|
||||
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
self.zerobreak()
|
||||
}
|
||||
|
|
@ -494,14 +494,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.word(line.clone());
|
||||
self.hardbreak()
|
||||
} else {
|
||||
self.visual_align();
|
||||
let vb = self.visual_align();
|
||||
for line in &cmnt.lines {
|
||||
if !line.is_empty() {
|
||||
self.word(line.clone());
|
||||
}
|
||||
self.hardbreak();
|
||||
}
|
||||
self.end();
|
||||
self.end(vb);
|
||||
}
|
||||
}
|
||||
CommentStyle::BlankLine => {
|
||||
|
|
@ -620,7 +620,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
|
||||
fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
match item.unsafety {
|
||||
ast::Safety::Unsafe(_) => {
|
||||
self.word("unsafe");
|
||||
|
|
@ -634,6 +634,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
false,
|
||||
None,
|
||||
*delim,
|
||||
None,
|
||||
tokens,
|
||||
true,
|
||||
span,
|
||||
|
|
@ -653,7 +654,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
ast::Safety::Unsafe(_) => self.pclose(),
|
||||
ast::Safety::Default | ast::Safety::Safe(_) => {}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
/// This doesn't deserve to be called "pretty" printing, but it should be
|
||||
|
|
@ -679,6 +680,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
false,
|
||||
None,
|
||||
*delim,
|
||||
Some(spacing.open),
|
||||
tts,
|
||||
convert_dollar_crate,
|
||||
dspan.entire(),
|
||||
|
|
@ -735,13 +737,12 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
has_bang: bool,
|
||||
ident: Option<Ident>,
|
||||
delim: Delimiter,
|
||||
open_spacing: Option<Spacing>,
|
||||
tts: &TokenStream,
|
||||
convert_dollar_crate: bool,
|
||||
span: Span,
|
||||
) {
|
||||
if delim == Delimiter::Brace {
|
||||
self.cbox(INDENT_UNIT);
|
||||
}
|
||||
let cb = (delim == Delimiter::Brace).then(|| self.cbox(INDENT_UNIT));
|
||||
match header {
|
||||
Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
|
||||
Some(MacHeader::Keyword(kw)) => self.word(kw),
|
||||
|
|
@ -760,21 +761,31 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
self.nbsp();
|
||||
}
|
||||
self.word("{");
|
||||
if !tts.is_empty() {
|
||||
|
||||
// Respect `Alone`, if provided, and print a space. Unless the list is empty.
|
||||
let open_space = (open_spacing == None || open_spacing == Some(Spacing::Alone))
|
||||
&& !tts.is_empty();
|
||||
if open_space {
|
||||
self.space();
|
||||
}
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_tts(tts, convert_dollar_crate);
|
||||
self.end();
|
||||
let empty = tts.is_empty();
|
||||
self.bclose(span, empty);
|
||||
self.end(ib);
|
||||
|
||||
// Use `open_space` for the spacing *before* the closing delim.
|
||||
// Because spacing on delimiters is lost when going through
|
||||
// proc macros, and otherwise we can end up with ugly cases
|
||||
// like `{ x}`. Symmetry is better.
|
||||
self.bclose(span, !open_space, cb.unwrap());
|
||||
}
|
||||
delim => {
|
||||
// `open_spacing` is ignored. We never print spaces after
|
||||
// non-brace opening delims or before non-brace closing delims.
|
||||
let token_str = self.token_kind_to_string(&delim.as_open_token_kind());
|
||||
self.word(token_str);
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_tts(tts, convert_dollar_crate);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
let token_str = self.token_kind_to_string(&delim.as_close_token_kind());
|
||||
self.word(token_str);
|
||||
}
|
||||
|
|
@ -799,6 +810,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
has_bang,
|
||||
Some(*ident),
|
||||
macro_def.body.delim,
|
||||
None,
|
||||
¯o_def.body.tokens,
|
||||
true,
|
||||
sp,
|
||||
|
|
@ -828,37 +840,38 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
}
|
||||
|
||||
fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
|
||||
fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) -> (BoxMarker, BoxMarker) {
|
||||
let w = w.into();
|
||||
// Outer-box is consistent.
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
// Head-box is inconsistent.
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
// Keyword that starts the head.
|
||||
if !w.is_empty() {
|
||||
self.word_nbsp(w);
|
||||
}
|
||||
(cb, ib)
|
||||
}
|
||||
|
||||
fn bopen(&mut self) {
|
||||
fn bopen(&mut self, ib: BoxMarker) {
|
||||
self.word("{");
|
||||
self.end(); // Close the head-box.
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
|
||||
fn bclose_maybe_open(&mut self, span: rustc_span::Span, no_space: bool, cb: Option<BoxMarker>) {
|
||||
let has_comment = self.maybe_print_comment(span.hi());
|
||||
if !empty || has_comment {
|
||||
if !no_space || has_comment {
|
||||
self.break_offset_if_not_bol(1, -INDENT_UNIT);
|
||||
}
|
||||
self.word("}");
|
||||
if close_box {
|
||||
self.end(); // Close the outer-box.
|
||||
if let Some(cb) = cb {
|
||||
self.end(cb);
|
||||
}
|
||||
}
|
||||
|
||||
fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
|
||||
let close_box = true;
|
||||
self.bclose_maybe_open(span, empty, close_box)
|
||||
fn bclose(&mut self, span: rustc_span::Span, no_space: bool, cb: BoxMarker) {
|
||||
let cb = Some(cb);
|
||||
self.bclose_maybe_open(span, no_space, cb)
|
||||
}
|
||||
|
||||
fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
|
||||
|
|
@ -1014,11 +1027,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
|
||||
fn block_to_string(&self, blk: &ast::Block) -> String {
|
||||
Self::to_string(|s| {
|
||||
// Containing cbox, will be closed by `print_block` at `}`.
|
||||
s.cbox(INDENT_UNIT);
|
||||
// Head-ibox, will be closed by `print_block` after `{`.
|
||||
s.ibox(0);
|
||||
s.print_block(blk)
|
||||
let (cb, ib) = s.head("");
|
||||
s.print_block(blk, cb, ib)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1090,7 +1100,7 @@ impl<'a> State<'a> {
|
|||
F: FnMut(&mut State<'_>, &T),
|
||||
G: FnMut(&T) -> rustc_span::Span,
|
||||
{
|
||||
self.rbox(0, b);
|
||||
let rb = self.rbox(0, b);
|
||||
let len = elts.len();
|
||||
let mut i = 0;
|
||||
for elt in elts {
|
||||
|
|
@ -1103,7 +1113,7 @@ impl<'a> State<'a> {
|
|||
self.space_if_not_bol();
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(rb);
|
||||
}
|
||||
|
||||
fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
|
||||
|
|
@ -1162,6 +1172,17 @@ impl<'a> State<'a> {
|
|||
self.print_expr_anon_const(end, &[]);
|
||||
}
|
||||
}
|
||||
rustc_ast::TyPatKind::Or(variants) => {
|
||||
let mut first = true;
|
||||
for pat in variants {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
self.word(" | ");
|
||||
}
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
}
|
||||
rustc_ast::TyPatKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
|
|
@ -1172,7 +1193,7 @@ impl<'a> State<'a> {
|
|||
|
||||
pub fn print_type(&mut self, ty: &ast::Ty) {
|
||||
self.maybe_print_comment(ty.span.lo());
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
match &ty.kind {
|
||||
ast::TyKind::Slice(ty) => {
|
||||
self.word("[");
|
||||
|
|
@ -1214,12 +1235,12 @@ impl<'a> State<'a> {
|
|||
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
|
||||
}
|
||||
ast::TyKind::UnsafeBinder(f) => {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(&f.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(&f.inner_ty);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
ast::TyKind::Path(None, path) => {
|
||||
self.print_path(path, false, 0);
|
||||
|
|
@ -1277,7 +1298,7 @@ impl<'a> State<'a> {
|
|||
self.print_ty_pat(pat);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_trait_ref(&mut self, t: &ast::TraitRef) {
|
||||
|
|
@ -1324,15 +1345,15 @@ impl<'a> State<'a> {
|
|||
ast::StmtKind::Let(loc) => {
|
||||
self.print_outer_attributes(&loc.attrs);
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib1 = self.ibox(INDENT_UNIT);
|
||||
if loc.super_.is_some() {
|
||||
self.word_nbsp("super");
|
||||
}
|
||||
self.word_nbsp("let");
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib2 = self.ibox(INDENT_UNIT);
|
||||
self.print_local_decl(loc);
|
||||
self.end();
|
||||
self.end(ib2);
|
||||
if let Some((init, els)) = loc.kind.init_else_opt() {
|
||||
self.nbsp();
|
||||
self.word_space("=");
|
||||
|
|
@ -1342,14 +1363,14 @@ impl<'a> State<'a> {
|
|||
FixupContext::default(),
|
||||
);
|
||||
if let Some(els) = els {
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word(" else ");
|
||||
self.print_block(els);
|
||||
self.print_block(els, cb, ib);
|
||||
}
|
||||
}
|
||||
self.word(";");
|
||||
self.end(); // `let` ibox
|
||||
self.end(ib1);
|
||||
}
|
||||
ast::StmtKind::Item(item) => self.print_item(item),
|
||||
ast::StmtKind::Expr(expr) => {
|
||||
|
|
@ -1380,23 +1401,30 @@ impl<'a> State<'a> {
|
|||
self.maybe_print_trailing_comment(st.span, None)
|
||||
}
|
||||
|
||||
fn print_block(&mut self, blk: &ast::Block) {
|
||||
self.print_block_with_attrs(blk, &[])
|
||||
fn print_block(&mut self, blk: &ast::Block, cb: BoxMarker, ib: BoxMarker) {
|
||||
self.print_block_with_attrs(blk, &[], cb, ib)
|
||||
}
|
||||
|
||||
fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
|
||||
self.print_block_maybe_unclosed(blk, &[], false)
|
||||
fn print_block_unclosed_indent(&mut self, blk: &ast::Block, ib: BoxMarker) {
|
||||
self.print_block_maybe_unclosed(blk, &[], None, ib)
|
||||
}
|
||||
|
||||
fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
|
||||
self.print_block_maybe_unclosed(blk, attrs, true)
|
||||
fn print_block_with_attrs(
|
||||
&mut self,
|
||||
blk: &ast::Block,
|
||||
attrs: &[ast::Attribute],
|
||||
cb: BoxMarker,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
self.print_block_maybe_unclosed(blk, attrs, Some(cb), ib)
|
||||
}
|
||||
|
||||
fn print_block_maybe_unclosed(
|
||||
&mut self,
|
||||
blk: &ast::Block,
|
||||
attrs: &[ast::Attribute],
|
||||
close_box: bool,
|
||||
cb: Option<BoxMarker>,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
match blk.rules {
|
||||
BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
|
||||
|
|
@ -1404,7 +1432,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.maybe_print_comment(blk.span.lo());
|
||||
self.ann.pre(self, AnnNode::Block(blk));
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
|
||||
let has_attrs = self.print_inner_attributes(attrs);
|
||||
|
||||
|
|
@ -1420,8 +1448,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let empty = !has_attrs && blk.stmts.is_empty();
|
||||
self.bclose_maybe_open(blk.span, empty, close_box);
|
||||
let no_space = !has_attrs && blk.stmts.is_empty();
|
||||
self.bclose_maybe_open(blk.span, no_space, cb);
|
||||
self.ann.post(self, AnnNode::Block(blk))
|
||||
}
|
||||
|
||||
|
|
@ -1468,6 +1496,7 @@ impl<'a> State<'a> {
|
|||
true,
|
||||
None,
|
||||
m.args.delim,
|
||||
None,
|
||||
&m.args.tokens,
|
||||
true,
|
||||
m.span(),
|
||||
|
|
@ -1556,8 +1585,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
InlineAsmOperand::Label { block } => {
|
||||
s.head("label");
|
||||
s.print_block(block);
|
||||
let (cb, ib) = s.head("label");
|
||||
s.print_block(block, cb, ib);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1671,13 +1700,13 @@ impl<'a> State<'a> {
|
|||
Consistent,
|
||||
fields,
|
||||
|s, f| {
|
||||
s.cbox(INDENT_UNIT);
|
||||
let cb = s.cbox(INDENT_UNIT);
|
||||
if !f.is_shorthand {
|
||||
s.print_ident(f.ident);
|
||||
s.word_nbsp(":");
|
||||
}
|
||||
s.print_pat(&f.pat);
|
||||
s.end();
|
||||
s.end(cb);
|
||||
},
|
||||
|f| f.pat.span,
|
||||
);
|
||||
|
|
@ -1928,7 +1957,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
|
||||
self.print_outer_attributes_inline(&input.attrs);
|
||||
|
||||
|
|
@ -1947,16 +1976,16 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
|
||||
if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word_space("->");
|
||||
self.print_type(ty);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.maybe_print_comment(ty.span.lo());
|
||||
}
|
||||
}
|
||||
|
|
@ -1969,12 +1998,12 @@ impl<'a> State<'a> {
|
|||
name: Option<Ident>,
|
||||
generic_params: &[ast::GenericParam],
|
||||
) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.print_formal_generic_params(generic_params);
|
||||
let generics = ast::Generics::default();
|
||||
let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
|
||||
self.print_fn(decl, header, name, &generics);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_fn_header_info(&mut self, header: ast::FnHeader) {
|
||||
|
|
@ -2052,7 +2081,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_meta_item(&mut self, item: &ast::MetaItem) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
match &item.kind {
|
||||
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
|
||||
ast::MetaItemKind::NameValue(value) => {
|
||||
|
|
@ -2068,7 +2097,7 @@ impl<'a> State<'a> {
|
|||
self.pclose();
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
pub(crate) fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_ast::{
|
|||
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::fixup::FixupContext;
|
||||
use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State};
|
||||
use crate::pprust::state::{AnnNode, BoxMarker, INDENT_UNIT, PrintState, State};
|
||||
|
||||
impl<'a> State<'a> {
|
||||
fn print_else(&mut self, els: Option<&ast::Expr>) {
|
||||
|
|
@ -21,20 +21,20 @@ impl<'a> State<'a> {
|
|||
match &_else.kind {
|
||||
// Another `else if` block.
|
||||
ast::ExprKind::If(i, then, e) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word(" else if ");
|
||||
self.print_expr_as_cond(i);
|
||||
self.space();
|
||||
self.print_block(then);
|
||||
self.print_block(then, cb, ib);
|
||||
self.print_else(e.as_deref())
|
||||
}
|
||||
// Final `else` block.
|
||||
ast::ExprKind::Block(b, None) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word(" else ");
|
||||
self.print_block(b)
|
||||
self.print_block(b, cb, ib)
|
||||
}
|
||||
// Constraints would be great here!
|
||||
_ => {
|
||||
|
|
@ -45,12 +45,12 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("if");
|
||||
self.print_expr_as_cond(test);
|
||||
self.space();
|
||||
self.print_block(blk);
|
||||
self.print_block(blk, cb, ib);
|
||||
self.print_else(elseopt)
|
||||
}
|
||||
|
||||
|
|
@ -112,11 +112,11 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.commasep_exprs(Inconsistent, exprs);
|
||||
self.word("]");
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
pub(super) fn print_expr_anon_const(
|
||||
|
|
@ -124,27 +124,27 @@ impl<'a> State<'a> {
|
|||
expr: &ast::AnonConst,
|
||||
attrs: &[ast::Attribute],
|
||||
) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("const");
|
||||
self.nbsp();
|
||||
if let ast::ExprKind::Block(block, None) = &expr.value.kind {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.print_block_with_attrs(block, attrs);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block_with_attrs(block, attrs, cb, ib);
|
||||
} else {
|
||||
self.print_expr(&expr.value, FixupContext::default());
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.print_expr(element, FixupContext::default());
|
||||
self.word_space(";");
|
||||
self.print_expr(&count.value, FixupContext::default());
|
||||
self.word("]");
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_expr_struct(
|
||||
|
|
@ -169,7 +169,7 @@ impl<'a> State<'a> {
|
|||
self.word("}");
|
||||
return;
|
||||
}
|
||||
self.cbox(0);
|
||||
let cb = self.cbox(0);
|
||||
for (pos, field) in fields.iter().with_position() {
|
||||
let is_first = matches!(pos, Position::First | Position::Only);
|
||||
let is_last = matches!(pos, Position::Last | Position::Only);
|
||||
|
|
@ -200,7 +200,7 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
}
|
||||
self.offset(-INDENT_UNIT);
|
||||
self.end();
|
||||
self.end(cb);
|
||||
self.word("}");
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +368,7 @@ impl<'a> State<'a> {
|
|||
self.print_outer_attributes(attrs);
|
||||
}
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
|
||||
// The Match subexpression in `match x {} - 1` must be parenthesized if
|
||||
// it is the leftmost subexpression in a statement:
|
||||
|
|
@ -440,14 +440,14 @@ impl<'a> State<'a> {
|
|||
ast::ExprKind::Type(expr, ty) => {
|
||||
self.word("builtin # type_ascribe");
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
|
||||
self.word(",");
|
||||
self.space_if_not_bol();
|
||||
self.print_type(ty);
|
||||
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::Let(pat, scrutinee, _, _) => {
|
||||
|
|
@ -459,20 +459,20 @@ impl<'a> State<'a> {
|
|||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("while");
|
||||
self.print_expr_as_cond(test);
|
||||
self.space();
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
self.print_block_with_attrs(blk, attrs, cb, ib);
|
||||
}
|
||||
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
|
||||
if let Some(label) = label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("for");
|
||||
if kind == &ForLoopKind::ForAwait {
|
||||
self.word_nbsp("await");
|
||||
|
|
@ -482,21 +482,21 @@ impl<'a> State<'a> {
|
|||
self.word_space("in");
|
||||
self.print_expr_as_cond(iter);
|
||||
self.space();
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
self.print_block_with_attrs(body, attrs, cb, ib);
|
||||
}
|
||||
ast::ExprKind::Loop(blk, opt_label, _) => {
|
||||
if let Some(label) = opt_label {
|
||||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("loop");
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
self.print_block_with_attrs(blk, attrs, cb, ib);
|
||||
}
|
||||
ast::ExprKind::Match(expr, arms, match_kind) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
|
||||
match match_kind {
|
||||
MatchKind::Prefix => {
|
||||
|
|
@ -514,13 +514,13 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_inner_attributes_no_trailing_hardbreak(attrs);
|
||||
for arm in arms {
|
||||
self.print_arm(arm);
|
||||
}
|
||||
let empty = attrs.is_empty() && arms.is_empty();
|
||||
self.bclose(expr.span, empty);
|
||||
self.bclose(expr.span, empty, cb);
|
||||
}
|
||||
ast::ExprKind::Closure(box ast::Closure {
|
||||
binder,
|
||||
|
|
@ -542,12 +542,15 @@ impl<'a> State<'a> {
|
|||
self.print_fn_params_and_ret(fn_decl, true);
|
||||
self.space();
|
||||
self.print_expr(body, FixupContext::default());
|
||||
self.end(); // need to close a box
|
||||
// FIXME(nnethercote): Bogus. Reduce visibility of `ended` once it's fixed.
|
||||
let fake_ib = BoxMarker;
|
||||
self.end(fake_ib);
|
||||
|
||||
// a box will be closed by print_expr, but we didn't want an overall
|
||||
// A box will be closed by print_expr, but we didn't want an overall
|
||||
// wrapper so we closed the corresponding opening. so create an
|
||||
// empty box to satisfy the close.
|
||||
self.ibox(0);
|
||||
// FIXME(nnethercote): Bogus.
|
||||
let _ib = self.ibox(0);
|
||||
}
|
||||
ast::ExprKind::Block(blk, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
|
|
@ -555,18 +558,18 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
}
|
||||
// containing cbox, will be closed by print-block at }
|
||||
self.cbox(0);
|
||||
let cb = self.cbox(0);
|
||||
// head-box, will be closed by print-block after {
|
||||
self.ibox(0);
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block_with_attrs(blk, attrs, cb, ib);
|
||||
}
|
||||
ast::ExprKind::Gen(capture_clause, blk, kind, _decl_span) => {
|
||||
self.word_nbsp(kind.modifier());
|
||||
self.print_capture_clause(*capture_clause);
|
||||
// cbox/ibox in analogy to the `ExprKind::Block` arm above
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.print_block_with_attrs(blk, attrs);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block_with_attrs(blk, attrs, cb, ib);
|
||||
}
|
||||
ast::ExprKind::Await(expr, _) => {
|
||||
self.print_expr_cond_paren(
|
||||
|
|
@ -728,19 +731,19 @@ impl<'a> State<'a> {
|
|||
// FIXME: Print `builtin # format_args` once macro `format_args` uses `builtin_syntax`.
|
||||
self.word("format_args!");
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word(reconstruct_format_args_template_string(&fmt.template));
|
||||
for arg in fmt.arguments.all_args() {
|
||||
self.word_space(",");
|
||||
self.print_expr(&arg.expr, FixupContext::default());
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::OffsetOf(container, fields) => {
|
||||
self.word("builtin # offset_of");
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_type(container);
|
||||
self.word(",");
|
||||
self.space();
|
||||
|
|
@ -753,7 +756,7 @@ impl<'a> State<'a> {
|
|||
self.print_ident(field);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::MacCall(m) => self.print_mac(m),
|
||||
|
|
@ -791,10 +794,10 @@ impl<'a> State<'a> {
|
|||
self.word("?")
|
||||
}
|
||||
ast::ExprKind::TryBlock(blk) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("try");
|
||||
self.print_block_with_attrs(blk, attrs)
|
||||
self.print_block_with_attrs(blk, attrs, cb, ib)
|
||||
}
|
||||
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
self.word("builtin # ");
|
||||
|
|
@ -803,7 +806,7 @@ impl<'a> State<'a> {
|
|||
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
|
||||
}
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
|
||||
if let Some(ty) = ty {
|
||||
|
|
@ -812,7 +815,7 @@ impl<'a> State<'a> {
|
|||
self.print_type(ty);
|
||||
}
|
||||
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::Err(_) => {
|
||||
|
|
@ -833,7 +836,7 @@ impl<'a> State<'a> {
|
|||
self.pclose();
|
||||
}
|
||||
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_arm(&mut self, arm: &ast::Arm) {
|
||||
|
|
@ -841,8 +844,8 @@ impl<'a> State<'a> {
|
|||
if arm.attrs.is_empty() {
|
||||
self.space();
|
||||
}
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
let ib = self.ibox(0);
|
||||
self.maybe_print_comment(arm.pat.span.lo());
|
||||
self.print_outer_attributes(&arm.attrs);
|
||||
self.print_pat(&arm.pat);
|
||||
|
|
@ -863,8 +866,7 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
}
|
||||
|
||||
// The block will close the pattern's ibox.
|
||||
self.print_block_unclosed_indent(blk);
|
||||
self.print_block_unclosed_indent(blk, ib);
|
||||
|
||||
// If it is a user-provided unsafe block, print a comma after it.
|
||||
if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
|
||||
|
|
@ -872,16 +874,16 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.end(ib);
|
||||
self.print_expr(body, FixupContext::new_match_arm());
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.end(); // Close the ibox for the pattern.
|
||||
self.end(ib);
|
||||
self.word(",");
|
||||
}
|
||||
self.end(); // Close enclosing cbox.
|
||||
self.end(cb);
|
||||
}
|
||||
|
||||
fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_ast::ModKind;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_span::Ident;
|
||||
|
||||
use crate::pp::BoxMarker;
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
use crate::pprust::state::fixup::FixupContext;
|
||||
use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State};
|
||||
|
|
@ -96,7 +97,7 @@ impl<'a> State<'a> {
|
|||
define_opaque: Option<&[(ast::NodeId, ast::Path)]>,
|
||||
) {
|
||||
self.print_define_opaques(define_opaque);
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_safety(safety);
|
||||
self.print_defaultness(defaultness);
|
||||
|
|
@ -113,14 +114,14 @@ impl<'a> State<'a> {
|
|||
if body.is_some() {
|
||||
self.space();
|
||||
}
|
||||
self.end(); // end the head-ibox
|
||||
self.end(ib);
|
||||
if let Some(body) = body {
|
||||
self.word_space("=");
|
||||
self.print_expr(body, FixupContext::default());
|
||||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
self.end(cb);
|
||||
}
|
||||
|
||||
fn print_associated_type(
|
||||
|
|
@ -135,7 +136,7 @@ impl<'a> State<'a> {
|
|||
) {
|
||||
let (before_predicates, after_predicates) =
|
||||
generics.where_clause.predicates.split_at(where_clauses.split);
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_defaultness(defaultness);
|
||||
self.word_space("type");
|
||||
|
|
@ -153,8 +154,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
|
||||
/// Pretty-prints an item.
|
||||
|
|
@ -165,7 +166,7 @@ impl<'a> State<'a> {
|
|||
self.ann.pre(self, AnnNode::Item(item));
|
||||
match &item.kind {
|
||||
ast::ItemKind::ExternCrate(orig_name, ident) => {
|
||||
self.head(visibility_qualified(&item.vis, "extern crate"));
|
||||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "extern crate"));
|
||||
if let &Some(orig_name) = orig_name {
|
||||
self.print_name(orig_name);
|
||||
self.space();
|
||||
|
|
@ -174,8 +175,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_ident(*ident);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
ast::ItemKind::Use(tree) => {
|
||||
self.print_visibility(&item.vis);
|
||||
|
|
@ -228,7 +229,7 @@ impl<'a> State<'a> {
|
|||
self.print_fn_full(&item.vis, &item.attrs, &*func);
|
||||
}
|
||||
ast::ItemKind::Mod(safety, ident, mod_kind) => {
|
||||
self.head(Self::to_string(|s| {
|
||||
let (cb, ib) = self.head(Self::to_string(|s| {
|
||||
s.print_visibility(&item.vis);
|
||||
s.print_safety(*safety);
|
||||
s.word("mod");
|
||||
|
|
@ -238,23 +239,23 @@ impl<'a> State<'a> {
|
|||
match mod_kind {
|
||||
ModKind::Loaded(items, ..) => {
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_inner_attributes(&item.attrs);
|
||||
for item in items {
|
||||
self.print_item(item);
|
||||
}
|
||||
let empty = item.attrs.is_empty() && items.is_empty();
|
||||
self.bclose(item.span, empty);
|
||||
self.bclose(item.span, empty, cb);
|
||||
}
|
||||
ModKind::Unloaded => {
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ItemKind::ForeignMod(nmod) => {
|
||||
self.head(Self::to_string(|s| {
|
||||
let (cb, ib) = self.head(Self::to_string(|s| {
|
||||
s.print_safety(nmod.safety);
|
||||
s.word("extern");
|
||||
}));
|
||||
|
|
@ -262,18 +263,18 @@ impl<'a> State<'a> {
|
|||
self.print_token_literal(abi.as_token_lit(), abi.span);
|
||||
self.nbsp();
|
||||
}
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_foreign_mod(nmod, &item.attrs);
|
||||
let empty = item.attrs.is_empty() && nmod.items.is_empty();
|
||||
self.bclose(item.span, empty);
|
||||
self.bclose(item.span, empty, cb);
|
||||
}
|
||||
ast::ItemKind::GlobalAsm(asm) => {
|
||||
// FIXME: Print `builtin # global_asm` once macro `global_asm` uses `builtin_syntax`.
|
||||
self.head(visibility_qualified(&item.vis, "global_asm!"));
|
||||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "global_asm!"));
|
||||
self.print_inline_asm(asm);
|
||||
self.word(";");
|
||||
self.end();
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
ast::ItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
|
|
@ -297,12 +298,12 @@ impl<'a> State<'a> {
|
|||
self.print_enum_def(enum_definition, params, *ident, item.span, &item.vis);
|
||||
}
|
||||
ast::ItemKind::Struct(ident, struct_def, generics) => {
|
||||
self.head(visibility_qualified(&item.vis, "struct"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true);
|
||||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "struct"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
|
||||
}
|
||||
ast::ItemKind::Union(ident, struct_def, generics) => {
|
||||
self.head(visibility_qualified(&item.vis, "union"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true);
|
||||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
|
||||
}
|
||||
ast::ItemKind::Impl(box ast::Impl {
|
||||
safety,
|
||||
|
|
@ -314,7 +315,7 @@ impl<'a> State<'a> {
|
|||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
self.print_defaultness(*defaultness);
|
||||
self.print_safety(*safety);
|
||||
|
|
@ -343,13 +344,13 @@ impl<'a> State<'a> {
|
|||
self.print_where_clause(&generics.where_clause);
|
||||
|
||||
self.space();
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_inner_attributes(&item.attrs);
|
||||
for impl_item in items {
|
||||
self.print_assoc_item(impl_item);
|
||||
}
|
||||
let empty = item.attrs.is_empty() && items.is_empty();
|
||||
self.bclose(item.span, empty);
|
||||
self.bclose(item.span, empty, cb);
|
||||
}
|
||||
ast::ItemKind::Trait(box ast::Trait {
|
||||
safety,
|
||||
|
|
@ -359,7 +360,7 @@ impl<'a> State<'a> {
|
|||
bounds,
|
||||
items,
|
||||
}) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
self.print_safety(*safety);
|
||||
self.print_is_auto(*is_auto);
|
||||
|
|
@ -372,16 +373,16 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(" ");
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_inner_attributes(&item.attrs);
|
||||
for trait_item in items {
|
||||
self.print_assoc_item(trait_item);
|
||||
}
|
||||
let empty = item.attrs.is_empty() && items.is_empty();
|
||||
self.bclose(item.span, empty);
|
||||
self.bclose(item.span, empty, cb);
|
||||
}
|
||||
ast::ItemKind::TraitAlias(ident, generics, bounds) => {
|
||||
self.head(visibility_qualified(&item.vis, "trait"));
|
||||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "trait"));
|
||||
self.print_ident(*ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
self.nbsp();
|
||||
|
|
@ -391,8 +392,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
ast::ItemKind::MacCall(mac) => {
|
||||
self.print_mac(mac);
|
||||
|
|
@ -433,28 +434,24 @@ impl<'a> State<'a> {
|
|||
span: rustc_span::Span,
|
||||
visibility: &ast::Visibility,
|
||||
) {
|
||||
self.head(visibility_qualified(visibility, "enum"));
|
||||
let (cb, ib) = self.head(visibility_qualified(visibility, "enum"));
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.space();
|
||||
self.print_variants(&enum_definition.variants, span)
|
||||
}
|
||||
|
||||
fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
|
||||
self.bopen();
|
||||
for v in variants {
|
||||
self.bopen(ib);
|
||||
for v in enum_definition.variants.iter() {
|
||||
self.space_if_not_bol();
|
||||
self.maybe_print_comment(v.span.lo());
|
||||
self.print_outer_attributes(&v.attrs);
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_variant(v);
|
||||
self.word(",");
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.maybe_print_trailing_comment(v.span, None);
|
||||
}
|
||||
let empty = variants.is_empty();
|
||||
self.bclose(span, empty)
|
||||
let empty = enum_definition.variants.is_empty();
|
||||
self.bclose(span, empty, cb)
|
||||
}
|
||||
|
||||
pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
|
||||
|
|
@ -478,33 +475,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_record_struct_body(
|
||||
&mut self,
|
||||
fields: &[ast::FieldDef],
|
||||
span: rustc_span::Span,
|
||||
) {
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
|
||||
let empty = fields.is_empty();
|
||||
if !empty {
|
||||
self.hardbreak_if_not_bol();
|
||||
|
||||
for field in fields {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(field.span.lo());
|
||||
self.print_outer_attributes(&field.attrs);
|
||||
self.print_visibility(&field.vis);
|
||||
self.print_ident(field.ident.unwrap());
|
||||
self.word_nbsp(":");
|
||||
self.print_type(&field.ty);
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
||||
self.bclose(span, empty);
|
||||
}
|
||||
|
||||
fn print_struct(
|
||||
&mut self,
|
||||
struct_def: &ast::VariantData,
|
||||
|
|
@ -512,6 +482,8 @@ impl<'a> State<'a> {
|
|||
ident: Ident,
|
||||
span: rustc_span::Span,
|
||||
print_finalizer: bool,
|
||||
cb: BoxMarker,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
|
|
@ -531,21 +503,40 @@ impl<'a> State<'a> {
|
|||
if print_finalizer {
|
||||
self.word(";");
|
||||
}
|
||||
self.end();
|
||||
self.end(); // Close the outer-box.
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
ast::VariantData::Struct { fields, .. } => {
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.print_record_struct_body(fields, span);
|
||||
self.nbsp();
|
||||
self.bopen(ib);
|
||||
|
||||
let empty = fields.is_empty();
|
||||
if !empty {
|
||||
self.hardbreak_if_not_bol();
|
||||
|
||||
for field in fields {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(field.span.lo());
|
||||
self.print_outer_attributes(&field.attrs);
|
||||
self.print_visibility(&field.vis);
|
||||
self.print_ident(field.ident.unwrap());
|
||||
self.word_nbsp(":");
|
||||
self.print_type(&field.ty);
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
|
||||
self.bclose(span, empty, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_variant(&mut self, v: &ast::Variant) {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&v.vis);
|
||||
let generics = ast::Generics::default();
|
||||
self.print_struct(&v.data, &generics, v.ident, v.span, false);
|
||||
self.print_struct(&v.data, &generics, v.ident, v.span, false, cb, ib);
|
||||
if let Some(d) = &v.disr_expr {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
|
|
@ -636,9 +627,7 @@ impl<'a> State<'a> {
|
|||
kind: DelegationKind<'_>,
|
||||
body: &Option<P<ast::Block>>,
|
||||
) {
|
||||
if body.is_some() {
|
||||
self.head("");
|
||||
}
|
||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||
self.print_visibility(vis);
|
||||
self.word_nbsp("reuse");
|
||||
|
||||
|
|
@ -670,9 +659,9 @@ impl<'a> State<'a> {
|
|||
self.word("*");
|
||||
}
|
||||
}
|
||||
if let Some(body) = body {
|
||||
if let Some((body, (cb, ib))) = body_cb_ib {
|
||||
self.nbsp();
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
self.print_block_with_attrs(body, attrs, cb, ib);
|
||||
} else {
|
||||
self.word(";");
|
||||
}
|
||||
|
|
@ -683,9 +672,8 @@ impl<'a> State<'a> {
|
|||
|
||||
self.print_define_opaques(define_opaque.as_deref());
|
||||
|
||||
if body.is_some() {
|
||||
self.head("");
|
||||
}
|
||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||
|
||||
self.print_visibility(vis);
|
||||
self.print_defaultness(*defaultness);
|
||||
self.print_fn(&sig.decl, sig.header, Some(*ident), generics);
|
||||
|
|
@ -693,9 +681,9 @@ impl<'a> State<'a> {
|
|||
self.nbsp();
|
||||
self.print_contract(contract);
|
||||
}
|
||||
if let Some(body) = body {
|
||||
if let Some((body, (cb, ib))) = body_cb_ib {
|
||||
self.nbsp();
|
||||
self.print_block_with_attrs(body, attrs);
|
||||
self.print_block_with_attrs(body, attrs, cb, ib);
|
||||
} else {
|
||||
self.word(";");
|
||||
}
|
||||
|
|
@ -851,10 +839,10 @@ impl<'a> State<'a> {
|
|||
} else if let [(item, _)] = items.as_slice() {
|
||||
self.print_use_tree(item);
|
||||
} else {
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
self.word("{");
|
||||
self.zerobreak();
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
for (pos, use_tree) in items.iter().with_position() {
|
||||
let is_last = matches!(pos, Position::Last | Position::Only);
|
||||
self.print_use_tree(&use_tree.0);
|
||||
|
|
@ -867,11 +855,11 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.trailing_comma();
|
||||
self.offset(-INDENT_UNIT);
|
||||
self.word("}");
|
||||
self.end();
|
||||
self.end(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ fn fun_to_string(
|
|||
generics: &ast::Generics,
|
||||
) -> String {
|
||||
to_string(|s| {
|
||||
s.head("");
|
||||
let (cb, ib) = s.head("");
|
||||
s.print_fn(decl, header, Some(ident), generics);
|
||||
s.end(); // Close the head box.
|
||||
s.end(); // Close the outer box.
|
||||
s.end(ib);
|
||||
s.end(cb);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
#![cfg_attr(bootstrap, feature(let_chains))]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -795,7 +795,14 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
|
|||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.consume_operand(loc, (discr, span), state);
|
||||
}
|
||||
TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
|
||||
TerminatorKind::Drop {
|
||||
place,
|
||||
target: _,
|
||||
unwind: _,
|
||||
replace,
|
||||
drop: _,
|
||||
async_fut: _,
|
||||
} => {
|
||||
debug!(
|
||||
"visit_terminator_drop \
|
||||
loc: {:?} term: {:?} place: {:?} span: {:?}",
|
||||
|
|
|
|||
|
|
@ -101,7 +101,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.consume_operand(location, discr);
|
||||
}
|
||||
TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
|
||||
TerminatorKind::Drop {
|
||||
place: drop_place,
|
||||
target: _,
|
||||
unwind: _,
|
||||
replace,
|
||||
drop: _,
|
||||
async_fut: _,
|
||||
} => {
|
||||
let write_kind =
|
||||
if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
|
||||
self.access_place(
|
||||
|
|
|
|||
|
|
@ -2079,8 +2079,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::Drop { target, unwind, .. }
|
||||
| TerminatorKind::Assert { target, unwind, .. } => {
|
||||
TerminatorKind::Drop { target, unwind, drop, .. } => {
|
||||
self.assert_iscleanup(block_data, target, is_cleanup);
|
||||
self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
|
||||
if let Some(drop) = drop {
|
||||
self.assert_iscleanup(block_data, drop, is_cleanup);
|
||||
}
|
||||
}
|
||||
TerminatorKind::Assert { target, unwind, .. } => {
|
||||
self.assert_iscleanup(block_data, target, is_cleanup);
|
||||
self.assert_iscleanup_unwind(block_data, unwind, is_cleanup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,9 +323,9 @@ mod llvm_enzyme {
|
|||
Spacing::Joint,
|
||||
)];
|
||||
let never_arg = ast::DelimArgs {
|
||||
dspan: ast::tokenstream::DelimSpan::from_single(span),
|
||||
dspan: DelimSpan::from_single(span),
|
||||
delim: ast::token::Delimiter::Parenthesis,
|
||||
tokens: ast::tokenstream::TokenStream::from_iter(ts2),
|
||||
tokens: TokenStream::from_iter(ts2),
|
||||
};
|
||||
let inline_item = ast::AttrItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#![feature(rustdoc_internals)]
|
||||
#![feature(string_from_utf8_lossy_owned)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate proc_macro;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast};
|
||||
use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub(crate) fn expand<'cx>(
|
||||
|
|
@ -26,19 +27,42 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
|
|||
|
||||
let ty = parser.parse_ty()?;
|
||||
parser.expect_keyword(exp!(Is))?;
|
||||
let pat = parser.parse_pat_no_top_alt(None, None)?.into_inner();
|
||||
|
||||
let pat = pat_to_ty_pat(
|
||||
cx,
|
||||
parser
|
||||
.parse_pat_no_top_guard(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
)?
|
||||
.into_inner(),
|
||||
);
|
||||
|
||||
if parser.token != token::Eof {
|
||||
parser.unexpected()?;
|
||||
}
|
||||
|
||||
Ok((ty, pat))
|
||||
}
|
||||
|
||||
fn ty_pat(kind: TyPatKind, span: Span) -> P<TyPat> {
|
||||
P(TyPat { id: DUMMY_NODE_ID, kind, span, tokens: None })
|
||||
}
|
||||
|
||||
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P<TyPat> {
|
||||
let kind = match pat.kind {
|
||||
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
|
||||
start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
|
||||
end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
|
||||
include_end,
|
||||
),
|
||||
ast::PatKind::Or(variants) => TyPatKind::Or(
|
||||
variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(),
|
||||
),
|
||||
ast::PatKind::Err(guar) => TyPatKind::Err(guar),
|
||||
_ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")),
|
||||
};
|
||||
|
||||
let pat = P(TyPat { id: pat.id, kind, span: pat.span, tokens: pat.tokens });
|
||||
|
||||
Ok((ty, pat))
|
||||
ty_pat(kind, pat.span)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,7 +441,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
Err(instance) => Some(instance),
|
||||
}
|
||||
}
|
||||
InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => {
|
||||
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
|
||||
// it is `func returning noop future`
|
||||
InstanceKind::DropGlue(_, None) => {
|
||||
// empty drop glue - a nop.
|
||||
let dest = target.expect("Non terminating drop_in_place_real???");
|
||||
let ret_block = fx.get_block(dest);
|
||||
|
|
@ -707,9 +709,8 @@ pub(crate) fn codegen_drop<'tcx>(
|
|||
let ty = drop_place.layout().ty;
|
||||
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty);
|
||||
|
||||
if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) =
|
||||
drop_instance.def
|
||||
{
|
||||
// AsyncDropGlueCtorShim can't be here
|
||||
if let ty::InstanceKind::DropGlue(_, None) = drop_instance.def {
|
||||
// we don't actually need to drop anything
|
||||
} else {
|
||||
match ty.kind() {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ 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;
|
||||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
||||
|
|
@ -18,7 +16,6 @@ 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;
|
||||
|
||||
|
|
@ -37,7 +34,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
cached_func: Function,
|
||||
module: &mut dyn Module,
|
||||
instance: Instance<'tcx>,
|
||||
) -> Option<CodegenedFunction> {
|
||||
) -> CodegenedFunction {
|
||||
debug_assert!(!instance.args.has_infer());
|
||||
|
||||
let symbol_name = tcx.symbol_name(instance).name.to_string();
|
||||
|
|
@ -54,38 +51,6 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
String::from_utf8_lossy(&buf).into_owned()
|
||||
});
|
||||
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
assert_eq!(mir.basic_blocks.len(), 1);
|
||||
assert!(mir.basic_blocks[START_BLOCK].statements.is_empty());
|
||||
|
||||
match &mir.basic_blocks[START_BLOCK].terminator().kind {
|
||||
TerminatorKind::InlineAsm {
|
||||
asm_macro: InlineAsmMacro::NakedAsm,
|
||||
template,
|
||||
operands,
|
||||
options,
|
||||
line_spans: _,
|
||||
targets: _,
|
||||
unwind: _,
|
||||
} => {
|
||||
codegen_naked_asm(
|
||||
tcx,
|
||||
cx,
|
||||
module,
|
||||
instance,
|
||||
mir.basic_blocks[START_BLOCK].terminator().source_info.span,
|
||||
&symbol_name,
|
||||
template,
|
||||
operands,
|
||||
*options,
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
// Declare function
|
||||
let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
|
||||
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
|
||||
|
|
@ -166,7 +131,7 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
// Verify function
|
||||
verify_func(tcx, &clif_comments, &func);
|
||||
|
||||
Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx })
|
||||
CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }
|
||||
}
|
||||
|
||||
pub(crate) fn compile_fn(
|
||||
|
|
@ -565,7 +530,11 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
| TerminatorKind::CoroutineDrop => {
|
||||
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
|
||||
}
|
||||
TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
|
||||
TerminatorKind::Drop { place, target, unwind: _, replace: _, drop, async_fut } => {
|
||||
assert!(
|
||||
async_fut.is_none() && drop.is_none(),
|
||||
"Async Drop must be expanded or reset to sync before codegen"
|
||||
);
|
||||
let drop_place = codegen_place(fx, *place);
|
||||
crate::abi::codegen_drop(fx, source_info, drop_place, *target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
|||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::mono::{
|
||||
CodegenUnit, Linkage as RLinkage, MonoItem, MonoItemData, Visibility,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType};
|
||||
|
||||
|
|
@ -30,7 +33,7 @@ use crate::CodegenCx;
|
|||
use crate::base::CodegenedFunction;
|
||||
use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken};
|
||||
use crate::debuginfo::TypeDebugContext;
|
||||
use crate::global_asm::GlobalAsmConfig;
|
||||
use crate::global_asm::{GlobalAsmConfig, GlobalAsmContext};
|
||||
use crate::prelude::*;
|
||||
use crate::unwind_module::UnwindModule;
|
||||
|
||||
|
|
@ -530,19 +533,35 @@ fn codegen_cgu_content(
|
|||
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 {
|
||||
for (mono_item, item_data) in mono_items {
|
||||
match mono_item {
|
||||
MonoItem::Fn(inst) => {
|
||||
if let Some(codegened_function) = crate::base::codegen_fn(
|
||||
MonoItem::Fn(instance) => {
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED)
|
||||
{
|
||||
rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm(
|
||||
&mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
|
||||
instance,
|
||||
MonoItemData {
|
||||
linkage: RLinkage::External,
|
||||
visibility: if item_data.linkage == RLinkage::Internal {
|
||||
Visibility::Hidden
|
||||
} else {
|
||||
item_data.visibility
|
||||
},
|
||||
..item_data
|
||||
},
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let codegened_function = crate::base::codegen_fn(
|
||||
tcx,
|
||||
&mut cx,
|
||||
&mut type_dbg,
|
||||
Function::new(),
|
||||
module,
|
||||
inst,
|
||||
) {
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
instance,
|
||||
);
|
||||
codegened_functions.push(codegened_function);
|
||||
}
|
||||
MonoItem::Static(def_id) => {
|
||||
let data_id = crate::constant::codegen_static(tcx, module, def_id);
|
||||
|
|
@ -551,7 +570,10 @@ fn codegen_cgu_content(
|
|||
}
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
crate::global_asm::codegen_global_asm_item(tcx, &mut cx.global_asm, item_id);
|
||||
rustc_codegen_ssa::base::codegen_global_asm(
|
||||
&mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm },
|
||||
item_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,11 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
module: &mut dyn Module,
|
||||
instance: Instance<'tcx>,
|
||||
) {
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
tcx.dcx()
|
||||
.span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode");
|
||||
}
|
||||
|
||||
cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
|
||||
tcx.prof.clone(),
|
||||
)));
|
||||
|
|
@ -135,16 +140,15 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
|
|||
crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
|
||||
|
||||
let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
|
||||
if let Some(codegened_func) = crate::base::codegen_fn(
|
||||
let codegened_func = crate::base::codegen_fn(
|
||||
tcx,
|
||||
cx,
|
||||
&mut TypeDebugContext::default(),
|
||||
cached_func,
|
||||
module,
|
||||
instance,
|
||||
) {
|
||||
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
||||
}
|
||||
);
|
||||
crate::base::compile_fn(cx, &tcx.prof, cached_context, module, codegened_func);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,102 +7,139 @@ use std::process::{Command, Stdio};
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::{InlineAsmOperand, ItemId};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_codegen_ssa::traits::{AsmCodegenMethods, GlobalAsmOperandRef};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
|
||||
};
|
||||
use rustc_session::config::{OutputFilenames, OutputType};
|
||||
use rustc_target::asm::InlineAsmArch;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
||||
let item = tcx.hir_item(item_id);
|
||||
if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
|
||||
let is_x86 =
|
||||
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
||||
pub(crate) struct GlobalAsmContext<'a, 'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
pub global_asm: &'a mut String,
|
||||
}
|
||||
|
||||
if is_x86 {
|
||||
if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
global_asm.push_str("\n.intel_syntax noprefix\n");
|
||||
} else {
|
||||
global_asm.push_str("\n.att_syntax\n");
|
||||
}
|
||||
impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&mut self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
_line_spans: &[Span],
|
||||
) {
|
||||
codegen_global_asm_inner(self.tcx, self.global_asm, template, operands, options);
|
||||
}
|
||||
|
||||
fn mangled_name(&self, instance: Instance<'tcx>) -> String {
|
||||
let symbol_name = self.tcx.symbol_name(instance).name.to_owned();
|
||||
if self.tcx.sess.target.is_like_darwin { format!("_{symbol_name}") } else { symbol_name }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
self.tcx.sess.dcx().span_fatal(span, err.to_string())
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.dcx()
|
||||
.span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err))
|
||||
}
|
||||
for piece in asm.template {
|
||||
match *piece {
|
||||
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
|
||||
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => {
|
||||
match asm.operands[operand_idx].0 {
|
||||
InlineAsmOperand::Const { ref anon_const } => {
|
||||
match tcx.const_eval_poly(anon_const.def_id.to_def_id()) {
|
||||
Ok(const_value) => {
|
||||
let ty = tcx
|
||||
.typeck_body(anon_const.body)
|
||||
.node_type(anon_const.hir_id);
|
||||
let string = rustc_codegen_ssa::common::asm_const_to_str(
|
||||
tcx,
|
||||
op_sp,
|
||||
const_value,
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(ty),
|
||||
);
|
||||
global_asm.push_str(&string);
|
||||
}
|
||||
Err(ErrorHandled::Reported { .. }) => {
|
||||
// An error has already been reported and compilation is
|
||||
// guaranteed to fail if execution hits this path.
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
span_bug!(op_sp, "asm const cannot be resolved; too generic");
|
||||
}
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SymFn { expr } => {
|
||||
if cfg!(not(feature = "inline_asm_sym")) {
|
||||
tcx.dcx().span_err(
|
||||
item.span,
|
||||
"asm! and global_asm! sym operands are not yet supported",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
|
||||
let instance = match ty.kind() {
|
||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||
_ => span_bug!(op_sp, "asm sym is not a function"),
|
||||
};
|
||||
let symbol = tcx.symbol_name(instance);
|
||||
// FIXME handle the case where the function was made private to the
|
||||
// current codegen unit
|
||||
global_asm.push_str(symbol.name);
|
||||
}
|
||||
InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||
if cfg!(not(feature = "inline_asm_sym")) {
|
||||
tcx.dcx().span_err(
|
||||
item.span,
|
||||
"asm! and global_asm! sym operands are not yet supported",
|
||||
);
|
||||
}
|
||||
impl<'tcx> FnAbiOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_fn_abi_err(
|
||||
&self,
|
||||
err: FnAbiError<'tcx>,
|
||||
span: Span,
|
||||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
FullyMonomorphizedLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
|
||||
}
|
||||
}
|
||||
|
||||
let instance = Instance::mono(tcx, def_id);
|
||||
let symbol = tcx.symbol_name(instance);
|
||||
global_asm.push_str(symbol.name);
|
||||
impl<'tcx> HasTyCtxt<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_abi::HasDataLayout for GlobalAsmContext<'_, 'tcx> {
|
||||
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||
&self.tcx.data_layout
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTypingEnv<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||
ty::TypingEnv::fully_monomorphized()
|
||||
}
|
||||
}
|
||||
|
||||
fn codegen_global_asm_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
global_asm: &mut String,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
) {
|
||||
let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
||||
|
||||
if is_x86 {
|
||||
if !options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
global_asm.push_str("\n.intel_syntax noprefix\n");
|
||||
} else {
|
||||
global_asm.push_str("\n.att_syntax\n");
|
||||
}
|
||||
}
|
||||
for piece in template {
|
||||
match *piece {
|
||||
InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
|
||||
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span } => {
|
||||
match operands[operand_idx] {
|
||||
GlobalAsmOperandRef::Const { ref string } => {
|
||||
global_asm.push_str(string);
|
||||
}
|
||||
GlobalAsmOperandRef::SymFn { instance } => {
|
||||
if cfg!(not(feature = "inline_asm_sym")) {
|
||||
tcx.dcx().span_err(
|
||||
span,
|
||||
"asm! and global_asm! sym operands are not yet supported",
|
||||
);
|
||||
}
|
||||
InlineAsmOperand::In { .. }
|
||||
| InlineAsmOperand::Out { .. }
|
||||
| InlineAsmOperand::InOut { .. }
|
||||
| InlineAsmOperand::SplitInOut { .. }
|
||||
| InlineAsmOperand::Label { .. } => {
|
||||
span_bug!(op_sp, "invalid operand type for global_asm!")
|
||||
|
||||
let symbol = tcx.symbol_name(instance);
|
||||
// FIXME handle the case where the function was made private to the
|
||||
// current codegen unit
|
||||
global_asm.push_str(symbol.name);
|
||||
}
|
||||
GlobalAsmOperandRef::SymStatic { def_id } => {
|
||||
if cfg!(not(feature = "inline_asm_sym")) {
|
||||
tcx.dcx().span_err(
|
||||
span,
|
||||
"asm! and global_asm! sym operands are not yet supported",
|
||||
);
|
||||
}
|
||||
|
||||
let instance = Instance::mono(tcx, def_id);
|
||||
let symbol = tcx.symbol_name(instance);
|
||||
global_asm.push_str(symbol.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global_asm.push('\n');
|
||||
if is_x86 {
|
||||
global_asm.push_str(".att_syntax\n\n");
|
||||
}
|
||||
} else {
|
||||
bug!("Expected GlobalAsm found {:?}", item);
|
||||
global_asm.push('\n');
|
||||
if is_x86 {
|
||||
global_asm.push_str(".att_syntax\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||
stack_slots_input: Vec::new(),
|
||||
stack_slots_output: Vec::new(),
|
||||
stack_slot_size: Size::from_bytes(0),
|
||||
is_naked: false,
|
||||
};
|
||||
asm_gen.allocate_registers();
|
||||
asm_gen.allocate_stack_slots();
|
||||
|
|
@ -201,114 +200,6 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
|||
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_naked_asm<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cx: &mut crate::CodegenCx,
|
||||
module: &mut dyn Module,
|
||||
instance: Instance<'tcx>,
|
||||
span: Span,
|
||||
symbol_name: &str,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[InlineAsmOperand<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
) {
|
||||
// FIXME add .eh_frame unwind info directives
|
||||
|
||||
let operands = operands
|
||||
.iter()
|
||||
.map(|operand| match *operand {
|
||||
InlineAsmOperand::In { .. }
|
||||
| InlineAsmOperand::Out { .. }
|
||||
| InlineAsmOperand::InOut { .. } => {
|
||||
span_bug!(span, "invalid operand type for naked asm")
|
||||
}
|
||||
InlineAsmOperand::Const { ref value } => {
|
||||
let cv = instance.instantiate_mir_and_normalize_erasing_regions(
|
||||
tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
ty::EarlyBinder::bind(value.const_),
|
||||
);
|
||||
let const_value = cv
|
||||
.eval(tcx, ty::TypingEnv::fully_monomorphized(), value.span)
|
||||
.expect("erroneous constant missed by mono item collection");
|
||||
|
||||
let value = rustc_codegen_ssa::common::asm_const_to_str(
|
||||
tcx,
|
||||
span,
|
||||
const_value,
|
||||
FullyMonomorphizedLayoutCx(tcx).layout_of(cv.ty()),
|
||||
);
|
||||
CInlineAsmOperand::Const { value }
|
||||
}
|
||||
InlineAsmOperand::SymFn { ref value } => {
|
||||
if cfg!(not(feature = "inline_asm_sym")) {
|
||||
tcx.dcx()
|
||||
.span_err(span, "asm! and global_asm! sym operands are not yet supported");
|
||||
}
|
||||
|
||||
let const_ = instance.instantiate_mir_and_normalize_erasing_regions(
|
||||
tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
ty::EarlyBinder::bind(value.const_),
|
||||
);
|
||||
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||
tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
def_id,
|
||||
args,
|
||||
)
|
||||
.unwrap();
|
||||
let symbol = tcx.symbol_name(instance);
|
||||
|
||||
// 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 wrapper_name = format!(
|
||||
"__inline_asm_{}_wrapper_n{}",
|
||||
cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
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);
|
||||
|
||||
CInlineAsmOperand::Symbol { symbol: wrapper_name }
|
||||
} else {
|
||||
span_bug!(span, "invalid type for asm sym (fn)");
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::SymStatic { def_id } => {
|
||||
assert!(tcx.is_static(def_id));
|
||||
let instance = Instance::mono(tcx, def_id);
|
||||
CInlineAsmOperand::Symbol { symbol: tcx.symbol_name(instance).name.to_owned() }
|
||||
}
|
||||
InlineAsmOperand::Label { .. } => {
|
||||
span_bug!(span, "asm! label operands are not yet supported");
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let asm_gen = InlineAssemblyGenerator {
|
||||
tcx,
|
||||
arch: tcx.sess.asm_arch.unwrap(),
|
||||
enclosing_def_id: instance.def_id(),
|
||||
template,
|
||||
operands: &operands,
|
||||
options,
|
||||
registers: Vec::new(),
|
||||
stack_slots_clobber: Vec::new(),
|
||||
stack_slots_input: Vec::new(),
|
||||
stack_slots_output: Vec::new(),
|
||||
stack_slot_size: Size::from_bytes(0),
|
||||
is_naked: true,
|
||||
};
|
||||
|
||||
let generated_asm = asm_gen.generate_asm_wrapper(symbol_name);
|
||||
cx.global_asm.push_str(&generated_asm);
|
||||
}
|
||||
|
||||
struct InlineAssemblyGenerator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
arch: InlineAsmArch,
|
||||
|
|
@ -321,13 +212,10 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
|
|||
stack_slots_input: Vec<Option<Size>>,
|
||||
stack_slots_output: Vec<Option<Size>>,
|
||||
stack_slot_size: Size,
|
||||
is_naked: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
||||
fn allocate_registers(&mut self) {
|
||||
assert!(!self.is_naked);
|
||||
|
||||
let sess = self.tcx.sess;
|
||||
let map = allocatable_registers(
|
||||
self.arch,
|
||||
|
|
@ -451,8 +339,6 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn allocate_stack_slots(&mut self) {
|
||||
assert!(!self.is_naked);
|
||||
|
||||
let mut slot_size = Size::from_bytes(0);
|
||||
let mut slots_clobber = vec![None; self.operands.len()];
|
||||
let mut slots_input = vec![None; self.operands.len()];
|
||||
|
|
@ -582,32 +468,31 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
if is_x86 {
|
||||
generated_asm.push_str(".intel_syntax noprefix\n");
|
||||
}
|
||||
if !self.is_naked {
|
||||
Self::prologue(&mut generated_asm, self.arch);
|
||||
|
||||
// Save clobbered registers
|
||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_clobber.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
}
|
||||
Self::prologue(&mut generated_asm, self.arch);
|
||||
|
||||
// Write input registers
|
||||
// Save clobbered registers
|
||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_input.iter().copied())
|
||||
.zip(self.stack_slots_clobber.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Write input registers
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_input.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
|
||||
if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
generated_asm.push_str(".att_syntax\n");
|
||||
}
|
||||
|
|
@ -701,32 +586,30 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
generated_asm.push_str(".intel_syntax noprefix\n");
|
||||
}
|
||||
|
||||
if !self.is_naked {
|
||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||
// Read output registers
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_output.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
|
||||
// Restore clobbered registers
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_clobber.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
|
||||
Self::epilogue(&mut generated_asm, self.arch);
|
||||
} else {
|
||||
Self::epilogue_noreturn(&mut generated_asm, self.arch);
|
||||
if !self.options.contains(InlineAsmOptions::NORETURN) {
|
||||
// Read output registers
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_output.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::save_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
|
||||
// Restore clobbered registers
|
||||
for (reg, slot) in self
|
||||
.registers
|
||||
.iter()
|
||||
.zip(self.stack_slots_clobber.iter().copied())
|
||||
.filter_map(|(r, s)| r.zip(s))
|
||||
{
|
||||
Self::restore_register(&mut generated_asm, self.arch, reg, slot);
|
||||
}
|
||||
|
||||
Self::epilogue(&mut generated_asm, self.arch);
|
||||
} else {
|
||||
Self::epilogue_noreturn(&mut generated_asm, self.arch);
|
||||
}
|
||||
|
||||
if is_x86 {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ use std::sync::Arc;
|
|||
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use cranelift_codegen::settings::{self, Configurable};
|
||||
use rustc_codegen_ssa::CodegenResults;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, TargetConfig};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -178,7 +178,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||
let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" {
|
||||
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
|
||||
|
|
@ -197,7 +197,16 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
};
|
||||
// FIXME do `unstable_target_features` properly
|
||||
let unstable_target_features = target_features.clone();
|
||||
(target_features, unstable_target_features)
|
||||
|
||||
TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
// Cranelift does not yet support f16 or f128
|
||||
has_reliable_f16: false,
|
||||
has_reliable_f16_math: false,
|
||||
has_reliable_f128: false,
|
||||
has_reliable_f128_math: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_version(&self) {
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
|
|||
|
||||
impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
&mut self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ pub fn compile_codegen_unit(
|
|||
let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128);
|
||||
let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t);
|
||||
// TODO: improve this to avoid passing that many arguments.
|
||||
let cx = CodegenCx::new(
|
||||
let mut cx = CodegenCx::new(
|
||||
&context,
|
||||
cgu,
|
||||
tcx,
|
||||
|
|
@ -223,8 +223,8 @@ pub fn compile_codegen_unit(
|
|||
}
|
||||
|
||||
// ... and now that we have everything pre-defined, fill out those definitions.
|
||||
for &(mono_item, _) in &mono_items {
|
||||
mono_item.define::<Builder<'_, '_, '_>>(&cx);
|
||||
for &(mono_item, item_data) in &mono_items {
|
||||
mono_item.define::<Builder<'_, '_, '_>>(&mut cx, item_data);
|
||||
}
|
||||
|
||||
// If this codegen unit contains the main function, also create the
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ enum ExtremumOperation {
|
|||
Min,
|
||||
}
|
||||
|
||||
pub struct Builder<'a: 'gcc, 'gcc, 'tcx> {
|
||||
pub struct Builder<'a, 'gcc, 'tcx> {
|
||||
pub cx: &'a CodegenCx<'gcc, 'tcx>,
|
||||
pub block: Block<'gcc>,
|
||||
pub location: Option<Location<'gcc>>,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
)
|
||||
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||
// FIXME: Why do we not remove implied features on "-" here?
|
||||
// We do the equivalent above in `target_features_cfg`.
|
||||
// We do the equivalent above in `target_config`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() && diagnostics {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ use rustc_codegen_ssa::back::write::{
|
|||
};
|
||||
use rustc_codegen_ssa::base::codegen_crate;
|
||||
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
|
|
@ -260,8 +260,8 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
.join(sess)
|
||||
}
|
||||
|
||||
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
target_features_cfg(sess, &self.target_info)
|
||||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
target_config(sess, &self.target_info)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -485,10 +485,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
|
|||
}
|
||||
|
||||
/// Returns the features that should be set in `cfg(target_feature)`.
|
||||
fn target_features_cfg(
|
||||
sess: &Session,
|
||||
target_info: &LockedTargetInfo,
|
||||
) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
fn target_config(sess: &Session, target_info: &LockedTargetInfo) -> TargetConfig {
|
||||
// TODO(antoyo): use global_gcc_features.
|
||||
let f = |allow_unstable| {
|
||||
sess.target
|
||||
|
|
@ -523,5 +520,14 @@ fn target_features_cfg(
|
|||
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
(target_features, unstable_target_features)
|
||||
|
||||
TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
// There are no known bugs with GCC support for f16 or f128
|
||||
has_reliable_f16: true,
|
||||
has_reliable_f16_math: true,
|
||||
has_reliable_f128: true,
|
||||
has_reliable_f128_math: true,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
|
||||
impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
&mut self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! Set and unset common attributes on LLVM values.
|
||||
|
||||
use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -28,6 +27,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool {
|
||||
llvm::HasAttributeAtIndex(llfn, idx, attr)
|
||||
}
|
||||
|
||||
pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool {
|
||||
llvm::HasStringAttribute(llfn, name)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) {
|
||||
llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind);
|
||||
}
|
||||
|
||||
pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
|
||||
llvm::RemoveStringAttrFromFn(llfn, name);
|
||||
}
|
||||
|
||||
/// Get LLVM attribute for the provided inline heuristic.
|
||||
#[inline]
|
||||
fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ use crate::back::write::{
|
|||
use crate::errors::{
|
||||
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
|
||||
};
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::{self, build_string};
|
||||
use crate::{LlvmCodegenBackend, ModuleLlvm};
|
||||
use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes};
|
||||
|
||||
/// We keep track of the computed LTO cache keys from the previous
|
||||
/// session to determine which CGUs we can reuse.
|
||||
|
|
@ -666,6 +667,31 @@ pub(crate) fn run_pass_manager(
|
|||
}
|
||||
|
||||
if cfg!(llvm_enzyme) && enable_ad && !thin {
|
||||
let cx =
|
||||
SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
|
||||
|
||||
for function in cx.get_functions() {
|
||||
let enzyme_marker = "enzyme_marker";
|
||||
if attributes::has_string_attr(function, enzyme_marker) {
|
||||
// Sanity check: Ensure 'noinline' is present before replacing it.
|
||||
assert!(
|
||||
!attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
|
||||
"Expected __enzyme function to have 'noinline' before adding 'alwaysinline'"
|
||||
);
|
||||
|
||||
attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline);
|
||||
attributes::remove_string_attr_from_llfn(function, enzyme_marker);
|
||||
|
||||
assert!(
|
||||
!attributes::has_string_attr(function, enzyme_marker),
|
||||
"Expected function to not have 'enzyme_marker'"
|
||||
);
|
||||
|
||||
let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(function, Function, &[always_inline]);
|
||||
}
|
||||
}
|
||||
|
||||
let opt_stage = llvm::OptStage::FatLTO;
|
||||
let stage = write::AutodiffStage::PostAD;
|
||||
if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {
|
||||
|
|
|
|||
|
|
@ -83,15 +83,15 @@ pub(crate) fn compile_codegen_unit(
|
|||
// Instantiate monomorphizations without filling out definitions yet...
|
||||
let llvm_module = ModuleLlvm::new(tcx, cgu_name.as_str());
|
||||
{
|
||||
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
|
||||
let mut cx = CodegenCx::new(tcx, cgu, &llvm_module);
|
||||
let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
|
||||
for &(mono_item, data) in &mono_items {
|
||||
mono_item.predefine::<Builder<'_, '_, '_>>(&cx, data.linkage, data.visibility);
|
||||
}
|
||||
|
||||
// ... and now that we have everything pre-defined, fill out those definitions.
|
||||
for &(mono_item, _) in &mono_items {
|
||||
mono_item.define::<Builder<'_, '_, '_>>(&cx);
|
||||
for &(mono_item, item_data) in &mono_items {
|
||||
mono_item.define::<Builder<'_, '_, '_>>(&mut cx, item_data);
|
||||
}
|
||||
|
||||
// If this codegen unit contains the main function, also create the
|
||||
|
|
|
|||
|
|
@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>(
|
|||
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
|
||||
|
||||
// We add a made-up attribute just such that we can recognize it after AD to update
|
||||
// (no)-inline attributes. We'll then also remove this attribute.
|
||||
let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
|
||||
attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]);
|
||||
|
||||
// first, remove all calls from fnc
|
||||
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
|
||||
let br = llvm::LLVMRustGetTerminator(entry);
|
||||
|
|
|
|||
|
|
@ -698,6 +698,16 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
|
||||
let mut functions = vec![];
|
||||
let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) };
|
||||
while let Some(f) = func {
|
||||
functions.push(f);
|
||||
func = unsafe { llvm::LLVMGetNextFunction(f) }
|
||||
}
|
||||
functions
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -721,8 +721,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let coroutine_layout =
|
||||
cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.kind_ty()).unwrap();
|
||||
let coroutine_layout = cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.args).unwrap();
|
||||
|
||||
let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id);
|
||||
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
|
||||
|
|
|
|||
|
|
@ -174,10 +174,8 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
|
|||
DIFlags::FlagZero,
|
||||
),
|
||||
|cx, coroutine_type_di_node| {
|
||||
let coroutine_layout = cx
|
||||
.tcx
|
||||
.coroutine_layout(coroutine_def_id, coroutine_args.as_coroutine().kind_ty())
|
||||
.unwrap();
|
||||
let coroutine_layout =
|
||||
cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args).unwrap();
|
||||
|
||||
let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } =
|
||||
coroutine_type_and_layout.variants
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use back::owned_target_machine::OwnedTargetMachine;
|
|||
use back::write::{create_informational_target_machine, create_target_machine};
|
||||
use context::SimpleCx;
|
||||
use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
|
||||
use llvm_util::target_features_cfg;
|
||||
use llvm_util::target_config;
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
|
||||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
|
|
@ -37,7 +37,7 @@ use rustc_codegen_ssa::back::write::{
|
|||
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
|
||||
};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetConfig};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagCtxtHandle, FatalError};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -338,8 +338,8 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
llvm_util::print_version();
|
||||
}
|
||||
|
||||
fn target_features_cfg(&self, sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
target_features_cfg(sess)
|
||||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
target_config(sess)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,19 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
|
||||
pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
|
||||
pub(crate) fn LLVMRustHasFnAttribute(
|
||||
F: &Value,
|
||||
Name: *const c_char,
|
||||
NameLen: libc::size_t,
|
||||
) -> bool;
|
||||
pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);
|
||||
pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
|
||||
pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
|
||||
pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
|
||||
Fn: &Value,
|
||||
index: c_uint,
|
||||
kind: AttributeKind,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn HasAttributeAtIndex<'ll>(
|
||||
llfn: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
kind: AttributeKind,
|
||||
) -> bool {
|
||||
unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
|
||||
}
|
||||
|
||||
pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool {
|
||||
unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
|
||||
}
|
||||
|
||||
pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) {
|
||||
unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
|
||||
}
|
||||
|
||||
pub(crate) fn RemoveRustEnumAttributeAtIndex(
|
||||
llfn: &Value,
|
||||
place: AttributePlace,
|
||||
kind: AttributeKind,
|
||||
) {
|
||||
unsafe {
|
||||
LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn AddCallSiteAttributes<'ll>(
|
||||
callsite: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::sync::Once;
|
|||
use std::{ptr, slice, str};
|
||||
|
||||
use libc::c_int;
|
||||
use rustc_codegen_ssa::TargetConfig;
|
||||
use rustc_codegen_ssa::base::wants_wasm_eh;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
|
@ -302,7 +303,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
|||
/// Must express features in the way Rust understands them.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||
pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
pub(crate) fn target_config(sess: &Session) -> TargetConfig {
|
||||
// Add base features for the target.
|
||||
// We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
|
||||
// The reason is that if LLVM considers a feature implied but we do not, we don't want that to
|
||||
|
|
@ -402,7 +403,85 @@ pub(crate) fn target_features_cfg(sess: &Session) -> (Vec<Symbol>, Vec<Symbol>)
|
|||
|
||||
let target_features = f(false);
|
||||
let unstable_target_features = f(true);
|
||||
(target_features, unstable_target_features)
|
||||
let mut cfg = TargetConfig {
|
||||
target_features,
|
||||
unstable_target_features,
|
||||
has_reliable_f16: true,
|
||||
has_reliable_f16_math: true,
|
||||
has_reliable_f128: true,
|
||||
has_reliable_f128_math: true,
|
||||
};
|
||||
|
||||
update_target_reliable_float_cfg(sess, &mut cfg);
|
||||
cfg
|
||||
}
|
||||
|
||||
/// Determine whether or not experimental float types are reliable based on known bugs.
|
||||
fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
let target_arch = sess.target.arch.as_ref();
|
||||
let target_os = sess.target.options.os.as_ref();
|
||||
let target_env = sess.target.options.env.as_ref();
|
||||
let target_abi = sess.target.options.abi.as_ref();
|
||||
let target_pointer_width = sess.target.pointer_width;
|
||||
|
||||
cfg.has_reliable_f16 = match (target_arch, target_os) {
|
||||
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
|
||||
("s390x", _) => false,
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
|
||||
("arm64ec", _) => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
|
||||
("csky", _) => false,
|
||||
("hexagon", _) => false,
|
||||
("powerpc" | "powerpc64", _) => false,
|
||||
("sparc" | "sparc64", _) => false,
|
||||
("wasm32" | "wasm64", _) => false,
|
||||
// `f16` support only requires that symbols converting to and from `f32` are available. We
|
||||
// provide these in `compiler-builtins`, so `f16` should be available on all platforms that
|
||||
// do not have other ABI issues or LLVM crashes.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
cfg.has_reliable_f128 = match (target_arch, target_os) {
|
||||
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
|
||||
("arm64ec", _) => false,
|
||||
// Selection bug <https://github.com/llvm/llvm-project/issues/96432>
|
||||
("mips64" | "mips64r6", _) => false,
|
||||
// Selection bug <https://github.com/llvm/llvm-project/issues/95471>
|
||||
("nvptx64", _) => false,
|
||||
// ABI bugs <https://github.com/rust-lang/rust/issues/125109> et al. (full
|
||||
// list at <https://github.com/rust-lang/rust/issues/116909>)
|
||||
("powerpc" | "powerpc64", _) => false,
|
||||
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838>
|
||||
("sparc", _) => false,
|
||||
// Stack alignment bug <https://github.com/llvm/llvm-project/issues/77401>. NB: tests may
|
||||
// not fail if our compiler-builtins is linked.
|
||||
("x86", _) => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
// There are no known problems on other platforms, so the only requirement is that symbols
|
||||
// are available. `compiler-builtins` provides all symbols required for core `f128`
|
||||
// support, so this should work for everything else.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// Assume that working `f16` means working `f16` math for most platforms, since
|
||||
// operations just go through `f32`.
|
||||
cfg.has_reliable_f16_math = cfg.has_reliable_f16;
|
||||
|
||||
cfg.has_reliable_f128_math = match (target_arch, target_os) {
|
||||
// LLVM lowers `fp128` math to `long double` symbols even on platforms where
|
||||
// `long double` is not IEEE binary128. See
|
||||
// <https://github.com/llvm/llvm-project/issues/44744>.
|
||||
//
|
||||
// This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
|
||||
// (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
|
||||
// (ld is 80-bit extended precision).
|
||||
("x86_64", _) => false,
|
||||
(_, "linux") if target_pointer_width == 64 => true,
|
||||
_ => false,
|
||||
} && cfg.has_reliable_f128;
|
||||
}
|
||||
|
||||
pub(crate) fn print_version() {
|
||||
|
|
@ -686,7 +765,7 @@ pub(crate) fn global_llvm_features(
|
|||
)
|
||||
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||
// FIXME: Why do we not remove implied features on "-" here?
|
||||
// We do the equivalent above in `target_features_cfg`.
|
||||
// We do the equivalent above in `target_config`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() {
|
||||
|
|
|
|||
|
|
@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
(**self).borrow().llcx
|
||||
}
|
||||
|
||||
pub(crate) fn llmod(&self) -> &'ll llvm::Module {
|
||||
(**self).borrow().llmod
|
||||
}
|
||||
|
||||
pub(crate) fn isize_ty(&self) -> &'ll Type {
|
||||
(**self).borrow().isize_ty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ fn exported_symbols_provider_local(
|
|||
));
|
||||
}
|
||||
MonoItem::Fn(Instance {
|
||||
def: InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)),
|
||||
def: InstanceKind::AsyncDropGlueCtorShim(_, ty),
|
||||
args,
|
||||
}) => {
|
||||
// A little sanity-check
|
||||
|
|
@ -388,6 +388,16 @@ fn exported_symbols_provider_local(
|
|||
},
|
||||
));
|
||||
}
|
||||
MonoItem::Fn(Instance { def: InstanceKind::AsyncDropGlue(def, ty), args: _ }) => {
|
||||
symbols.push((
|
||||
ExportedSymbol::AsyncDropGlue(def, ty),
|
||||
SymbolExportInfo {
|
||||
level: SymbolExportLevel::Rust,
|
||||
kind: SymbolExportKind::Text,
|
||||
used: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// Any other symbols don't qualify for sharing
|
||||
}
|
||||
|
|
@ -429,11 +439,10 @@ fn upstream_monomorphizations_provider(
|
|||
if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id {
|
||||
(async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()]))
|
||||
} else {
|
||||
// `drop_in_place` in place does not exist, don't try
|
||||
// to use it.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])),
|
||||
ExportedSymbol::NonGeneric(..)
|
||||
| ExportedSymbol::ThreadLocalShim(..)
|
||||
| ExportedSymbol::NoDefId(..) => {
|
||||
|
|
@ -582,6 +591,13 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>(
|
|||
instantiating_crate,
|
||||
)
|
||||
}
|
||||
ExportedSymbol::AsyncDropGlue(def_id, ty) => {
|
||||
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
|
||||
tcx,
|
||||
Instance::resolve_async_drop_in_place_poll(tcx, def_id, ty),
|
||||
instantiating_crate,
|
||||
)
|
||||
}
|
||||
ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -604,6 +620,7 @@ fn calling_convention_for_symbol<'tcx>(
|
|||
// AsyncDropGlueCtorShim always use the Rust calling convention and thus follow the
|
||||
// target's default symbol decoration scheme.
|
||||
ExportedSymbol::AsyncDropGlueCtorShim(..) => None,
|
||||
ExportedSymbol::AsyncDropGlue(..) => None,
|
||||
// NoDefId always follow the target's default symbol decoration scheme.
|
||||
ExportedSymbol::NoDefId(..) => None,
|
||||
// ThreadLocalShim always follow the target's default symbol decoration scheme.
|
||||
|
|
|
|||
|
|
@ -12,19 +12,21 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
|||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::ItemId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::middle::{exported_symbols, lang_items};
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
|
|
@ -417,6 +419,69 @@ pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
mir::codegen_mir::<Bx>(cx, instance);
|
||||
}
|
||||
|
||||
pub fn codegen_global_asm<'tcx, Cx>(cx: &mut Cx, item_id: ItemId)
|
||||
where
|
||||
Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + AsmCodegenMethods<'tcx>,
|
||||
{
|
||||
let item = cx.tcx().hir_item(item_id);
|
||||
if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
|
||||
let operands: Vec<_> = asm
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(op, op_sp)| match *op {
|
||||
rustc_hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) {
|
||||
Ok(const_value) => {
|
||||
let ty =
|
||||
cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
||||
let string = common::asm_const_to_str(
|
||||
cx.tcx(),
|
||||
*op_sp,
|
||||
const_value,
|
||||
cx.layout_of(ty),
|
||||
);
|
||||
GlobalAsmOperandRef::Const { string }
|
||||
}
|
||||
Err(ErrorHandled::Reported { .. }) => {
|
||||
// An error has already been reported and
|
||||
// compilation is guaranteed to fail if execution
|
||||
// hits this path. So an empty string instead of
|
||||
// a stringified constant value will suffice.
|
||||
GlobalAsmOperandRef::Const { string: String::new() }
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
span_bug!(*op_sp, "asm const cannot be resolved; too generic")
|
||||
}
|
||||
}
|
||||
}
|
||||
rustc_hir::InlineAsmOperand::SymFn { expr } => {
|
||||
let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
|
||||
let instance = match ty.kind() {
|
||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||
_ => span_bug!(*op_sp, "asm sym is not a function"),
|
||||
};
|
||||
|
||||
GlobalAsmOperandRef::SymFn { instance }
|
||||
}
|
||||
rustc_hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||
GlobalAsmOperandRef::SymStatic { def_id }
|
||||
}
|
||||
rustc_hir::InlineAsmOperand::In { .. }
|
||||
| rustc_hir::InlineAsmOperand::Out { .. }
|
||||
| rustc_hir::InlineAsmOperand::InOut { .. }
|
||||
| rustc_hir::InlineAsmOperand::SplitInOut { .. }
|
||||
| rustc_hir::InlineAsmOperand::Label { .. } => {
|
||||
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans);
|
||||
} else {
|
||||
span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the `main` function which will initialize the rust runtime and call
|
||||
/// users main function.
|
||||
pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
|
||||
let mut no_mangle_span = None;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
// In some cases, attribute are only valid on functions, but it's the `check_attr`
|
||||
|
|
@ -139,6 +140,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
sym::no_mangle => {
|
||||
no_mangle_span = Some(attr.span());
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
mixed_export_name_no_mangle_lint_state.track_no_mangle(
|
||||
|
|
@ -621,6 +623,34 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
{
|
||||
let lang_item =
|
||||
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
|
||||
let mut err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
no_mangle_span.unwrap_or_default(),
|
||||
"`#[no_mangle]` cannot be used on internal language items",
|
||||
)
|
||||
.with_note("Rustc requires this item to have a specific mangled name.")
|
||||
.with_span_label(tcx.def_span(did), "should be the internal language item");
|
||||
if let Some(lang_item) = lang_item {
|
||||
if let Some(link_name) = lang_item.link_name() {
|
||||
err = err
|
||||
.with_note("If you are trying to prevent mangling to ease debugging, many")
|
||||
.with_note(format!(
|
||||
"debuggers support a command such as `rbreak {link_name}` to"
|
||||
))
|
||||
.with_note(format!(
|
||||
"match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
|
||||
))
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// Any linkage to LLVM intrinsics for now forcibly marks them all as never
|
||||
// unwinds since LLVM sometimes can't handle codegen which `invoke`s
|
||||
// intrinsic functions.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#![feature(string_from_utf8_lossy_owned)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
|
||||
|
|
@ -235,6 +236,24 @@ pub struct CrateInfo {
|
|||
pub lint_levels: CodegenLintLevels,
|
||||
}
|
||||
|
||||
/// Target-specific options that get set in `cfg(...)`.
|
||||
///
|
||||
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
||||
pub struct TargetConfig {
|
||||
/// Options to be set in `cfg(target_features)`.
|
||||
pub target_features: Vec<Symbol>,
|
||||
/// Options to be set in `cfg(target_features)`, but including unstable features.
|
||||
pub unstable_target_features: Vec<Symbol>,
|
||||
/// Option for `cfg(target_has_reliable_f16)`, true if `f16` basic arithmetic works.
|
||||
pub has_reliable_f16: bool,
|
||||
/// Option for `cfg(target_has_reliable_f16_math)`, true if `f16` math calls work.
|
||||
pub has_reliable_f16_math: bool,
|
||||
/// Option for `cfg(target_has_reliable_f128)`, true if `f128` basic arithmetic works.
|
||||
pub has_reliable_f128: bool,
|
||||
/// Option for `cfg(target_has_reliable_f128_math)`, true if `f128` math calls work.
|
||||
pub has_reliable_f128_math: bool,
|
||||
}
|
||||
|
||||
#[derive(Encodable, Decodable)]
|
||||
pub struct CodegenResults {
|
||||
pub modules: Vec<CompiledModule>,
|
||||
|
|
|
|||
|
|
@ -926,10 +926,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
let def = instance.map(|i| i.def);
|
||||
|
||||
if let Some(
|
||||
ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None),
|
||||
) = def
|
||||
{
|
||||
// We don't need AsyncDropGlueCtorShim here because it is not `noop func`,
|
||||
// it is `func returning noop future`
|
||||
if let Some(ty::InstanceKind::DropGlue(_, None)) = def {
|
||||
// Empty drop glue; a no-op.
|
||||
let target = target.unwrap();
|
||||
return helper.funclet_br(self, bx, target, mergeable_succ);
|
||||
|
|
@ -1386,8 +1385,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
MergingSucc::False
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => self
|
||||
.codegen_drop_terminator(
|
||||
mir::TerminatorKind::Drop { place, target, unwind, replace: _, drop, async_fut } => {
|
||||
assert!(
|
||||
async_fut.is_none() && drop.is_none(),
|
||||
"Async Drop must be expanded or reset to sync before codegen"
|
||||
);
|
||||
self.codegen_drop_terminator(
|
||||
helper,
|
||||
bx,
|
||||
&terminator.source_info,
|
||||
|
|
@ -1395,7 +1398,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
target,
|
||||
unwind,
|
||||
mergeable_succ(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, unwind } => self
|
||||
.codegen_assert_terminator(
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ mod coverageinfo;
|
|||
pub mod debuginfo;
|
||||
mod intrinsic;
|
||||
mod locals;
|
||||
mod naked_asm;
|
||||
pub mod naked_asm;
|
||||
pub mod operand;
|
||||
pub mod place;
|
||||
mod rvalue;
|
||||
|
|
@ -178,11 +178,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
|
||||
debug!("fn_abi: {:?}", fn_abi);
|
||||
|
||||
if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
|
||||
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
|
||||
return;
|
||||
}
|
||||
|
||||
if tcx.features().ergonomic_clones() {
|
||||
let monomorphized_mir = instance.instantiate_mir_and_normalize_erasing_regions(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -1,23 +1,33 @@
|
|||
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind};
|
||||
use rustc_attr_parsing::InstructionSetAttr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
|
||||
use rustc_middle::mir::{Body, InlineAsmOperand};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{Instance, Ty, TyCtxt};
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility};
|
||||
use rustc_middle::mir::{InlineAsmOperand, START_BLOCK};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_span::sym;
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::spec::{BinaryFormat, WasmCAbi};
|
||||
|
||||
use crate::common;
|
||||
use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
|
||||
use crate::mir::AsmCodegenMethods;
|
||||
use crate::traits::GlobalAsmOperandRef;
|
||||
|
||||
pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
cx: &'a Bx::CodegenCx,
|
||||
mir: &Body<'tcx>,
|
||||
pub fn codegen_naked_asm<
|
||||
'a,
|
||||
'tcx,
|
||||
Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
|
||||
+ FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
|
||||
+ AsmCodegenMethods<'tcx>,
|
||||
>(
|
||||
cx: &'a mut Cx,
|
||||
instance: Instance<'tcx>,
|
||||
item_data: MonoItemData,
|
||||
) {
|
||||
assert!(!instance.args.has_infer());
|
||||
let mir = cx.tcx().instance_mir(instance.def);
|
||||
|
||||
let rustc_middle::mir::TerminatorKind::InlineAsm {
|
||||
asm_macro: _,
|
||||
template,
|
||||
|
|
@ -26,15 +36,14 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
line_spans,
|
||||
targets: _,
|
||||
unwind: _,
|
||||
} = mir.basic_blocks.iter().next().unwrap().terminator().kind
|
||||
} = mir.basic_blocks[START_BLOCK].terminator().kind
|
||||
else {
|
||||
bug!("#[naked] functions should always terminate with an asm! block")
|
||||
};
|
||||
|
||||
let operands: Vec<_> =
|
||||
operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect();
|
||||
operands.iter().map(|op| inline_to_global_operand::<Cx>(cx, instance, op)).collect();
|
||||
|
||||
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
|
||||
let name = cx.mangled_name(instance);
|
||||
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
|
||||
let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data, fn_abi);
|
||||
|
|
@ -47,8 +56,8 @@ pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
|
||||
}
|
||||
|
||||
fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
cx: &'a Bx::CodegenCx,
|
||||
fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>>(
|
||||
cx: &'a Cx,
|
||||
instance: Instance<'tcx>,
|
||||
op: &InlineAsmOperand<'tcx>,
|
||||
) -> GlobalAsmOperandRef<'tcx> {
|
||||
|
|
@ -108,7 +117,7 @@ fn prefix_and_suffix<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
asm_name: &str,
|
||||
item_data: &MonoItemData,
|
||||
item_data: MonoItemData,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) -> (String, String) {
|
||||
use std::fmt::Write;
|
||||
|
|
@ -210,8 +219,10 @@ fn prefix_and_suffix<'tcx>(
|
|||
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
|
||||
writeln!(begin, ".balign {align_bytes}").unwrap();
|
||||
write_linkage(&mut begin).unwrap();
|
||||
if let Visibility::Hidden = item_data.visibility {
|
||||
writeln!(begin, ".hidden {asm_name}").unwrap();
|
||||
match item_data.visibility {
|
||||
Visibility::Default => {}
|
||||
Visibility::Protected => writeln!(begin, ".protected {asm_name}").unwrap(),
|
||||
Visibility::Hidden => writeln!(begin, ".hidden {asm_name}").unwrap(),
|
||||
}
|
||||
writeln!(begin, ".type {asm_name}, {function}").unwrap();
|
||||
if !arch_prefix.is_empty() {
|
||||
|
|
@ -231,8 +242,9 @@ fn prefix_and_suffix<'tcx>(
|
|||
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
|
||||
writeln!(begin, ".balign {align_bytes}").unwrap();
|
||||
write_linkage(&mut begin).unwrap();
|
||||
if let Visibility::Hidden = item_data.visibility {
|
||||
writeln!(begin, ".private_extern {asm_name}").unwrap();
|
||||
match item_data.visibility {
|
||||
Visibility::Default | Visibility::Protected => {}
|
||||
Visibility::Hidden => writeln!(begin, ".private_extern {asm_name}").unwrap(),
|
||||
}
|
||||
writeln!(begin, "{asm_name}:").unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::base;
|
||||
use crate::mir::naked_asm;
|
||||
use crate::traits::*;
|
||||
use crate::{base, common};
|
||||
|
||||
pub trait MonoItemExt<'a, 'tcx> {
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
&self,
|
||||
cx: &'a mut Bx::CodegenCx,
|
||||
item_data: MonoItemData,
|
||||
);
|
||||
fn predefine<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
&self,
|
||||
cx: &'a Bx::CodegenCx,
|
||||
|
|
@ -22,7 +23,11 @@ pub trait MonoItemExt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx) {
|
||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
&self,
|
||||
cx: &'a mut Bx::CodegenCx,
|
||||
item_data: MonoItemData,
|
||||
) {
|
||||
debug!(
|
||||
"BEGIN IMPLEMENTING '{} ({})' in cgu {}",
|
||||
self,
|
||||
|
|
@ -35,71 +40,19 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
|||
cx.codegen_static(def_id);
|
||||
}
|
||||
MonoItem::GlobalAsm(item_id) => {
|
||||
let item = cx.tcx().hir_item(item_id);
|
||||
if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
|
||||
let operands: Vec<_> = asm
|
||||
.operands
|
||||
.iter()
|
||||
.map(|(op, op_sp)| match *op {
|
||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) {
|
||||
Ok(const_value) => {
|
||||
let ty = cx
|
||||
.tcx()
|
||||
.typeck_body(anon_const.body)
|
||||
.node_type(anon_const.hir_id);
|
||||
let string = common::asm_const_to_str(
|
||||
cx.tcx(),
|
||||
*op_sp,
|
||||
const_value,
|
||||
cx.layout_of(ty),
|
||||
);
|
||||
GlobalAsmOperandRef::Const { string }
|
||||
}
|
||||
Err(ErrorHandled::Reported { .. }) => {
|
||||
// An error has already been reported and
|
||||
// compilation is guaranteed to fail if execution
|
||||
// hits this path. So an empty string instead of
|
||||
// a stringified constant value will suffice.
|
||||
GlobalAsmOperandRef::Const { string: String::new() }
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
span_bug!(
|
||||
*op_sp,
|
||||
"asm const cannot be resolved; too generic"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { expr } => {
|
||||
let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
|
||||
let instance = match ty.kind() {
|
||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||
_ => span_bug!(*op_sp, "asm sym is not a function"),
|
||||
};
|
||||
|
||||
GlobalAsmOperandRef::SymFn { instance }
|
||||
}
|
||||
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||
GlobalAsmOperandRef::SymStatic { def_id }
|
||||
}
|
||||
hir::InlineAsmOperand::In { .. }
|
||||
| hir::InlineAsmOperand::Out { .. }
|
||||
| hir::InlineAsmOperand::InOut { .. }
|
||||
| hir::InlineAsmOperand::SplitInOut { .. }
|
||||
| hir::InlineAsmOperand::Label { .. } => {
|
||||
span_bug!(*op_sp, "invalid operand type for global_asm!")
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans);
|
||||
} else {
|
||||
span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
|
||||
}
|
||||
base::codegen_global_asm(cx, item_id);
|
||||
}
|
||||
MonoItem::Fn(instance) => {
|
||||
base::codegen_instance::<Bx>(cx, instance);
|
||||
if cx
|
||||
.tcx()
|
||||
.codegen_fn_attrs(instance.def_id())
|
||||
.flags
|
||||
.contains(CodegenFnAttrFlags::NAKED)
|
||||
{
|
||||
naked_asm::codegen_naked_asm::<Bx::CodegenCx>(cx, instance, item_data);
|
||||
} else {
|
||||
base::codegen_instance::<Bx>(cx, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
|||
|
||||
pub trait AsmCodegenMethods<'tcx> {
|
||||
fn codegen_global_asm(
|
||||
&self,
|
||||
&mut self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[GlobalAsmOperandRef<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use super::write::WriteBackendMethods;
|
|||
use crate::back::archive::ArArchiveBuilderBuilder;
|
||||
use crate::back::link::link_binary;
|
||||
use crate::back::write::TargetMachineFactoryFn;
|
||||
use crate::{CodegenResults, ModuleCodegen};
|
||||
use crate::{CodegenResults, ModuleCodegen, TargetConfig};
|
||||
|
||||
pub trait BackendTypes {
|
||||
type Value: CodegenObject;
|
||||
|
|
@ -45,13 +45,19 @@ pub trait CodegenBackend {
|
|||
|
||||
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
||||
|
||||
/// Returns two feature sets:
|
||||
/// - The first has the features that should be set in `cfg(target_features)`.
|
||||
/// - The second is like the first, but also includes unstable features.
|
||||
///
|
||||
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
||||
fn target_features_cfg(&self, _sess: &Session) -> (Vec<Symbol>, Vec<Symbol>) {
|
||||
(vec![], vec![])
|
||||
/// Collect target-specific options that should be set in `cfg(...)`, including
|
||||
/// `target_feature` and support for unstable float types.
|
||||
fn target_config(&self, _sess: &Session) -> TargetConfig {
|
||||
TargetConfig {
|
||||
target_features: vec![],
|
||||
unstable_target_features: vec![],
|
||||
// `true` is used as a default so backends need to acknowledge when they do not
|
||||
// support the float types, rather than accidentally quietly skipping all tests.
|
||||
has_reliable_f16: true,
|
||||
has_reliable_f16_math: true,
|
||||
has_reliable_f128: true,
|
||||
has_reliable_f128_math: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_passes(&self) {}
|
||||
|
|
|
|||
|
|
@ -502,6 +502,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||
RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
|
||||
ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind),
|
||||
ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind),
|
||||
ResumedAfterDrop(coroutine_kind) => ResumedAfterDrop(*coroutine_kind),
|
||||
MisalignedPointerDereference { required, found } => MisalignedPointerDereference {
|
||||
required: eval_to_int(required)?,
|
||||
found: eval_to_int(found)?,
|
||||
|
|
|
|||
|
|
@ -570,6 +570,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
| ty::InstanceKind::FnPtrAddrShim(..)
|
||||
| ty::InstanceKind::ThreadLocalShim(..)
|
||||
| ty::InstanceKind::AsyncDropGlueCtorShim(..)
|
||||
| ty::InstanceKind::AsyncDropGlue(..)
|
||||
| ty::InstanceKind::FutureDropPollShim(..)
|
||||
| ty::InstanceKind::Item(_) => {
|
||||
// We need MIR for this fn.
|
||||
// Note that this can be an intrinsic, if we are executing its fallback body.
|
||||
|
|
|
|||
|
|
@ -61,16 +61,21 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
|||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128())
|
||||
}
|
||||
sym::variant_count => match tp_ty.kind() {
|
||||
sym::variant_count => match match tp_ty.kind() {
|
||||
// Pattern types have the same number of variants as their base type.
|
||||
// Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited.
|
||||
// And `Result<(), !>` still has two variants according to `variant_count`.
|
||||
ty::Pat(base, _) => *base,
|
||||
_ => tp_ty,
|
||||
}
|
||||
.kind()
|
||||
{
|
||||
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
|
||||
ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx),
|
||||
ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
|
||||
throw_inval!(TooGeneric)
|
||||
}
|
||||
ty::Pat(_, pat) => match **pat {
|
||||
ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
|
||||
// Future pattern kinds may have more variants
|
||||
},
|
||||
ty::Pat(..) => unreachable!(),
|
||||
ty::Bound(_, _) => bug!("bound ty during ctfe"),
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
|
|
@ -178,8 +183,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
let res = self.binary_op(op, &a, &b)?;
|
||||
// `binary_op` already called `generate_nan` if needed.
|
||||
|
||||
// FIXME: Miri should add some non-determinism to the result here to catch any dependences on exact computations. This has previously been done, but the behaviour was removed as part of constification.
|
||||
let res = M::apply_float_nondet(self, res)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,6 +276,14 @@ pub trait Machine<'tcx>: Sized {
|
|||
F2::NAN
|
||||
}
|
||||
|
||||
/// Apply non-determinism to float operations that do not return a precise result.
|
||||
fn apply_float_nondet(
|
||||
_ecx: &mut InterpCx<'tcx, Self>,
|
||||
val: ImmTy<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
|
||||
interp_ok(val)
|
||||
}
|
||||
|
||||
/// Determines the result of `min`/`max` on floats when the arguments are equal.
|
||||
fn equal_float_min_max<F: Float>(_ecx: &InterpCx<'tcx, Self>, a: F, _b: F) -> F {
|
||||
// By default, we pick the left argument.
|
||||
|
|
|
|||
|
|
@ -539,7 +539,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
Drop { place, target, unwind, replace: _ } => {
|
||||
Drop { place, target, unwind, replace: _, drop, async_fut } => {
|
||||
assert!(
|
||||
async_fut.is_none() && drop.is_none(),
|
||||
"Async Drop must be expanded or reset to sync in runtime MIR"
|
||||
);
|
||||
let place = self.eval_place(place)?;
|
||||
let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
|
||||
if let ty::InstanceKind::DropGlue(_, None) = instance.def {
|
||||
|
|
|
|||
|
|
@ -1248,6 +1248,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
|
|||
// Range patterns are precisely reflected into `valid_range` and thus
|
||||
// handled fully by `visit_scalar` (called below).
|
||||
ty::PatternKind::Range { .. } => {},
|
||||
|
||||
// FIXME(pattern_types): check that the value is covered by one of the variants.
|
||||
// For now, we rely on layout computation setting the scalar's `valid_range` to
|
||||
// match the pattern. However, this cannot always work; the layout may
|
||||
// pessimistically cover actually illegal ranges and Miri would miss that UB.
|
||||
// The consolation here is that codegen also will miss that UB, so at least
|
||||
// we won't see optimizations actually breaking such programs.
|
||||
ty::PatternKind::Or(_patterns) => {}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
|||
| ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
|
||||
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
|
||||
|
||||
ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
|
||||
ty::Alias(ty::Free, _) => bug!("type_name: unexpected free alias"),
|
||||
ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
|
||||
ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
|
|||
pub use self::lock::{Lock, LockGuard, Mode};
|
||||
pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
|
||||
pub use self::parallel::{
|
||||
join, par_for_each_in, par_map, parallel_guard, scope, try_par_for_each_in,
|
||||
join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in,
|
||||
};
|
||||
pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec};
|
||||
pub use self::worker_local::{Registry, WorkerLocal};
|
||||
|
|
|
|||
|
|
@ -93,6 +93,17 @@ macro_rules! parallel {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn spawn(func: impl FnOnce() + DynSend + 'static) {
|
||||
if mode::is_dyn_thread_safe() {
|
||||
let func = FromDyn::from(func);
|
||||
rayon_core::spawn(|| {
|
||||
(func.into_inner())();
|
||||
});
|
||||
} else {
|
||||
func()
|
||||
}
|
||||
}
|
||||
|
||||
// This function only works when `mode::is_dyn_thread_safe()`.
|
||||
pub fn scope<'scope, OP, R>(op: OP) -> R
|
||||
where
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::util::literal;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp,
|
||||
attr, token,
|
||||
attr, token, tokenstream,
|
||||
};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
|
|
@ -55,13 +57,13 @@ impl<'a> ExtCtxt<'a> {
|
|||
&self,
|
||||
span: Span,
|
||||
path: ast::Path,
|
||||
delim: ast::token::Delimiter,
|
||||
tokens: ast::tokenstream::TokenStream,
|
||||
delim: Delimiter,
|
||||
tokens: TokenStream,
|
||||
) -> P<ast::MacCall> {
|
||||
P(ast::MacCall {
|
||||
path,
|
||||
args: P(ast::DelimArgs {
|
||||
dspan: ast::tokenstream::DelimSpan { open: span, close: span },
|
||||
dspan: tokenstream::DelimSpan { open: span, close: span },
|
||||
delim,
|
||||
tokens,
|
||||
}),
|
||||
|
|
@ -480,8 +482,8 @@ impl<'a> ExtCtxt<'a> {
|
|||
span,
|
||||
[sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(),
|
||||
),
|
||||
ast::token::Delimiter::Parenthesis,
|
||||
ast::tokenstream::TokenStream::default(),
|
||||
Delimiter::Parenthesis,
|
||||
TokenStream::default(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attrib
|
|||
let NormalAttr { item, tokens } = &mut **normal;
|
||||
item.path.segments[0].ident.name = trace_name;
|
||||
// This makes the trace attributes unobservable to token-based proc macros.
|
||||
*tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default()));
|
||||
*tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::default()));
|
||||
}
|
||||
AttrKind::DocComment(..) => unreachable!(),
|
||||
}
|
||||
|
|
@ -192,7 +192,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
if self.config_tokens {
|
||||
if let Some(Some(tokens)) = node.tokens_mut() {
|
||||
let attr_stream = tokens.to_attr_token_stream();
|
||||
*tokens = LazyAttrTokenStream::new(self.configure_tokens(&attr_stream));
|
||||
*tokens = LazyAttrTokenStream::new_direct(self.configure_tokens(&attr_stream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
|
||||
|
||||
if self.in_cfg(&target.attrs) {
|
||||
target.tokens = LazyAttrTokenStream::new(
|
||||
target.tokens = LazyAttrTokenStream::new_direct(
|
||||
self.configure_tokens(&target.tokens.to_attr_token_stream()),
|
||||
);
|
||||
Some(AttrTokenTree::AttrsTarget(target))
|
||||
|
|
@ -361,7 +361,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
.to_attr_token_stream(),
|
||||
));
|
||||
|
||||
let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees)));
|
||||
let tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::new(trees)));
|
||||
let attr = ast::attr::mk_attr_from_item(
|
||||
&self.sess.psess.attr_id_generator,
|
||||
item,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use std::mem;
|
||||
|
||||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Token, TokenKind,
|
||||
};
|
||||
|
|
@ -29,10 +28,8 @@ use crate::mbe::{self, KleeneOp, MetaVarExpr};
|
|||
// A Marker adds the given mark to the syntax context.
|
||||
struct Marker(LocalExpnId, Transparency, FxHashMap<SyntaxContext, SyntaxContext>);
|
||||
|
||||
impl MutVisitor for Marker {
|
||||
const VISIT_TOKENS: bool = true;
|
||||
|
||||
fn visit_span(&mut self, span: &mut Span) {
|
||||
impl Marker {
|
||||
fn mark_span(&mut self, span: &mut Span) {
|
||||
// `apply_mark` is a relatively expensive operation, both due to taking hygiene lock, and
|
||||
// by itself. All tokens in a macro body typically have the same syntactic context, unless
|
||||
// it's some advanced case with macro-generated macros. So if we cache the marked version
|
||||
|
|
@ -292,7 +289,7 @@ pub(super) fn transcribe<'a>(
|
|||
|
||||
// Emit as a token stream within `Delimiter::Invisible` to maintain
|
||||
// parsing priorities.
|
||||
marker.visit_span(&mut sp);
|
||||
marker.mark_span(&mut sp);
|
||||
with_metavar_spans(|mspans| mspans.insert(mk_span, sp));
|
||||
// Both the open delim and close delim get the same span, which covers the
|
||||
// `$foo` in the decl macro RHS.
|
||||
|
|
@ -312,13 +309,13 @@ pub(super) fn transcribe<'a>(
|
|||
maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
|
||||
marker.visit_span(&mut sp);
|
||||
marker.mark_span(&mut sp);
|
||||
with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
|
||||
let kind = token::NtIdent(*ident, *is_raw);
|
||||
TokenTree::token_alone(kind, sp)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
|
||||
marker.visit_span(&mut sp);
|
||||
marker.mark_span(&mut sp);
|
||||
with_metavar_spans(|mspans| mspans.insert(ident.span, sp));
|
||||
let kind = token::NtLifetime(*ident, *is_raw);
|
||||
TokenTree::token_alone(kind, sp)
|
||||
|
|
@ -400,8 +397,8 @@ pub(super) fn transcribe<'a>(
|
|||
} else {
|
||||
// If we aren't able to match the meta-var, we push it back into the result but
|
||||
// with modified syntax context. (I believe this supports nested macros).
|
||||
marker.visit_span(&mut sp);
|
||||
marker.visit_ident(&mut original_ident);
|
||||
marker.mark_span(&mut sp);
|
||||
marker.mark_span(&mut original_ident.span);
|
||||
result.push(TokenTree::token_joint_hidden(token::Dollar, sp));
|
||||
result.push(TokenTree::Token(
|
||||
Token::from_ast_ident(original_ident),
|
||||
|
|
@ -430,16 +427,19 @@ pub(super) fn transcribe<'a>(
|
|||
// jump back out of the Delimited, pop the result_stack and add the new results back to
|
||||
// the previous results (from outside the Delimited).
|
||||
&mbe::TokenTree::Delimited(mut span, ref spacing, ref delimited) => {
|
||||
mut_visit::visit_delim_span(&mut marker, &mut span);
|
||||
marker.mark_span(&mut span.open);
|
||||
marker.mark_span(&mut span.close);
|
||||
stack.push(Frame::new_delimited(delimited, span, *spacing));
|
||||
result_stack.push(mem::take(&mut result));
|
||||
}
|
||||
|
||||
// Nothing much to do here. Just push the token to the result, being careful to
|
||||
// preserve syntax context.
|
||||
mbe::TokenTree::Token(token) => {
|
||||
let mut token = *token;
|
||||
mut_visit::visit_token(&mut marker, &mut token);
|
||||
&mbe::TokenTree::Token(mut token) => {
|
||||
marker.mark_span(&mut token.span);
|
||||
if let token::NtIdent(ident, _) | token::NtLifetime(ident, _) = &mut token.kind {
|
||||
marker.mark_span(&mut ident.span);
|
||||
}
|
||||
let tt = TokenTree::Token(token, Spacing::Alone);
|
||||
result.push(tt);
|
||||
}
|
||||
|
|
@ -504,7 +504,7 @@ fn maybe_use_metavar_location(
|
|||
return orig_tt.clone();
|
||||
}
|
||||
|
||||
marker.visit_span(&mut metavar_span);
|
||||
marker.mark_span(&mut metavar_span);
|
||||
let no_collision = match orig_tt {
|
||||
TokenTree::Token(token, ..) => {
|
||||
with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span))
|
||||
|
|
@ -774,7 +774,7 @@ fn transcribe_metavar_expr<'a>(
|
|||
) -> PResult<'a, ()> {
|
||||
let mut visited_span = || {
|
||||
let mut span = sp.entire();
|
||||
marker.visit_span(&mut span);
|
||||
marker.mark_span(&mut span);
|
||||
span
|
||||
};
|
||||
match *expr {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,26 @@ const GATED_CFGS: &[GatedCfg] = &[
|
|||
// this is consistent with naming of the compiler flag it's for
|
||||
(sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
|
||||
(sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh),
|
||||
(
|
||||
sym::target_has_reliable_f16,
|
||||
sym::cfg_target_has_reliable_f16_f128,
|
||||
Features::cfg_target_has_reliable_f16_f128,
|
||||
),
|
||||
(
|
||||
sym::target_has_reliable_f16_math,
|
||||
sym::cfg_target_has_reliable_f16_f128,
|
||||
Features::cfg_target_has_reliable_f16_f128,
|
||||
),
|
||||
(
|
||||
sym::target_has_reliable_f128,
|
||||
sym::cfg_target_has_reliable_f16_f128,
|
||||
Features::cfg_target_has_reliable_f16_f128,
|
||||
),
|
||||
(
|
||||
sym::target_has_reliable_f128_math,
|
||||
sym::cfg_target_has_reliable_f16_f128,
|
||||
Features::cfg_target_has_reliable_f16_f128,
|
||||
),
|
||||
];
|
||||
|
||||
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
|
||||
|
|
@ -918,6 +938,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ declare_features! (
|
|||
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
|
||||
/// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind
|
||||
(internal, cfg_emscripten_wasm_eh, "1.86.0", None),
|
||||
/// Allows checking whether or not the backend correctly supports unstable float types.
|
||||
(internal, cfg_target_has_reliable_f16_f128, "CURRENT_RUSTC_VERSION", None),
|
||||
/// Allows identifying the `compiler_builtins` crate.
|
||||
(internal, compiler_builtins, "1.13.0", None),
|
||||
/// Allows writing custom MIR
|
||||
|
|
@ -381,6 +383,8 @@ declare_features! (
|
|||
(unstable, associated_const_equality, "1.58.0", Some(92827)),
|
||||
/// Allows associated type defaults.
|
||||
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
|
||||
/// Allows implementing `AsyncDrop`.
|
||||
(incomplete, async_drop, "CURRENT_RUSTC_VERSION", Some(126482)),
|
||||
/// Allows async functions to be called from `dyn Trait`.
|
||||
(incomplete, async_fn_in_dyn_trait, "1.85.0", Some(133119)),
|
||||
/// Allows `#[track_caller]` on async functions.
|
||||
|
|
|
|||
|
|
@ -1813,6 +1813,9 @@ pub enum TyPatKind<'hir> {
|
|||
/// A range pattern (e.g., `1..=2` or `1..2`).
|
||||
Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>),
|
||||
|
||||
/// A list of patterns where only one needs to be satisfied
|
||||
Or(&'hir [TyPat<'hir>]),
|
||||
|
||||
/// A placeholder for a pattern that wasn't well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -710,6 +710,7 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>)
|
|||
try_visit!(visitor.visit_const_arg_unambig(lower_bound));
|
||||
try_visit!(visitor.visit_const_arg_unambig(upper_bound));
|
||||
}
|
||||
TyPatKind::Or(patterns) => walk_list!(visitor, visit_pattern_type_pattern, patterns),
|
||||
TyPatKind::Err(_) => (),
|
||||
}
|
||||
V::Result::output()
|
||||
|
|
|
|||
|
|
@ -189,19 +189,8 @@ language_item_table! {
|
|||
|
||||
Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
|
||||
Destruct, sym::destruct, destruct_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
AsyncDestruct, sym::async_destruct, async_destruct_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
AsyncDrop, sym::async_drop, async_drop_trait, Target::Trait, GenericRequirement::None;
|
||||
AsyncDropInPlace, sym::async_drop_in_place, async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
SurfaceAsyncDropInPlace, sym::surface_async_drop_in_place, surface_async_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropSurfaceDropInPlace, sym::async_drop_surface_drop_in_place, async_drop_surface_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropSlice, sym::async_drop_slice, async_drop_slice_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropChain, sym::async_drop_chain, async_drop_chain_fn, Target::Fn, GenericRequirement::Exact(2);
|
||||
AsyncDropNoop, sym::async_drop_noop, async_drop_noop_fn, Target::Fn, GenericRequirement::Exact(0);
|
||||
AsyncDropDeferredDropInPlace, sym::async_drop_deferred_drop_in_place, async_drop_deferred_drop_in_place_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropFuse, sym::async_drop_fuse, async_drop_fuse_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropDefer, sym::async_drop_defer, async_drop_defer_fn, Target::Fn, GenericRequirement::Exact(1);
|
||||
AsyncDropEither, sym::async_drop_either, async_drop_either_fn, Target::Fn, GenericRequirement::Exact(3);
|
||||
|
||||
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
|
|
@ -321,6 +310,10 @@ language_item_table! {
|
|||
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
|
||||
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
|
||||
PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None;
|
||||
PanicCoroutineResumedDrop, sym::panic_const_coroutine_resumed_drop, panic_const_coroutine_resumed_drop, Target::Fn, GenericRequirement::None;
|
||||
PanicAsyncFnResumedDrop, sym::panic_const_async_fn_resumed_drop, panic_const_async_fn_resumed_drop, Target::Fn, GenericRequirement::None;
|
||||
PanicAsyncGenFnResumedDrop, sym::panic_const_async_gen_fn_resumed_drop, panic_const_async_gen_fn_resumed_drop, Target::Fn, GenericRequirement::None;
|
||||
PanicGenFnNoneDrop, sym::panic_const_gen_fn_none_drop, panic_const_gen_fn_none_drop, Target::Fn, GenericRequirement::None;
|
||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
|
|
@ -333,7 +326,6 @@ language_item_table! {
|
|||
|
||||
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
|
||||
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
|
||||
FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None;
|
||||
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;
|
||||
|
||||
/// For all binary crates without `#![no_main]`, Rust will generate a "main" function.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(variant_count)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate self as rustc_hir;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ rustc_macros = { path = "../rustc_macros" }
|
|||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
|
|
|
|||
|
|
@ -450,9 +450,6 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is
|
|||
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
|
||||
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
|
||||
|
||||
hir_analysis_register_type_unstable =
|
||||
type `{$ty}` cannot be used with this register class in stable
|
||||
|
||||
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
|
||||
|
||||
hir_analysis_return_type_notation_equality_bound =
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ mod check;
|
|||
mod compare_impl_item;
|
||||
mod entry;
|
||||
pub mod intrinsic;
|
||||
pub mod intrinsicck;
|
||||
mod region;
|
||||
pub mod wfcheck;
|
||||
|
||||
|
|
|
|||
|
|
@ -2019,7 +2019,7 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
ItemKind::TyAlias(..) => {
|
||||
assert!(
|
||||
tcx.type_alias_is_lazy(item.owner_id),
|
||||
"should not be computing variance of non-weak type alias"
|
||||
"should not be computing variance of non-free type alias"
|
||||
);
|
||||
}
|
||||
kind => span_bug!(item.span, "cannot compute the variances of {kind:?}"),
|
||||
|
|
@ -2251,7 +2251,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> {
|
|||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
let def_id = match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(adt_def.did()),
|
||||
ty::Alias(ty::Weak, alias_ty) => Some(alias_ty.def_id),
|
||||
ty::Alias(ty::Free, alias_ty) => Some(alias_ty.def_id),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(def_id) = def_id {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
let id = id.owner_id.def_id;
|
||||
let item_span = self.tcx.def_span(id);
|
||||
let self_ty = self.tcx.type_of(id).instantiate_identity();
|
||||
let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
|
||||
let mut self_ty = self.tcx.peel_off_free_alias_tys(self_ty);
|
||||
// We allow impls on pattern types exactly when we allow impls on the base type.
|
||||
// FIXME(pattern_types): Figure out the exact coherence rules we want here.
|
||||
while let ty::Pat(base, _) = *self_ty.kind() {
|
||||
|
|
@ -188,7 +188,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Alias(ty::Weak, _)
|
||||
| ty::Alias(ty::Free, _)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_) => {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ pub(crate) fn orphan_check_impl(
|
|||
ty::Projection => "associated type",
|
||||
// type Foo = (impl Sized, bool)
|
||||
// impl AutoTrait for Foo {}
|
||||
ty::Weak => "type alias",
|
||||
ty::Free => "type alias",
|
||||
// type Opaque = impl Trait;
|
||||
// impl AutoTrait for Opaque {}
|
||||
ty::Opaque => "opaque type",
|
||||
|
|
|
|||
|
|
@ -94,10 +94,12 @@ fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: S
|
|||
}
|
||||
|
||||
Node::TyPat(pat) => {
|
||||
let hir::TyKind::Pat(ty, p) = tcx.parent_hir_node(pat.hir_id).expect_ty().kind else {
|
||||
bug!()
|
||||
let node = match tcx.parent_hir_node(pat.hir_id) {
|
||||
// Or patterns can be nested one level deep
|
||||
Node::TyPat(p) => tcx.parent_hir_node(p.hir_id),
|
||||
other => other,
|
||||
};
|
||||
assert_eq!(p.hir_id, pat.hir_id);
|
||||
let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() };
|
||||
icx.lower_ty(ty)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ pub(crate) fn parameters_for<'tcx>(
|
|||
include_nonconstraining: bool,
|
||||
) -> Vec<Parameter> {
|
||||
let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
|
||||
let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value };
|
||||
let value = if !include_nonconstraining { tcx.expand_free_alias_tys(value) } else { value };
|
||||
value.visit_with(&mut collector);
|
||||
collector.parameters
|
||||
}
|
||||
|
|
@ -68,9 +68,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
|
|||
{
|
||||
return;
|
||||
}
|
||||
// All weak alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Weak, _) if !self.include_nonconstraining => {
|
||||
bug!("unexpected weak alias type")
|
||||
// All free alias types should've been expanded beforehand.
|
||||
ty::Alias(ty::Free, _) if !self.include_nonconstraining => {
|
||||
bug!("unexpected free alias type")
|
||||
}
|
||||
ty::Param(param) => self.parameters.push(Parameter::from(param)),
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -1675,14 +1675,6 @@ pub(crate) struct CmseEntryGeneric {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_register_type_unstable)]
|
||||
pub(crate) struct RegisterTypeUnstable<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_analysis_supertrait_item_shadowing)]
|
||||
pub(crate) struct SupertraitItemShadowing {
|
||||
|
|
|
|||
|
|
@ -958,7 +958,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// feature `lazy_type_alias` enabled get encoded as a type alias that normalization will
|
||||
// then actually instantiate the where bounds of.
|
||||
let alias_ty = ty::AliasTy::new_from_args(tcx, did, args);
|
||||
Ty::new_alias(tcx, ty::Weak, alias_ty)
|
||||
Ty::new_alias(tcx, ty::Free, alias_ty)
|
||||
} else {
|
||||
tcx.at(span).type_of(did).instantiate(tcx, args)
|
||||
}
|
||||
|
|
@ -2715,30 +2715,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::TyKind::Pat(ty, pat) => {
|
||||
let ty_span = ty.span;
|
||||
let ty = self.lower_ty(ty);
|
||||
let pat_ty = match pat.kind {
|
||||
hir::TyPatKind::Range(start, end) => {
|
||||
let (ty, start, end) = match ty.kind() {
|
||||
// Keep this list of types in sync with the list of types that
|
||||
// the `RangePattern` trait is implemented for.
|
||||
ty::Int(_) | ty::Uint(_) | ty::Char => {
|
||||
let start = self.lower_const_arg(start, FeedConstTy::No);
|
||||
let end = self.lower_const_arg(end, FeedConstTy::No);
|
||||
(ty, start, end)
|
||||
}
|
||||
_ => {
|
||||
let guar = self.dcx().span_delayed_bug(
|
||||
ty_span,
|
||||
"invalid base type for range pattern",
|
||||
);
|
||||
let errc = ty::Const::new_error(tcx, guar);
|
||||
(Ty::new_error(tcx, guar), errc, errc)
|
||||
}
|
||||
};
|
||||
|
||||
let pat = tcx.mk_pat(ty::PatternKind::Range { start, end });
|
||||
Ty::new_pat(tcx, ty, pat)
|
||||
}
|
||||
hir::TyPatKind::Err(e) => Ty::new_error(tcx, e),
|
||||
let pat_ty = match self.lower_pat_ty_pat(ty, ty_span, pat) {
|
||||
Ok(kind) => Ty::new_pat(tcx, ty, tcx.mk_pat(kind)),
|
||||
Err(guar) => Ty::new_error(tcx, guar),
|
||||
};
|
||||
self.record_ty(pat.hir_id, ty, pat.span);
|
||||
pat_ty
|
||||
|
|
@ -2750,6 +2729,39 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
result_ty
|
||||
}
|
||||
|
||||
fn lower_pat_ty_pat(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
ty_span: Span,
|
||||
pat: &hir::TyPat<'tcx>,
|
||||
) -> Result<ty::PatternKind<'tcx>, ErrorGuaranteed> {
|
||||
let tcx = self.tcx();
|
||||
match pat.kind {
|
||||
hir::TyPatKind::Range(start, end) => {
|
||||
match ty.kind() {
|
||||
// Keep this list of types in sync with the list of types that
|
||||
// the `RangePattern` trait is implemented for.
|
||||
ty::Int(_) | ty::Uint(_) | ty::Char => {
|
||||
let start = self.lower_const_arg(start, FeedConstTy::No);
|
||||
let end = self.lower_const_arg(end, FeedConstTy::No);
|
||||
Ok(ty::PatternKind::Range { start, end })
|
||||
}
|
||||
_ => Err(self
|
||||
.dcx()
|
||||
.span_delayed_bug(ty_span, "invalid base type for range pattern")),
|
||||
}
|
||||
}
|
||||
hir::TyPatKind::Or(patterns) => {
|
||||
self.tcx()
|
||||
.mk_patterns_from_iter(patterns.iter().map(|pat| {
|
||||
self.lower_pat_ty_pat(ty, ty_span, pat).map(|pat| tcx.mk_pat(pat))
|
||||
}))
|
||||
.map(ty::PatternKind::Or)
|
||||
}
|
||||
hir::TyPatKind::Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -157,10 +157,10 @@ fn insert_required_predicates_to_be_wf<'tcx>(
|
|||
);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
ty::Alias(ty::Free, alias) => {
|
||||
// This corresponds to a type like `Type<'a, T>`.
|
||||
// We check inferred and explicit predicates.
|
||||
debug!("Weak");
|
||||
debug!("Free");
|
||||
check_inferred_predicates(
|
||||
tcx,
|
||||
alias.def_id,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
let current_item = &CurrentItem { inferred_start };
|
||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||
|
||||
// The type as returned by `type_of` is the underlying type and generally not a weak projection.
|
||||
// The type as returned by `type_of` is the underlying type and generally not a free alias.
|
||||
// Therefore we need to check the `DefKind` first.
|
||||
if let DefKind::TyAlias = tcx.def_kind(def_id)
|
||||
&& tcx.type_alias_is_lazy(def_id)
|
||||
|
|
@ -251,12 +251,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Pat(typ, pat) => {
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
self.add_constraints_from_const(current, start, variance);
|
||||
self.add_constraints_from_const(current, end, variance);
|
||||
}
|
||||
}
|
||||
self.add_constraints_from_pat(current, variance, pat);
|
||||
self.add_constraints_from_ty(current, typ, variance);
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +277,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
self.add_constraints_from_invariant_args(current, data.args, variance);
|
||||
}
|
||||
|
||||
ty::Alias(ty::Weak, ref data) => {
|
||||
ty::Alias(ty::Free, ref data) => {
|
||||
self.add_constraints_from_args(current, data.def_id, data.args, variance);
|
||||
}
|
||||
|
||||
|
|
@ -334,6 +329,25 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_constraints_from_pat(
|
||||
&mut self,
|
||||
current: &CurrentItem,
|
||||
variance: VarianceTermPtr<'a>,
|
||||
pat: ty::Pattern<'tcx>,
|
||||
) {
|
||||
match *pat {
|
||||
ty::PatternKind::Range { start, end } => {
|
||||
self.add_constraints_from_const(current, start, variance);
|
||||
self.add_constraints_from_const(current, end, variance);
|
||||
}
|
||||
ty::PatternKind::Or(patterns) => {
|
||||
for pat in patterns {
|
||||
self.add_constraints_from_pat(current, variance, pat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds constraints appropriate for a nominal type (enum, struct,
|
||||
/// object, etc) appearing in a context with ambient variance `variance`
|
||||
fn add_constraints_from_args(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs};
|
||||
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
|
||||
use rustc_ast_pretty::pp::{self, Breaks};
|
||||
use rustc_ast_pretty::pp::{self, BoxMarker, Breaks};
|
||||
use rustc_ast_pretty::pprust::state::MacHeader;
|
||||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
use rustc_attr_data_structures::{AttributeKind, PrintAttribute};
|
||||
|
|
@ -127,7 +127,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_attr_item(&mut self, item: &hir::AttrItem, span: Span) {
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
let path = ast::Path {
|
||||
span,
|
||||
segments: item
|
||||
|
|
@ -146,6 +146,7 @@ impl<'a> State<'a> {
|
|||
false,
|
||||
None,
|
||||
*delim,
|
||||
None,
|
||||
&tokens,
|
||||
true,
|
||||
span,
|
||||
|
|
@ -161,7 +162,7 @@ impl<'a> State<'a> {
|
|||
self.word(token_str);
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_node(&mut self, node: Node<'_>) {
|
||||
|
|
@ -192,10 +193,10 @@ impl<'a> State<'a> {
|
|||
Node::PreciseCapturingNonLifetimeArg(param) => self.print_ident(param.ident),
|
||||
Node::Block(a) => {
|
||||
// Containing cbox, will be closed by print-block at `}`.
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
// Head-ibox, will be closed by print-block after `{`.
|
||||
self.ibox(0);
|
||||
self.print_block(a);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block(a, cb, ib);
|
||||
}
|
||||
Node::Lifetime(a) => self.print_lifetime(a),
|
||||
Node::GenericParam(_) => panic!("cannot print Node::GenericParam"),
|
||||
|
|
@ -315,17 +316,17 @@ pub fn item_to_string(ann: &dyn PpAnn, pat: &hir::Item<'_>) -> String {
|
|||
}
|
||||
|
||||
impl<'a> State<'a> {
|
||||
fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) {
|
||||
fn bclose_maybe_open(&mut self, span: rustc_span::Span, cb: Option<BoxMarker>) {
|
||||
self.maybe_print_comment(span.hi());
|
||||
self.break_offset_if_not_bol(1, -INDENT_UNIT);
|
||||
self.word("}");
|
||||
if close_box {
|
||||
self.end(); // close the outer-box
|
||||
if let Some(cb) = cb {
|
||||
self.end(cb);
|
||||
}
|
||||
}
|
||||
|
||||
fn bclose(&mut self, span: rustc_span::Span) {
|
||||
self.bclose_maybe_open(span, true)
|
||||
fn bclose(&mut self, span: rustc_span::Span, cb: BoxMarker) {
|
||||
self.bclose_maybe_open(span, Some(cb))
|
||||
}
|
||||
|
||||
fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
|
||||
|
|
@ -333,7 +334,7 @@ impl<'a> State<'a> {
|
|||
F: FnMut(&mut State<'_>, &T),
|
||||
G: FnMut(&T) -> rustc_span::Span,
|
||||
{
|
||||
self.rbox(0, b);
|
||||
let rb = self.rbox(0, b);
|
||||
let len = elts.len();
|
||||
let mut i = 0;
|
||||
for elt in elts {
|
||||
|
|
@ -346,7 +347,7 @@ impl<'a> State<'a> {
|
|||
self.space_if_not_bol();
|
||||
}
|
||||
}
|
||||
self.end();
|
||||
self.end(rb);
|
||||
}
|
||||
|
||||
fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
|
||||
|
|
@ -369,7 +370,7 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_type(&mut self, ty: &hir::Ty<'_>) {
|
||||
self.maybe_print_comment(ty.span.lo());
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
match ty.kind {
|
||||
hir::TyKind::Slice(ty) => {
|
||||
self.word("[");
|
||||
|
|
@ -456,16 +457,16 @@ impl<'a> State<'a> {
|
|||
self.print_ty_pat(pat);
|
||||
}
|
||||
}
|
||||
self.end()
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(unsafe_binder.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(unsafe_binder.inner_ty);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
|
||||
|
|
@ -474,7 +475,7 @@ impl<'a> State<'a> {
|
|||
self.print_attrs_as_outer(self.attrs(item.hir_id()));
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(sig, arg_idents, generics) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_fn(
|
||||
sig.decl,
|
||||
sig.header,
|
||||
|
|
@ -483,13 +484,13 @@ impl<'a> State<'a> {
|
|||
arg_idents,
|
||||
None,
|
||||
);
|
||||
self.end(); // end head-ibox
|
||||
self.end(ib);
|
||||
self.word(";");
|
||||
self.end() // end the outer fn box
|
||||
self.end(cb)
|
||||
}
|
||||
hir::ForeignItemKind::Static(t, m, safety) => {
|
||||
self.print_safety(safety);
|
||||
self.head("static");
|
||||
let (cb, ib) = self.head("static");
|
||||
if m.is_mut() {
|
||||
self.word_space("mut");
|
||||
}
|
||||
|
|
@ -497,15 +498,15 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
self.print_type(t);
|
||||
self.word(";");
|
||||
self.end(); // end the head-ibox
|
||||
self.end() // end the outer cbox
|
||||
self.end(ib);
|
||||
self.end(cb)
|
||||
}
|
||||
hir::ForeignItemKind::Type => {
|
||||
self.head("type");
|
||||
let (cb, ib) = self.head("type");
|
||||
self.print_ident(item.ident);
|
||||
self.word(";");
|
||||
self.end(); // end the head-ibox
|
||||
self.end() // end the outer cbox
|
||||
self.end(ib);
|
||||
self.end(cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -561,7 +562,7 @@ impl<'a> State<'a> {
|
|||
self.ann.pre(self, AnnNode::Item(item));
|
||||
match item.kind {
|
||||
hir::ItemKind::ExternCrate(orig_name, ident) => {
|
||||
self.head("extern crate");
|
||||
let (cb, ib) = self.head("extern crate");
|
||||
if let Some(orig_name) = orig_name {
|
||||
self.print_name(orig_name);
|
||||
self.space();
|
||||
|
|
@ -570,11 +571,11 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_ident(ident);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Use(path, kind) => {
|
||||
self.head("use");
|
||||
let (cb, ib) = self.head("use");
|
||||
self.print_path(path, false);
|
||||
|
||||
match kind {
|
||||
|
|
@ -589,11 +590,11 @@ impl<'a> State<'a> {
|
|||
hir::UseKind::Glob => self.word("::*;"),
|
||||
hir::UseKind::ListStem => self.word("::{};"),
|
||||
}
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Static(ident, ty, m, expr) => {
|
||||
self.head("static");
|
||||
let (cb, ib) = self.head("static");
|
||||
if m.is_mut() {
|
||||
self.word_space("mut");
|
||||
}
|
||||
|
|
@ -601,85 +602,86 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
self.space();
|
||||
self.end(); // end the head-ibox
|
||||
self.end(ib);
|
||||
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Const(ident, ty, generics, expr) => {
|
||||
self.head("const");
|
||||
let (cb, ib) = self.head("const");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
self.space();
|
||||
self.end(); // end the head-ibox
|
||||
self.end(ib);
|
||||
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
self.print_where_clause(generics);
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Fn { ident, sig, generics, body, .. } => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_fn(sig.decl, sig.header, Some(ident.name), generics, &[], Some(body));
|
||||
self.word(" ");
|
||||
self.end(); // need to close a box
|
||||
self.end(); // need to close a box
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
self.ann.nested(self, Nested::Body(body));
|
||||
}
|
||||
hir::ItemKind::Macro(ident, macro_def, _) => {
|
||||
self.print_mac_def(macro_def, &ident, item.span, |_| {});
|
||||
}
|
||||
hir::ItemKind::Mod(ident, mod_) => {
|
||||
self.head("mod");
|
||||
let (cb, ib) = self.head("mod");
|
||||
self.print_ident(ident);
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_mod(mod_, attrs);
|
||||
self.bclose(item.span);
|
||||
self.bclose(item.span, cb);
|
||||
}
|
||||
hir::ItemKind::ForeignMod { abi, items } => {
|
||||
self.head("extern");
|
||||
let (cb, ib) = self.head("extern");
|
||||
self.word_nbsp(abi.to_string());
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_attrs_as_inner(self.attrs(item.hir_id()));
|
||||
for item in items {
|
||||
self.ann.nested(self, Nested::ForeignItem(item.id));
|
||||
}
|
||||
self.bclose(item.span);
|
||||
self.bclose(item.span, cb);
|
||||
}
|
||||
hir::ItemKind::GlobalAsm { asm, .. } => {
|
||||
self.head("global_asm!");
|
||||
// FIXME(nnethercote): `ib` is unclosed
|
||||
let (cb, _ib) = self.head("global_asm!");
|
||||
self.print_inline_asm(asm);
|
||||
self.end()
|
||||
self.end(cb)
|
||||
}
|
||||
hir::ItemKind::TyAlias(ident, ty, generics) => {
|
||||
self.head("type");
|
||||
let (cb, ib) = self.head("type");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.end(); // end the inner ibox
|
||||
self.end(ib);
|
||||
|
||||
self.print_where_clause(generics);
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_type(ty);
|
||||
self.word(";");
|
||||
self.end(); // end the outer ibox
|
||||
self.end(cb);
|
||||
}
|
||||
hir::ItemKind::Enum(ident, ref enum_definition, params) => {
|
||||
self.print_enum_def(enum_definition, params, ident.name, item.span);
|
||||
}
|
||||
hir::ItemKind::Struct(ident, ref struct_def, generics) => {
|
||||
self.head("struct");
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true);
|
||||
let (cb, ib) = self.head("struct");
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true, cb, ib);
|
||||
}
|
||||
hir::ItemKind::Union(ident, ref struct_def, generics) => {
|
||||
self.head("union");
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true);
|
||||
let (cb, ib) = self.head("union");
|
||||
self.print_struct(struct_def, generics, ident.name, item.span, true, cb, ib);
|
||||
}
|
||||
hir::ItemKind::Impl(&hir::Impl {
|
||||
constness,
|
||||
|
|
@ -692,7 +694,7 @@ impl<'a> State<'a> {
|
|||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_safety(safety);
|
||||
self.word_nbsp("impl");
|
||||
|
|
@ -720,15 +722,15 @@ impl<'a> State<'a> {
|
|||
self.print_where_clause(generics);
|
||||
|
||||
self.space();
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
self.print_attrs_as_inner(attrs);
|
||||
for impl_item in items {
|
||||
self.ann.nested(self, Nested::ImplItem(impl_item.id));
|
||||
}
|
||||
self.bclose(item.span);
|
||||
self.bclose(item.span, cb);
|
||||
}
|
||||
hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_is_auto(is_auto);
|
||||
self.print_safety(safety);
|
||||
self.word_nbsp("trait");
|
||||
|
|
@ -737,22 +739,22 @@ impl<'a> State<'a> {
|
|||
self.print_bounds(":", bounds);
|
||||
self.print_where_clause(generics);
|
||||
self.word(" ");
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
for trait_item in trait_items {
|
||||
self.ann.nested(self, Nested::TraitItem(trait_item.id));
|
||||
}
|
||||
self.bclose(item.span);
|
||||
self.bclose(item.span, cb);
|
||||
}
|
||||
hir::ItemKind::TraitAlias(ident, generics, bounds) => {
|
||||
self.head("trait");
|
||||
let (cb, ib) = self.head("trait");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.nbsp();
|
||||
self.print_bounds("=", bounds);
|
||||
self.print_where_clause(generics);
|
||||
self.word(";");
|
||||
self.end(); // end inner head-block
|
||||
self.end(); // end outer head-block
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Item(item))
|
||||
|
|
@ -763,7 +765,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) {
|
||||
self.head("opaque");
|
||||
// FIXME(nnethercote): `cb` and `ib` are unclosed
|
||||
let (_cb, _ib) = self.head("opaque");
|
||||
self.word("{");
|
||||
self.print_bounds("impl", o.bounds);
|
||||
self.word("}");
|
||||
|
|
@ -800,27 +803,33 @@ impl<'a> State<'a> {
|
|||
name: Symbol,
|
||||
span: rustc_span::Span,
|
||||
) {
|
||||
self.head("enum");
|
||||
let (cb, ib) = self.head("enum");
|
||||
self.print_name(name);
|
||||
self.print_generic_params(generics.params);
|
||||
self.print_where_clause(generics);
|
||||
self.space();
|
||||
self.print_variants(enum_definition.variants, span);
|
||||
self.print_variants(enum_definition.variants, span, cb, ib);
|
||||
}
|
||||
|
||||
fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
|
||||
self.bopen();
|
||||
fn print_variants(
|
||||
&mut self,
|
||||
variants: &[hir::Variant<'_>],
|
||||
span: rustc_span::Span,
|
||||
cb: BoxMarker,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
self.bopen(ib);
|
||||
for v in variants {
|
||||
self.space_if_not_bol();
|
||||
self.maybe_print_comment(v.span.lo());
|
||||
self.print_attrs_as_outer(self.attrs(v.hir_id));
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.print_variant(v);
|
||||
self.word(",");
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.maybe_print_trailing_comment(v.span, None);
|
||||
}
|
||||
self.bclose(span)
|
||||
self.bclose(span, cb)
|
||||
}
|
||||
|
||||
fn print_defaultness(&mut self, defaultness: hir::Defaultness) {
|
||||
|
|
@ -837,6 +846,8 @@ impl<'a> State<'a> {
|
|||
name: Symbol,
|
||||
span: rustc_span::Span,
|
||||
print_finalizer: bool,
|
||||
cb: BoxMarker,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
self.print_name(name);
|
||||
self.print_generic_params(generics.params);
|
||||
|
|
@ -855,38 +866,34 @@ impl<'a> State<'a> {
|
|||
if print_finalizer {
|
||||
self.word(";");
|
||||
}
|
||||
self.end();
|
||||
self.end() // close the outer-box
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
}
|
||||
hir::VariantData::Struct { .. } => {
|
||||
self.print_where_clause(generics);
|
||||
self.print_variant_struct(span, struct_def.fields())
|
||||
self.nbsp();
|
||||
self.bopen(ib);
|
||||
self.hardbreak_if_not_bol();
|
||||
|
||||
for field in struct_def.fields() {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(field.span.lo());
|
||||
self.print_attrs_as_outer(self.attrs(field.hir_id));
|
||||
self.print_ident(field.ident);
|
||||
self.word_nbsp(":");
|
||||
self.print_type(field.ty);
|
||||
self.word(",");
|
||||
}
|
||||
|
||||
self.bclose(span, cb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
self.hardbreak_if_not_bol();
|
||||
|
||||
for field in fields {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(field.span.lo());
|
||||
self.print_attrs_as_outer(self.attrs(field.hir_id));
|
||||
self.print_ident(field.ident);
|
||||
self.word_nbsp(":");
|
||||
self.print_type(field.ty);
|
||||
self.word(",");
|
||||
}
|
||||
|
||||
self.bclose(span)
|
||||
}
|
||||
|
||||
pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
let generics = hir::Generics::empty();
|
||||
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
|
||||
self.print_struct(&v.data, generics, v.ident.name, v.span, false, cb, ib);
|
||||
if let Some(ref d) = v.disr_expr {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
|
|
@ -919,11 +926,11 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(body));
|
||||
self.nbsp();
|
||||
self.end(); // need to close a box
|
||||
self.end(); // need to close a box
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
self.ann.nested(self, Nested::Body(body));
|
||||
}
|
||||
hir::TraitItemKind::Type(bounds, default) => {
|
||||
|
|
@ -944,11 +951,11 @@ impl<'a> State<'a> {
|
|||
self.print_associated_const(ii.ident, ii.generics, ty, Some(expr));
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
self.head("");
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(body));
|
||||
self.nbsp();
|
||||
self.end(); // need to close a box
|
||||
self.end(); // need to close a box
|
||||
self.end(ib);
|
||||
self.end(cb);
|
||||
self.ann.nested(self, Nested::Body(body));
|
||||
}
|
||||
hir::ImplItemKind::Type(ty) => {
|
||||
|
|
@ -966,15 +973,15 @@ impl<'a> State<'a> {
|
|||
decl: impl Fn(&mut Self),
|
||||
) {
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ibm1 = self.ibox(INDENT_UNIT);
|
||||
if super_ {
|
||||
self.word_nbsp("super");
|
||||
}
|
||||
self.word_nbsp("let");
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ibm2 = self.ibox(INDENT_UNIT);
|
||||
decl(self);
|
||||
self.end();
|
||||
self.end(ibm2);
|
||||
|
||||
if let Some(init) = init {
|
||||
self.nbsp();
|
||||
|
|
@ -986,13 +993,13 @@ impl<'a> State<'a> {
|
|||
self.nbsp();
|
||||
self.word_space("else");
|
||||
// containing cbox, will be closed by print-block at `}`
|
||||
self.cbox(0);
|
||||
let cb = self.cbox(0);
|
||||
// head-box, will be closed by print-block after `{`
|
||||
self.ibox(0);
|
||||
self.print_block(els);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block(els, cb, ib);
|
||||
}
|
||||
|
||||
self.end()
|
||||
self.end(ibm1)
|
||||
}
|
||||
|
||||
fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
|
||||
|
|
@ -1020,23 +1027,30 @@ impl<'a> State<'a> {
|
|||
self.maybe_print_trailing_comment(st.span, None)
|
||||
}
|
||||
|
||||
fn print_block(&mut self, blk: &hir::Block<'_>) {
|
||||
self.print_block_with_attrs(blk, &[])
|
||||
fn print_block(&mut self, blk: &hir::Block<'_>, cb: BoxMarker, ib: BoxMarker) {
|
||||
self.print_block_with_attrs(blk, &[], cb, ib)
|
||||
}
|
||||
|
||||
fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) {
|
||||
self.print_block_maybe_unclosed(blk, &[], false)
|
||||
fn print_block_unclosed(&mut self, blk: &hir::Block<'_>, ib: BoxMarker) {
|
||||
self.print_block_maybe_unclosed(blk, &[], None, ib)
|
||||
}
|
||||
|
||||
fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[hir::Attribute]) {
|
||||
self.print_block_maybe_unclosed(blk, attrs, true)
|
||||
fn print_block_with_attrs(
|
||||
&mut self,
|
||||
blk: &hir::Block<'_>,
|
||||
attrs: &[hir::Attribute],
|
||||
cb: BoxMarker,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
self.print_block_maybe_unclosed(blk, attrs, Some(cb), ib)
|
||||
}
|
||||
|
||||
fn print_block_maybe_unclosed(
|
||||
&mut self,
|
||||
blk: &hir::Block<'_>,
|
||||
attrs: &[hir::Attribute],
|
||||
close_box: bool,
|
||||
cb: Option<BoxMarker>,
|
||||
ib: BoxMarker,
|
||||
) {
|
||||
match blk.rules {
|
||||
hir::BlockCheckMode::UnsafeBlock(..) => self.word_space("unsafe"),
|
||||
|
|
@ -1044,7 +1058,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.maybe_print_comment(blk.span.lo());
|
||||
self.ann.pre(self, AnnNode::Block(blk));
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
|
||||
self.print_attrs_as_inner(attrs);
|
||||
|
||||
|
|
@ -1056,7 +1070,7 @@ impl<'a> State<'a> {
|
|||
self.print_expr(expr);
|
||||
self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
|
||||
}
|
||||
self.bclose_maybe_open(blk.span, close_box);
|
||||
self.bclose_maybe_open(blk.span, cb);
|
||||
self.ann.post(self, AnnNode::Block(blk))
|
||||
}
|
||||
|
||||
|
|
@ -1065,20 +1079,20 @@ impl<'a> State<'a> {
|
|||
match els_inner.kind {
|
||||
// Another `else if` block.
|
||||
hir::ExprKind::If(i, hir::Expr { kind: hir::ExprKind::Block(t, None), .. }, e) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word(" else if ");
|
||||
self.print_expr_as_cond(i);
|
||||
self.space();
|
||||
self.print_block(t);
|
||||
self.print_block(t, cb, ib);
|
||||
self.print_else(e);
|
||||
}
|
||||
// Final `else` block.
|
||||
hir::ExprKind::Block(b, None) => {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word(" else ");
|
||||
self.print_block(b);
|
||||
self.print_block(b, cb, ib);
|
||||
}
|
||||
// Constraints would be great here!
|
||||
_ => {
|
||||
|
|
@ -1094,14 +1108,14 @@ impl<'a> State<'a> {
|
|||
blk: &hir::Expr<'_>,
|
||||
elseopt: Option<&hir::Expr<'_>>,
|
||||
) {
|
||||
self.cbox(0);
|
||||
self.ibox(0);
|
||||
self.word_nbsp("if");
|
||||
self.print_expr_as_cond(test);
|
||||
self.space();
|
||||
match blk.kind {
|
||||
hir::ExprKind::Block(blk, None) => {
|
||||
self.print_block(blk);
|
||||
let cb = self.cbox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.word_nbsp("if");
|
||||
self.print_expr_as_cond(test);
|
||||
self.space();
|
||||
self.print_block(blk, cb, ib);
|
||||
self.print_else(elseopt)
|
||||
}
|
||||
_ => panic!("non-block then expr"),
|
||||
|
|
@ -1175,28 +1189,28 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_vec(&mut self, exprs: &[hir::Expr<'_>]) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.commasep_exprs(Inconsistent, exprs);
|
||||
self.word("]");
|
||||
self.end()
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word_space("const");
|
||||
self.ann.nested(self, Nested::Body(constant.body));
|
||||
self.end()
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ConstArg<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.print_expr(element);
|
||||
self.word_space(";");
|
||||
self.print_const_arg(count);
|
||||
self.word("]");
|
||||
self.end()
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
fn print_expr_struct(
|
||||
|
|
@ -1211,23 +1225,23 @@ impl<'a> State<'a> {
|
|||
self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span);
|
||||
match wth {
|
||||
hir::StructTailExpr::Base(expr) => {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
if !fields.is_empty() {
|
||||
self.word(",");
|
||||
self.space();
|
||||
}
|
||||
self.word("..");
|
||||
self.print_expr(expr);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
hir::StructTailExpr::DefaultFields(_) => {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
if !fields.is_empty() {
|
||||
self.word(",");
|
||||
self.space();
|
||||
}
|
||||
self.word("..");
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
hir::StructTailExpr::None => {}
|
||||
}
|
||||
|
|
@ -1236,14 +1250,14 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_field(&mut self, field: &hir::ExprField<'_>) {
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
self.print_attrs_as_outer(self.attrs(field.hir_id));
|
||||
if !field.is_shorthand {
|
||||
self.print_ident(field.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.print_expr(field.expr);
|
||||
self.end()
|
||||
self.end(cb)
|
||||
}
|
||||
|
||||
fn print_expr_tup(&mut self, exprs: &[hir::Expr<'_>]) {
|
||||
|
|
@ -1416,8 +1430,8 @@ impl<'a> State<'a> {
|
|||
s.print_qpath(path, true);
|
||||
}
|
||||
hir::InlineAsmOperand::Label { block } => {
|
||||
s.head("label");
|
||||
s.print_block(block);
|
||||
let (cb, ib) = s.head("label");
|
||||
s.print_block(block, cb, ib);
|
||||
}
|
||||
},
|
||||
AsmArg::Options(opts) => {
|
||||
|
|
@ -1435,7 +1449,7 @@ impl<'a> State<'a> {
|
|||
fn print_expr(&mut self, expr: &hir::Expr<'_>) {
|
||||
self.maybe_print_comment(expr.span.lo());
|
||||
self.print_attrs_as_outer(self.attrs(expr.hir_id));
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.ann.pre(self, AnnNode::Expr(expr));
|
||||
match expr.kind {
|
||||
hir::ExprKind::Array(exprs) => {
|
||||
|
|
@ -1483,21 +1497,21 @@ impl<'a> State<'a> {
|
|||
}
|
||||
hir::ExprKind::Type(expr, ty) => {
|
||||
self.word("type_ascribe!(");
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_expr(expr);
|
||||
|
||||
self.word(",");
|
||||
self.space_if_not_bol();
|
||||
self.print_type(ty);
|
||||
|
||||
self.end();
|
||||
self.end(ib);
|
||||
self.word(")");
|
||||
}
|
||||
hir::ExprKind::DropTemps(init) => {
|
||||
// Print `{`:
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(0);
|
||||
self.bopen();
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
let ib = self.ibox(0);
|
||||
self.bopen(ib);
|
||||
|
||||
// Print `let _t = $init;`:
|
||||
let temp = Ident::from_str("_t");
|
||||
|
|
@ -1509,7 +1523,7 @@ impl<'a> State<'a> {
|
|||
self.print_ident(temp);
|
||||
|
||||
// Print `}`:
|
||||
self.bclose_maybe_open(expr.span, true);
|
||||
self.bclose_maybe_open(expr.span, Some(cb));
|
||||
}
|
||||
hir::ExprKind::Let(&hir::LetExpr { pat, ty, init, .. }) => {
|
||||
self.print_let(pat, ty, init);
|
||||
|
|
@ -1522,20 +1536,20 @@ impl<'a> State<'a> {
|
|||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
self.head("loop");
|
||||
self.print_block(blk);
|
||||
let (cb, ib) = self.head("loop");
|
||||
self.print_block(blk, cb, ib);
|
||||
}
|
||||
hir::ExprKind::Match(expr, arms, _) => {
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.ibox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word_nbsp("match");
|
||||
self.print_expr_as_cond(expr);
|
||||
self.space();
|
||||
self.bopen();
|
||||
self.bopen(ib);
|
||||
for arm in arms {
|
||||
self.print_arm(arm);
|
||||
}
|
||||
self.bclose(expr.span);
|
||||
self.bclose(expr.span, cb);
|
||||
}
|
||||
hir::ExprKind::Closure(&hir::Closure {
|
||||
binder,
|
||||
|
|
@ -1558,12 +1572,15 @@ impl<'a> State<'a> {
|
|||
|
||||
// This is a bare expression.
|
||||
self.ann.nested(self, Nested::Body(body));
|
||||
self.end(); // need to close a box
|
||||
// FIXME(nnethercote): this is bogus
|
||||
let fake_ib = BoxMarker;
|
||||
self.end(fake_ib);
|
||||
|
||||
// A box will be closed by `print_expr`, but we didn't want an overall
|
||||
// wrapper so we closed the corresponding opening. so create an
|
||||
// empty box to satisfy the close.
|
||||
self.ibox(0);
|
||||
// FIXME(nnethercote): this is bogus, and `print_expr` is missing
|
||||
let _ib = self.ibox(0);
|
||||
}
|
||||
hir::ExprKind::Block(blk, opt_label) => {
|
||||
if let Some(label) = opt_label {
|
||||
|
|
@ -1571,10 +1588,10 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
}
|
||||
// containing cbox, will be closed by print-block at `}`
|
||||
self.cbox(0);
|
||||
let cb = self.cbox(0);
|
||||
// head-box, will be closed by print-block after `{`
|
||||
self.ibox(0);
|
||||
self.print_block(blk);
|
||||
let ib = self.ibox(0);
|
||||
self.print_block(blk, cb, ib);
|
||||
}
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
self.print_expr_cond_paren(lhs, lhs.precedence() <= ExprPrecedence::Assign);
|
||||
|
|
@ -1675,7 +1692,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Expr(expr));
|
||||
self.end()
|
||||
self.end(ib)
|
||||
}
|
||||
|
||||
fn print_local_decl(&mut self, loc: &hir::LetStmt<'_>) {
|
||||
|
|
@ -1866,6 +1883,19 @@ impl<'a> State<'a> {
|
|||
self.word("..=");
|
||||
self.print_const_arg(end);
|
||||
}
|
||||
TyPatKind::Or(patterns) => {
|
||||
self.popen();
|
||||
let mut first = true;
|
||||
for pat in patterns {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
self.word(" | ");
|
||||
}
|
||||
self.print_ty_pat(pat);
|
||||
}
|
||||
self.pclose();
|
||||
}
|
||||
TyPatKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
|
|
@ -2043,14 +2073,14 @@ impl<'a> State<'a> {
|
|||
if self.attrs(field.hir_id).is_empty() {
|
||||
self.space();
|
||||
}
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
self.print_attrs_as_outer(self.attrs(field.hir_id));
|
||||
if !field.is_shorthand {
|
||||
self.print_ident(field.ident);
|
||||
self.word_nbsp(":");
|
||||
}
|
||||
self.print_pat(field.pat);
|
||||
self.end();
|
||||
self.end(cb);
|
||||
}
|
||||
|
||||
fn print_param(&mut self, arg: &hir::Param<'_>) {
|
||||
|
|
@ -2086,9 +2116,9 @@ impl<'a> State<'a> {
|
|||
if self.attrs(arm.hir_id).is_empty() {
|
||||
self.space();
|
||||
}
|
||||
self.cbox(INDENT_UNIT);
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
self.ann.pre(self, AnnNode::Arm(arm));
|
||||
self.ibox(0);
|
||||
let ib = self.ibox(0);
|
||||
self.print_attrs_as_outer(self.attrs(arm.hir_id));
|
||||
self.print_pat(arm.pat);
|
||||
self.space();
|
||||
|
|
@ -2105,8 +2135,7 @@ impl<'a> State<'a> {
|
|||
self.print_ident(label.ident);
|
||||
self.word_space(":");
|
||||
}
|
||||
// the block will close the pattern's ibox
|
||||
self.print_block_unclosed(blk);
|
||||
self.print_block_unclosed(blk, ib);
|
||||
|
||||
// If it is a user-provided unsafe block, print a comma after it
|
||||
if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules
|
||||
|
|
@ -2115,13 +2144,13 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
self.end(); // close the ibox for the pattern
|
||||
self.end(ib);
|
||||
self.print_expr(arm.body);
|
||||
self.word(",");
|
||||
}
|
||||
}
|
||||
self.ann.post(self, AnnNode::Arm(arm));
|
||||
self.end() // close enclosing cbox
|
||||
self.end(cb)
|
||||
}
|
||||
|
||||
fn print_fn(
|
||||
|
|
@ -2167,9 +2196,9 @@ impl<'a> State<'a> {
|
|||
i += 1;
|
||||
};
|
||||
self.commasep(Inconsistent, decl.inputs, |s, ty| {
|
||||
s.ibox(INDENT_UNIT);
|
||||
let ib = s.ibox(INDENT_UNIT);
|
||||
print_arg(s, Some(ty));
|
||||
s.end();
|
||||
s.end(ib);
|
||||
});
|
||||
if decl.c_variadic {
|
||||
if !decl.inputs.is_empty() {
|
||||
|
|
@ -2188,7 +2217,7 @@ impl<'a> State<'a> {
|
|||
self.word("|");
|
||||
let mut i = 0;
|
||||
self.commasep(Inconsistent, decl.inputs, |s, ty| {
|
||||
s.ibox(INDENT_UNIT);
|
||||
let ib = s.ibox(INDENT_UNIT);
|
||||
|
||||
s.ann.nested(s, Nested::BodyParamPat(body_id, i));
|
||||
i += 1;
|
||||
|
|
@ -2200,7 +2229,7 @@ impl<'a> State<'a> {
|
|||
s.space();
|
||||
s.print_type(ty);
|
||||
}
|
||||
s.end();
|
||||
s.end(ib);
|
||||
});
|
||||
self.word("|");
|
||||
|
||||
|
|
@ -2442,16 +2471,16 @@ impl<'a> State<'a> {
|
|||
match decl.output {
|
||||
hir::FnRetTy::Return(ty) => {
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word_space("->");
|
||||
self.print_type(ty);
|
||||
}
|
||||
hir::FnRetTy::DefaultReturn(..) => return,
|
||||
}
|
||||
self.end();
|
||||
self.end(ib);
|
||||
|
||||
if let hir::FnRetTy::Return(output) = decl.output {
|
||||
self.maybe_print_comment(output.span.lo());
|
||||
if let hir::FnRetTy::Return(output) = decl.output {
|
||||
self.maybe_print_comment(output.span.lo());
|
||||
}
|
||||
}
|
||||
hir::FnRetTy::DefaultReturn(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2464,7 +2493,7 @@ impl<'a> State<'a> {
|
|||
generic_params: &[hir::GenericParam<'_>],
|
||||
arg_idents: &[Option<Ident>],
|
||||
) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.print_formal_generic_params(generic_params);
|
||||
let generics = hir::Generics::empty();
|
||||
self.print_fn(
|
||||
|
|
@ -2480,7 +2509,7 @@ impl<'a> State<'a> {
|
|||
arg_idents,
|
||||
None,
|
||||
);
|
||||
self.end();
|
||||
self.end(ib);
|
||||
}
|
||||
|
||||
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ rustc_macros = { path = "../rustc_macros" }
|
|||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@ hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len ->
|
|||
.help = use `transmute` if you're sure this is sound
|
||||
.label = unsupported cast
|
||||
|
||||
hir_typeck_register_type_unstable =
|
||||
type `{$ty}` cannot be used with this register class in stable
|
||||
|
||||
hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
|
||||
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
|
||||
hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_middle::ty::adjustment::{
|
|||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
|
@ -34,11 +34,9 @@ pub(crate) fn check_legal_trait_for_method_call(
|
|||
receiver: Option<Span>,
|
||||
expr_span: Span,
|
||||
trait_id: DefId,
|
||||
body_id: DefId,
|
||||
_body_id: DefId,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if tcx.is_lang_item(trait_id, LangItem::Drop)
|
||||
&& !tcx.is_lang_item(body_id, LangItem::FallbackSurfaceDrop)
|
||||
{
|
||||
if tcx.is_lang_item(trait_id, LangItem::Drop) {
|
||||
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
|
||||
errors::ExplicitDestructorCallSugg::Snippet {
|
||||
lo: expr_span.shrink_to_lo(),
|
||||
|
|
@ -89,14 +87,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let output = match result {
|
||||
None => {
|
||||
// this will report an error since original_callee_ty is not a fn
|
||||
self.confirm_builtin_call(
|
||||
call_expr,
|
||||
callee_expr,
|
||||
original_callee_ty,
|
||||
arg_exprs,
|
||||
expected,
|
||||
)
|
||||
// Check all of the arg expressions, but with no expectations
|
||||
// since we don't have a signature to compare them to.
|
||||
for arg in arg_exprs {
|
||||
self.check_expr(arg);
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
|
||||
&& let [segment] = path.segments
|
||||
{
|
||||
self.dcx().try_steal_modify_and_emit_err(
|
||||
segment.ident.span,
|
||||
StashKey::CallIntoMethod,
|
||||
|err| {
|
||||
// Try suggesting `foo(a)` -> `a.foo()` if possible.
|
||||
self.suggest_call_as_method(
|
||||
err, segment, arg_exprs, call_expr, expected,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let guar = self.report_invalid_callee(call_expr, callee_expr, expr_ty, arg_exprs);
|
||||
Ty::new_error(self.tcx, guar)
|
||||
}
|
||||
|
||||
Some(CallStep::Builtin(callee_ty)) => {
|
||||
|
|
@ -298,9 +311,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
|
||||
});
|
||||
|
||||
if let Some(ok) = self.lookup_method_in_trait(
|
||||
if let Some(ok) = self.lookup_method_for_operator(
|
||||
self.misc(call_expr.span),
|
||||
Ident::with_dummy_span(method_name),
|
||||
method_name,
|
||||
trait_def_id,
|
||||
adjusted_ty,
|
||||
opt_input_type,
|
||||
|
|
@ -463,32 +476,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
(fn_sig, Some(def_id))
|
||||
}
|
||||
|
||||
// FIXME(const_trait_impl): these arms should error because we can't enforce them
|
||||
ty::FnPtr(sig_tys, hdr) => (sig_tys.with(hdr), None),
|
||||
_ => {
|
||||
for arg in arg_exprs {
|
||||
self.check_expr(arg);
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
|
||||
&& let [segment] = path.segments
|
||||
{
|
||||
self.dcx().try_steal_modify_and_emit_err(
|
||||
segment.ident.span,
|
||||
StashKey::CallIntoMethod,
|
||||
|err| {
|
||||
// Try suggesting `foo(a)` -> `a.foo()` if possible.
|
||||
self.suggest_call_as_method(
|
||||
err, segment, arg_exprs, call_expr, expected,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
|
||||
|
||||
return Ty::new_error(self.tcx, err);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Replace any late-bound regions that appear in the function
|
||||
|
|
@ -910,19 +902,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
arg_exprs: &'tcx [hir::Expr<'tcx>],
|
||||
expected: Expectation<'tcx>,
|
||||
method_callee: MethodCallee<'tcx>,
|
||||
method: MethodCallee<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let output_type = self.check_method_argument_types(
|
||||
self.check_argument_types(
|
||||
call_expr.span,
|
||||
call_expr,
|
||||
Ok(method_callee),
|
||||
arg_exprs,
|
||||
TupleArgumentsFlag::TupleArguments,
|
||||
&method.sig.inputs()[1..],
|
||||
method.sig.output(),
|
||||
expected,
|
||||
arg_exprs,
|
||||
method.sig.c_variadic,
|
||||
TupleArgumentsFlag::TupleArguments,
|
||||
Some(method.def_id),
|
||||
);
|
||||
|
||||
self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method_callee);
|
||||
output_type
|
||||
self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method);
|
||||
|
||||
method.sig.output()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -963,3 +963,11 @@ pub(crate) enum SupertraitItemShadowee {
|
|||
traits: DiagSymbolList,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_register_type_unstable)]
|
||||
pub(crate) struct RegisterTypeUnstable<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ use tracing::{debug, instrument, trace};
|
|||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use crate::TupleArgumentsFlag::DontTupleArguments;
|
||||
use crate::coercion::{CoerceMany, DynamicCoerceMany};
|
||||
use crate::errors::{
|
||||
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
|
||||
|
|
@ -51,8 +50,8 @@ use crate::errors::{
|
|||
YieldExprOutsideOfCoroutine,
|
||||
};
|
||||
use crate::{
|
||||
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust,
|
||||
report_unexpected_variant_res, type_error_struct,
|
||||
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast,
|
||||
fatally_break_rust, report_unexpected_variant_res, type_error_struct,
|
||||
};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
|
@ -1591,28 +1590,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// no need to check for bot/err -- callee does that
|
||||
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
|
||||
|
||||
let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args)
|
||||
{
|
||||
match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) {
|
||||
Ok(method) => {
|
||||
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
||||
// trigger this codepath causing `structurally_resolve_type` to emit an error.
|
||||
self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
|
||||
Ok(method)
|
||||
|
||||
self.check_argument_types(
|
||||
segment.ident.span,
|
||||
expr,
|
||||
&method.sig.inputs()[1..],
|
||||
method.sig.output(),
|
||||
expected,
|
||||
args,
|
||||
method.sig.c_variadic,
|
||||
TupleArgumentsFlag::DontTupleArguments,
|
||||
Some(method.def_id),
|
||||
);
|
||||
|
||||
method.sig.output()
|
||||
}
|
||||
Err(error) => {
|
||||
Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
|
||||
}
|
||||
};
|
||||
let guar = self.report_method_error(expr.hir_id, rcvr_t, error, expected, false);
|
||||
|
||||
// Call the generic checker.
|
||||
self.check_method_argument_types(
|
||||
segment.ident.span,
|
||||
expr,
|
||||
method,
|
||||
args,
|
||||
DontTupleArguments,
|
||||
expected,
|
||||
)
|
||||
let err_inputs = self.err_args(args.len(), guar);
|
||||
let err_output = Ty::new_error(self.tcx, guar);
|
||||
|
||||
self.check_argument_types(
|
||||
segment.ident.span,
|
||||
expr,
|
||||
&err_inputs,
|
||||
err_output,
|
||||
NoExpectation,
|
||||
args,
|
||||
false,
|
||||
TupleArgumentsFlag::DontTupleArguments,
|
||||
None,
|
||||
);
|
||||
|
||||
err_output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks use `x.use`.
|
||||
|
|
|
|||
|
|
@ -1000,13 +1000,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// determines whether to borrow *at the level of the deref pattern* rather than
|
||||
// borrowing the bound place (since that inner place is inside the temporary that
|
||||
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
|
||||
// Deref patterns on boxes don't borrow, so we ignore them here.
|
||||
// HACK: this could be a fake pattern corresponding to a deref inserted by match
|
||||
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
|
||||
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
|
||||
let mutability =
|
||||
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
let bk = ty::BorrowKind::from_mutbl(mutability);
|
||||
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
|
||||
if let hir::ByRef::Yes(mutability) =
|
||||
self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
|
||||
{
|
||||
let bk = ty::BorrowKind::from_mutbl(mutability);
|
||||
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
|
||||
}
|
||||
}
|
||||
PatKind::Never => {
|
||||
// A `!` pattern always counts as an immutable read of the discriminant,
|
||||
|
|
@ -1691,18 +1693,19 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
place_with_id = match adjust.kind {
|
||||
adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?,
|
||||
adjustment::PatAdjust::OverloadedDeref => {
|
||||
// This adjustment corresponds to an overloaded deref; it borrows the scrutinee to
|
||||
// call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting
|
||||
// `place_with_id` to the temporary storing the result of the deref.
|
||||
// This adjustment corresponds to an overloaded deref; unless it's on a box, it
|
||||
// borrows the scrutinee to call `Deref::deref` or `DerefMut::deref_mut`. Invoke
|
||||
// the callback before setting `place_with_id` to the temporary storing the
|
||||
// result of the deref.
|
||||
// HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
|
||||
// same as it would if this were an explicit deref pattern.
|
||||
// same as it would if this were an explicit deref pattern (including for boxes).
|
||||
op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?;
|
||||
let target_ty = match adjusts.peek() {
|
||||
Some(&&next_adjust) => next_adjust.source,
|
||||
// At the end of the deref chain, we get `pat`'s scrutinee.
|
||||
None => self.pat_ty_unadjusted(pat)?,
|
||||
};
|
||||
self.pat_deref_temp(pat.hir_id, pat, target_ty)?
|
||||
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1810,7 +1813,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
PatKind::Deref(subpat) => {
|
||||
let ty = self.pat_ty_adjusted(subpat)?;
|
||||
let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?;
|
||||
let place = self.pat_deref_place(pat.hir_id, place_with_id, subpat, ty)?;
|
||||
self.cat_pattern(place, subpat, op)?;
|
||||
}
|
||||
|
||||
|
|
@ -1863,21 +1866,27 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Represents the place of the temp that stores the scrutinee of a deref pattern's interior.
|
||||
fn pat_deref_temp(
|
||||
/// Represents the place matched on by a deref pattern's interior.
|
||||
fn pat_deref_place(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
base_place: PlaceWithHirId<'tcx>,
|
||||
inner: &hir::Pat<'_>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
|
||||
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner);
|
||||
let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
|
||||
let re_erased = self.cx.tcx().lifetimes.re_erased;
|
||||
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
|
||||
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
|
||||
let base = self.cat_rvalue(hir_id, ty);
|
||||
// ... and the inner pattern matches on the place behind that reference.
|
||||
self.cat_deref(hir_id, base)
|
||||
match self.cx.typeck_results().deref_pat_borrow_mode(base_place.place.ty(), inner) {
|
||||
// Deref patterns on boxes are lowered using a built-in deref.
|
||||
hir::ByRef::No => self.cat_deref(hir_id, base_place),
|
||||
// For other types, we create a temporary to match on.
|
||||
hir::ByRef::Yes(mutability) => {
|
||||
let re_erased = self.cx.tcx().lifetimes.re_erased;
|
||||
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
|
||||
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
|
||||
let base = self.cat_rvalue(hir_id, ty);
|
||||
// ... and the inner pattern matches on the place behind that reference.
|
||||
self.cat_deref(hir_id, base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{ExprKind, HirId, Node, QPath};
|
||||
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
|
||||
use rustc_hir_analysis::check::potentially_plural_count;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_index::IndexVec;
|
||||
|
|
@ -33,7 +32,7 @@ use crate::errors::SuggestPtrNullMut;
|
|||
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
|
||||
use crate::fn_ctxt::infer::FnCall;
|
||||
use crate::gather_locals::Declaration;
|
||||
use crate::method::MethodCallee;
|
||||
use crate::inline_asm::InlineAsmCtxt;
|
||||
use crate::method::probe::IsSuggestion;
|
||||
use crate::method::probe::Mode::MethodCall;
|
||||
use crate::method::probe::ProbeScope::TraitsInScope;
|
||||
|
|
@ -98,13 +97,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
|
||||
for (asm, hir_id) in deferred_asm_checks.drain(..) {
|
||||
let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
|
||||
InlineAsmCtxt::new(
|
||||
enclosing_id,
|
||||
&self.infcx,
|
||||
self.typing_env(self.param_env),
|
||||
&*self.typeck_results.borrow(),
|
||||
)
|
||||
.check_asm(asm);
|
||||
InlineAsmCtxt::new(self, enclosing_id).check_asm(asm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,61 +126,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_method_argument_types(
|
||||
&self,
|
||||
sp: Span,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
method: Result<MethodCallee<'tcx>, ErrorGuaranteed>,
|
||||
args_no_rcvr: &'tcx [hir::Expr<'tcx>],
|
||||
tuple_arguments: TupleArgumentsFlag,
|
||||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let has_error = match method {
|
||||
Ok(method) => method.args.error_reported().and(method.sig.error_reported()),
|
||||
Err(guar) => Err(guar),
|
||||
};
|
||||
if let Err(guar) = has_error {
|
||||
let err_inputs = self.err_args(
|
||||
method.map_or(args_no_rcvr.len(), |method| method.sig.inputs().len() - 1),
|
||||
guar,
|
||||
);
|
||||
let err_output = Ty::new_error(self.tcx, guar);
|
||||
|
||||
let err_inputs = match tuple_arguments {
|
||||
DontTupleArguments => err_inputs,
|
||||
TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)],
|
||||
};
|
||||
|
||||
self.check_argument_types(
|
||||
sp,
|
||||
expr,
|
||||
&err_inputs,
|
||||
err_output,
|
||||
NoExpectation,
|
||||
args_no_rcvr,
|
||||
false,
|
||||
tuple_arguments,
|
||||
method.ok().map(|method| method.def_id),
|
||||
);
|
||||
return err_output;
|
||||
}
|
||||
|
||||
let method = method.unwrap();
|
||||
self.check_argument_types(
|
||||
sp,
|
||||
expr,
|
||||
&method.sig.inputs()[1..],
|
||||
method.sig.output(),
|
||||
expected,
|
||||
args_no_rcvr,
|
||||
method.sig.c_variadic,
|
||||
tuple_arguments,
|
||||
Some(method.def_id),
|
||||
);
|
||||
|
||||
method.sig.output()
|
||||
}
|
||||
|
||||
/// Generic function that factors out common logic from function calls,
|
||||
/// method calls and overloaded operators.
|
||||
pub(in super::super) fn check_argument_types(
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(*adt_def),
|
||||
// FIXME(#104767): Should we handle bound regions here?
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _)
|
||||
ty::Alias(ty::Projection | ty::Inherent | ty::Free, _)
|
||||
if !ty.has_escaping_bound_vars() =>
|
||||
{
|
||||
if self.next_trait_solver() {
|
||||
|
|
@ -357,7 +357,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
|||
// WF obligations that are registered elsewhere, but they have a
|
||||
// better cause code assigned to them in `add_required_obligations_for_hir`.
|
||||
// This means that they should shadow obligations with worse spans.
|
||||
if let ty::Alias(ty::Projection | ty::Weak, ty::AliasTy { args, def_id, .. }) =
|
||||
if let ty::Alias(ty::Projection | ty::Free, ty::AliasTy { args, def_id, .. }) =
|
||||
ty.kind()
|
||||
{
|
||||
self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
|
||||
|
|
|
|||
|
|
@ -3,25 +3,22 @@ use rustc_ast::InlineAsmTemplatePiece;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, TypeckResults, UintTy,
|
||||
};
|
||||
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_target::asm::{
|
||||
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
|
||||
};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
use crate::FnCtxt;
|
||||
use crate::errors::RegisterTypeUnstable;
|
||||
|
||||
pub struct InlineAsmCtxt<'a, 'tcx> {
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
pub(crate) struct InlineAsmCtxt<'a, 'tcx> {
|
||||
target_features: &'tcx FxIndexSet<Symbol>,
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
typeck_results: &'a TypeckResults<'tcx>,
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
enum NonAsmTypeReason<'tcx> {
|
||||
|
|
@ -33,27 +30,17 @@ enum NonAsmTypeReason<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||
pub fn new(
|
||||
def_id: LocalDefId,
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
typeck_results: &'a TypeckResults<'tcx>,
|
||||
) -> Self {
|
||||
InlineAsmCtxt {
|
||||
typing_env,
|
||||
target_features: infcx.tcx.asm_target_features(def_id),
|
||||
infcx,
|
||||
typeck_results,
|
||||
}
|
||||
pub(crate) fn new(fcx: &'a FnCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
|
||||
InlineAsmCtxt { target_features: fcx.tcx.asm_target_features(def_id), fcx }
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
self.fcx.tcx
|
||||
}
|
||||
|
||||
fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
|
||||
let ty = self.typeck_results.expr_ty_adjusted(expr);
|
||||
let ty = self.infcx.resolve_vars_if_possible(ty);
|
||||
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted(expr);
|
||||
let ty = self.fcx.try_structurally_resolve_type(expr.span, ty);
|
||||
if ty.has_non_region_infer() {
|
||||
Ty::new_misc_error(self.tcx())
|
||||
} else {
|
||||
|
|
@ -62,19 +49,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
|
||||
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
|
||||
fn is_thin_ptr_ty(&self, span: Span, ty: Ty<'tcx>) -> bool {
|
||||
// Type still may have region variables, but `Sized` does not depend
|
||||
// on those, so just erase them before querying.
|
||||
if ty.is_sized(self.tcx(), self.typing_env) {
|
||||
if self.fcx.type_is_sized_modulo_regions(self.fcx.param_env, ty) {
|
||||
return true;
|
||||
}
|
||||
if let ty::Foreign(..) = ty.kind() {
|
||||
if let ty::Foreign(..) = self.fcx.try_structurally_resolve_type(span, ty).kind() {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
|
||||
fn get_asm_ty(
|
||||
&self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
|
||||
let asm_ty_isize = match self.tcx().sess.target.pointer_width {
|
||||
16 => InlineAsmType::I16,
|
||||
32 => InlineAsmType::I32,
|
||||
|
|
@ -95,7 +86,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128),
|
||||
ty::FnPtr(..) => Ok(asm_ty_isize),
|
||||
ty::RawPtr(elem_ty, _) => {
|
||||
if self.is_thin_ptr_ty(elem_ty) {
|
||||
if self.is_thin_ptr_ty(span, elem_ty) {
|
||||
Ok(asm_ty_isize)
|
||||
} else {
|
||||
Err(NonAsmTypeReason::NotSizedPtr(ty))
|
||||
|
|
@ -109,11 +100,20 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
let field = &fields[FieldIdx::ZERO];
|
||||
let elem_ty = field.ty(self.tcx(), args);
|
||||
|
||||
let (size, ty) = match elem_ty.kind() {
|
||||
let (size, ty) = match *elem_ty.kind() {
|
||||
ty::Array(ty, len) => {
|
||||
let len = self.tcx().normalize_erasing_regions(self.typing_env, *len);
|
||||
// FIXME: `try_structurally_resolve_const` doesn't eval consts
|
||||
// in the old solver.
|
||||
let len = if self.fcx.next_trait_solver() {
|
||||
self.fcx.try_structurally_resolve_const(span, len)
|
||||
} else {
|
||||
self.fcx.tcx.normalize_erasing_regions(
|
||||
self.fcx.typing_env(self.fcx.param_env),
|
||||
len,
|
||||
)
|
||||
};
|
||||
if let Some(len) = len.try_to_target_usize(self.tcx()) {
|
||||
(len, *ty)
|
||||
(len, ty)
|
||||
} else {
|
||||
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
|
||||
field.did, len,
|
||||
|
|
@ -183,9 +183,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
);
|
||||
let fields = &ty.non_enum_variant().fields;
|
||||
let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args);
|
||||
self.get_asm_ty(ty)
|
||||
self.get_asm_ty(expr.span, ty)
|
||||
}
|
||||
_ => self.get_asm_ty(ty),
|
||||
_ => self.get_asm_ty(expr.span, ty),
|
||||
};
|
||||
let asm_ty = match asm_ty {
|
||||
Ok(asm_ty) => asm_ty,
|
||||
|
|
@ -193,7 +193,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
match reason {
|
||||
NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => {
|
||||
let msg = format!("cannot evaluate SIMD vector length `{len}`");
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(self.tcx().def_span(did), msg)
|
||||
.with_span_note(
|
||||
|
|
@ -204,7 +204,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
NonAsmTypeReason::Invalid(ty) => {
|
||||
let msg = format!("cannot use value of type `{ty}` for inline assembly");
|
||||
self.infcx.dcx().struct_span_err(expr.span, msg).with_note(
|
||||
self.fcx.dcx().struct_span_err(expr.span, msg).with_note(
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
can be used as arguments for inline assembly",
|
||||
).emit();
|
||||
|
|
@ -213,7 +213,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
let msg = format!(
|
||||
"cannot use value of unsized pointer type `{ty}` for inline assembly"
|
||||
);
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(expr.span, msg)
|
||||
.with_note("only sized pointers can be used in inline assembly")
|
||||
|
|
@ -223,7 +223,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
let msg = format!(
|
||||
"cannot use SIMD vector with element type `{ty}` for inline assembly"
|
||||
);
|
||||
self.infcx.dcx()
|
||||
self.fcx.dcx()
|
||||
.struct_span_err(self.tcx().def_span(did), msg).with_span_note(
|
||||
expr.span,
|
||||
"only integers, floats, SIMD vectors, pointers and function pointers \
|
||||
|
|
@ -232,7 +232,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
NonAsmTypeReason::EmptySIMDArray(ty) => {
|
||||
let msg = format!("use of empty SIMD vector `{ty}`");
|
||||
self.infcx.dcx().struct_span_err(expr.span, msg).emit();
|
||||
self.fcx.dcx().struct_span_err(expr.span, msg).emit();
|
||||
}
|
||||
}
|
||||
return None;
|
||||
|
|
@ -241,9 +241,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
|
||||
// Check that the type implements Copy. The only case where this can
|
||||
// possibly fail is for SIMD types which don't #[derive(Copy)].
|
||||
if !self.tcx().type_is_copy_modulo_regions(self.typing_env, ty) {
|
||||
if !self.fcx.type_is_copy_modulo_regions(self.fcx.param_env, ty) {
|
||||
let msg = "arguments for inline assembly must be copyable";
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(expr.span, msg)
|
||||
.with_note(format!("`{ty}` does not implement the Copy trait"))
|
||||
|
|
@ -263,7 +263,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
if in_asm_ty != asm_ty {
|
||||
let msg = "incompatible types for asm inout argument";
|
||||
let in_expr_ty = self.expr_ty(in_expr);
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(vec![in_expr.span, expr.span], msg)
|
||||
.with_span_label(in_expr.span, format!("type `{in_expr_ty}`"))
|
||||
|
|
@ -296,7 +296,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
)
|
||||
} else {
|
||||
let msg = format!("type `{ty}` cannot be used with this register class");
|
||||
let mut err = self.infcx.dcx().struct_span_err(expr.span, msg);
|
||||
let mut err = self.fcx.dcx().struct_span_err(expr.span, msg);
|
||||
let supported_tys: Vec<_> =
|
||||
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
|
||||
err.note(format!(
|
||||
|
|
@ -326,7 +326,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
if let Some(feature) = feature {
|
||||
if !self.target_features.contains(feature) {
|
||||
let msg = format!("`{feature}` target feature is not enabled");
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(expr.span, msg)
|
||||
.with_note(format!(
|
||||
|
|
@ -384,9 +384,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
Some(asm_ty)
|
||||
}
|
||||
|
||||
pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
|
||||
pub(crate) fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
|
||||
let Some(asm_arch) = self.tcx().sess.asm_arch else {
|
||||
self.infcx.dcx().delayed_bug("target architecture does not support asm");
|
||||
self.fcx.dcx().delayed_bug("target architecture does not support asm");
|
||||
return;
|
||||
};
|
||||
let allow_experimental_reg = self.tcx().features().asm_experimental_reg();
|
||||
|
|
@ -418,7 +418,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
op.is_clobber(),
|
||||
) {
|
||||
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
|
||||
self.infcx.dcx().span_err(op_sp, msg);
|
||||
self.fcx.dcx().span_err(op_sp, msg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +458,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
reg_class.name(),
|
||||
feature
|
||||
);
|
||||
self.infcx.dcx().span_err(op_sp, msg);
|
||||
self.fcx.dcx().span_err(op_sp, msg);
|
||||
// register isn't enabled, don't do more checks
|
||||
continue;
|
||||
}
|
||||
|
|
@ -472,7 +472,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
.intersperse(", ")
|
||||
.collect::<String>(),
|
||||
);
|
||||
self.infcx.dcx().span_err(op_sp, msg);
|
||||
self.fcx.dcx().span_err(op_sp, msg);
|
||||
// register isn't enabled, don't do more checks
|
||||
continue;
|
||||
}
|
||||
|
|
@ -512,7 +512,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
ty::Error(_) => {}
|
||||
_ if ty.is_integral() => {}
|
||||
_ => {
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(op_sp, "invalid type for `const` operand")
|
||||
.with_span_label(
|
||||
|
|
@ -531,7 +531,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
ty::FnDef(..) => {}
|
||||
ty::Error(_) => {}
|
||||
_ => {
|
||||
self.infcx
|
||||
self.fcx
|
||||
.dcx()
|
||||
.struct_span_err(op_sp, "invalid `sym` operand")
|
||||
.with_span_label(
|
||||
|
|
@ -23,6 +23,7 @@ mod diverges;
|
|||
mod errors;
|
||||
mod expectation;
|
||||
mod expr;
|
||||
mod inline_asm;
|
||||
// Used by clippy;
|
||||
pub mod expr_use_visitor;
|
||||
mod fallback;
|
||||
|
|
|
|||
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