Merge from rustc

This commit is contained in:
The rustc-dev-guide Cronjob Bot 2025-05-01 04:05:49 +00:00
commit 560de7e512
1844 changed files with 46923 additions and 47824 deletions

View file

@ -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",

View file

@ -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

View file

@ -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

View file

@ -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),
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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);

View file

@ -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()

View file

@ -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 =

View file

@ -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),
};

View file

@ -2,6 +2,7 @@
#![allow(internal_features)]
#![doc(rust_logo)]
#![feature(box_patterns)]
#![feature(negative_impls)]
#![feature(rustdoc_internals)]
// tidy-alphabetical-end

View file

@ -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) {

View file

@ -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 {

View file

@ -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,
&macro_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 {

View file

@ -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) {

View file

@ -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);
}
}
}

View file

@ -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);
})
}

View file

@ -80,6 +80,7 @@
#![cfg_attr(bootstrap, feature(let_chains))]
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
#![recursion_limit = "256"]
// tidy-alphabetical-end
#[macro_use]

View file

@ -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: {:?}",

View file

@ -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(

View file

@ -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);
}

View file

@ -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,

View file

@ -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;

View file

@ -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)
}

View file

@ -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() {

View file

@ -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);
}

View file

@ -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,
);
}
}
}

View file

@ -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);
});
}

View file

@ -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");
}
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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,

View file

@ -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

View file

@ -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>>,

View file

@ -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 {

View file

@ -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,
}
}

View file

@ -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,

View file

@ -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> {

View file

@ -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) {

View file

@ -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

View file

@ -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);

View file

@ -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> {

View file

@ -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);

View file

@ -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

View file

@ -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>(

View file

@ -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" {

View file

@ -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,

View file

@ -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() {

View file

@ -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
}

View file

@ -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.

View file

@ -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>>(

View file

@ -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.

View file

@ -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>,

View file

@ -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(

View file

@ -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,

View file

@ -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();

View file

@ -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);
}
}
}

View file

@ -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,

View file

@ -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) {}

View file

@ -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)?,

View file

@ -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.

View file

@ -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)?;
}

View file

@ -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.

View file

@ -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 {

View file

@ -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) => {}
}
}
_ => {

View file

@ -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`"),
}

View file

@ -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};

View file

@ -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

View file

@ -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(),
),
)
}

View file

@ -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,

View file

@ -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 {

View file

@ -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`."

View file

@ -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.

View file

@ -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),
}

View file

@ -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()

View file

@ -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.

View file

@ -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;

View file

@ -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"

View file

@ -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 =

View file

@ -67,7 +67,6 @@ mod check;
mod compare_impl_item;
mod entry;
pub mod intrinsic;
pub mod intrinsicck;
mod region;
pub mod wfcheck;

View file

@ -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 {

View file

@ -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(_) => {

View file

@ -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",

View file

@ -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)
}

View file

@ -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)),
_ => {}

View file

@ -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 {

View file

@ -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> {

View file

@ -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,

View file

@ -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(

View file

@ -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) {

View file

@ -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"

View file

@ -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

View file

@ -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()
}
}

View file

@ -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>,
}

View file

@ -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`.

View file

@ -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 {

View file

@ -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(

View file

@ -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);

View file

@ -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(

View file

@ -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