Auto merge of #3602 - RalfJung:rustup, r=RalfJung

Rustup
This commit is contained in:
bors 2024-05-12 13:47:29 +00:00
commit 75d531d18c
546 changed files with 9071 additions and 5306 deletions

View file

@ -56,7 +56,7 @@ jobs:
- name: install the bootstrap toolchain
run: |
# Extract the stage0 version
TOOLCHAIN=$(jq -r '.compiler | {version,date} | join("-")' -- src/stage0.json)
TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0)
# Install and set as default
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
rustup default $TOOLCHAIN

File diff suppressed because it is too large Load diff

View file

@ -1255,7 +1255,7 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
/// Gets source indices of the fields by increasing offsets.
#[inline]
pub fn index_by_increasing_offset(&self) -> impl Iterator<Item = usize> + '_ {
pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> + '_ {
let mut inverse_small = [0u8; 64];
let mut inverse_big = IndexVec::new();
let use_small = self.count() <= inverse_small.len();
@ -1271,7 +1271,12 @@ impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
}
}
(0..self.count()).map(move |i| match *self {
// Primitives don't really have fields in the way that structs do,
// but having this return an empty iterator for them is unhelpful
// since that makes them look kinda like ZSTs, which they're not.
let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
(0..pseudofield_count).map(move |i| match *self {
FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
FieldsShape::Arbitrary { .. } => {
if use_small {

View file

@ -3250,6 +3250,7 @@ pub enum ItemKind {
}
impl ItemKind {
/// "a" or "an"
pub fn article(&self) -> &'static str {
use ItemKind::*;
match self {

View file

@ -240,7 +240,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtPath(path) => path.tokens(),
Nonterminal::NtVis(vis) => vis.tokens(),
Nonterminal::NtBlock(block) => block.tokens(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
@ -254,7 +253,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
}

View file

@ -345,7 +345,7 @@ impl MetaItem {
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
Path { span, segments, tokens: None }
}
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(path) => (**path).clone(),
_ => return None,

View file

@ -781,10 +781,14 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
*span = ident.span;
return; // Avoid visiting the span for the second time.
}
token::NtIdent(ident, _is_raw) => {
vis.visit_ident(ident);
}
token::NtLifetime(ident) => {
vis.visit_ident(ident);
}
token::Interpolated(nt) => {
let nt = Lrc::make_mut(nt);
let (nt, sp) = (&mut nt.0, &mut nt.1);
vis.visit_span(sp);
visit_nonterminal(nt, vis);
}
_ => {}
@ -834,8 +838,6 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
token::NtPat(pat) => vis.visit_pat(pat),
token::NtExpr(expr) => vis.visit_expr(expr),
token::NtTy(ty) => vis.visit_ty(ty),
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut();

View file

@ -111,7 +111,7 @@ impl Lit {
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
Literal(token_lit) => Some(token_lit),
Interpolated(ref nt)
if let NtExpr(expr) | NtLiteral(expr) = &nt.0
if let NtExpr(expr) | NtLiteral(expr) = &**nt
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
{
Some(token_lit)
@ -318,11 +318,20 @@ pub enum TokenKind {
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated identifiers in the same way.
Ident(Symbol, IdentIsRaw),
/// This identifier (and its span) is the identifier passed to the
/// declarative macro. The span in the surrounding `Token` is the span of
/// the `ident` metavariable in the macro's RHS.
NtIdent(Ident, IdentIsRaw),
/// Lifetime identifier token.
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated lifetime identifiers in the same way.
Lifetime(Symbol),
/// This identifier (and its span) is the lifetime passed to the
/// declarative macro. The span in the surrounding `Token` is the span of
/// the `lifetime` metavariable in the macro's RHS.
NtLifetime(Ident),
/// An embedded AST node, as produced by a macro. This only exists for
/// historical reasons. We'd like to get rid of it, for multiple reasons.
@ -333,7 +342,11 @@ pub enum TokenKind {
/// - It prevents `Token` from implementing `Copy`.
/// It adds complexity and likely slows things down. Please don't add new
/// occurrences of this token kind!
Interpolated(Lrc<(Nonterminal, Span)>),
///
/// The span in the surrounding `Token` is that of the metavariable in the
/// macro's RHS. The span within the Nonterminal is that of the fragment
/// passed to the macro at the call site.
Interpolated(Lrc<Nonterminal>),
/// A doc comment token.
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
@ -440,8 +453,9 @@ impl Token {
/// Note that keywords are also identifiers, so they should use this
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
match &self.kind {
Interpolated(nt) => nt.0.use_span(),
match self.kind {
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
Interpolated(ref nt) => nt.use_span(),
_ => self.span,
}
}
@ -459,7 +473,7 @@ impl Token {
}
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | Eof => false,
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
}
}
@ -486,7 +500,7 @@ impl Token {
PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
NtPath(..)),
@ -510,7 +524,7 @@ impl Token {
| DotDot | DotDotDot | DotDotEq // ranges
| Lt | BinOp(Shl) // associated path
| PathSep => true, // global path
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
NtPat(..) |
NtBlock(..) |
NtPath(..)),
@ -533,7 +547,7 @@ impl Token {
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
PathSep => true, // global path
Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
// For anonymous structs or unions, which only appear in specific positions
// (type of struct fields or union fields), we don't consider them as regular types
_ => false,
@ -544,7 +558,7 @@ impl Token {
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Delimiter::Brace) => true,
Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
_ => self.can_begin_literal_maybe_minus(),
}
}
@ -589,7 +603,7 @@ impl Token {
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
Interpolated(ref nt) => match &nt.0 {
Interpolated(ref nt) => match &**nt {
NtLiteral(_) => true,
NtExpr(e) => match &e.kind {
ast::ExprKind::Lit(_) => true,
@ -609,14 +623,9 @@ impl Token {
/// into the regular identifier or lifetime token it refers to,
/// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
Interpolated(nt) => match &nt.0 {
NtIdent(ident, is_raw) => {
Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
}
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
},
match self.kind {
NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
}
}
@ -625,12 +634,9 @@ impl Token {
#[inline]
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
// We avoid using `Token::uninterpolate` here because it's slow.
match &self.kind {
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
Interpolated(nt) => match &nt.0 {
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
_ => None,
},
match self.kind {
Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
NtIdent(ident, is_raw) => Some((ident, is_raw)),
_ => None,
}
}
@ -639,12 +645,9 @@ impl Token {
#[inline]
pub fn lifetime(&self) -> Option<Ident> {
// We avoid using `Token::uninterpolate` here because it's slow.
match &self.kind {
&Lifetime(name) => Some(Ident::new(name, self.span)),
Interpolated(nt) => match &nt.0 {
NtLifetime(ident) => Some(*ident),
_ => None,
},
match self.kind {
Lifetime(name) => Some(Ident::new(name, self.span)),
NtLifetime(ident) => Some(ident),
_ => None,
}
}
@ -668,7 +671,7 @@ impl Token {
/// Returns `true` if the token is an interpolated path.
fn is_whole_path(&self) -> bool {
if let Interpolated(nt) = &self.kind
&& let NtPath(..) = &nt.0
&& let NtPath(..) = &**nt
{
return true;
}
@ -681,7 +684,7 @@ impl Token {
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
if let Interpolated(nt) = &self.kind
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt
{
return true;
}
@ -692,7 +695,7 @@ impl Token {
/// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool {
if let Interpolated(nt) = &self.kind
&& let NtBlock(..) = &nt.0
&& let NtBlock(..) = &**nt
{
return true;
}
@ -833,8 +836,10 @@ impl Token {
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
| DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
| Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => {
return None;
}
};
Some(Token::new(kind, self.span.to(joint.span)))
@ -857,8 +862,6 @@ pub enum Nonterminal {
NtPat(P<ast::Pat>),
NtExpr(P<ast::Expr>),
NtTy(P<ast::Ty>),
NtIdent(Ident, IdentIsRaw),
NtLifetime(Ident),
NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
@ -953,7 +956,6 @@ impl Nonterminal {
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
@ -969,8 +971,6 @@ impl Nonterminal {
NtExpr(..) => "expression",
NtLiteral(..) => "literal",
NtTy(..) => "type",
NtIdent(..) => "identifier",
NtLifetime(..) => "lifetime",
NtMeta(..) => "attribute",
NtPath(..) => "path",
NtVis(..) => "visibility",
@ -979,18 +979,12 @@ impl Nonterminal {
}
impl PartialEq for Nonterminal {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
}
(NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
// FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
// attached token stream from which it was parsed.
_ => false,
}
fn eq(&self, _rhs: &Self) -> bool {
// FIXME: Assume that all nonterminals are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
// attached token stream from which it was parsed.
false
}
}
@ -1003,12 +997,10 @@ impl fmt::Debug for Nonterminal {
NtPat(..) => f.pad("NtPat(..)"),
NtExpr(..) => f.pad("NtExpr(..)"),
NtTy(..) => f.pad("NtTy(..)"),
NtIdent(..) => f.pad("NtIdent(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtVis(..) => f.pad("NtVis(..)"),
NtLifetime(..) => f.pad("NtLifetime(..)"),
}
}
}

View file

@ -466,12 +466,6 @@ impl TokenStream {
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt {
Nonterminal::NtIdent(ident, is_raw) => {
TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
}
Nonterminal::NtLifetime(ident) => {
TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
}
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
@ -489,15 +483,21 @@ impl TokenStream {
}
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
match &token.kind {
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
match token.kind {
token::NtIdent(ident, is_raw) => {
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
}
token::Interpolated(nt) => TokenTree::Delimited(
token::NtLifetime(ident) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
TokenStream::from_nonterminal_ast(&nt.0).flattened(),
TokenStream::token_alone(token::Lifetime(ident.name), ident.span),
),
token::Interpolated(ref nt) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
TokenStream::from_nonterminal_ast(&nt).flattened(),
),
_ => TokenTree::Token(token.clone(), spacing),
}
@ -516,7 +516,10 @@ impl TokenStream {
pub fn flattened(&self) -> TokenStream {
fn can_skip(stream: &TokenStream) -> bool {
stream.trees().all(|tree| match tree {
TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)),
TokenTree::Token(token, _) => !matches!(
token.kind,
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
),
TokenTree::Delimited(.., inner) => can_skip(inner),
})
}

View file

@ -1,34 +1,88 @@
//! Routines the parser uses to classify AST nodes
// Predicates on exprs and stmts that the pretty-printer and parser use
//! Routines the parser and pretty-printer use to classify AST nodes.
use crate::ast::ExprKind::*;
use crate::{ast, token::Delimiter};
/// Does this expression require a semicolon to be treated
/// as a statement? The negation of this: 'can this expression
/// be used as a statement without a semicolon' -- is used
/// as an early-bail-out in the parser so that, for instance,
/// if true {...} else {...}
/// |x| 5
/// isn't parsed as (if true {...} else {...} | x) | 5
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
!matches!(
/// This classification determines whether various syntactic positions break out
/// of parsing the current expression (true) or continue parsing more of the
/// same expression (false).
///
/// For example, it's relevant in the parsing of match arms:
///
/// ```ignore (illustrative)
/// match ... {
/// // Is this calling $e as a function, or is it the start of a new arm
/// // with a tuple pattern?
/// _ => $e (
/// ^ )
///
/// // Is this an Index operation, or new arm with a slice pattern?
/// _ => $e [
/// ^ ]
///
/// // Is this a binary operator, or leading vert in a new arm? Same for
/// // other punctuation which can either be a binary operator in
/// // expression or unary operator in pattern, such as `&` and `-`.
/// _ => $e |
/// ^
/// }
/// ```
///
/// If $e is something like `{}` or `if … {}`, then terminate the current
/// arm and parse a new arm.
///
/// If $e is something like `path::to` or `(…)`, continue parsing the same
/// arm.
///
/// *Almost* the same classification is used as an early bail-out for parsing
/// statements. See `expr_requires_semi_to_be_stmt`.
pub fn expr_is_complete(e: &ast::Expr) -> bool {
matches!(
e.kind,
ast::ExprKind::If(..)
| ast::ExprKind::Match(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::While(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop { .. }
| ast::ExprKind::TryBlock(..)
| ast::ExprKind::ConstBlock(..)
If(..)
| Match(..)
| Block(..)
| While(..)
| Loop(..)
| ForLoop { .. }
| TryBlock(..)
| ConstBlock(..)
)
}
/// Does this expression require a semicolon to be treated as a statement?
///
/// The negation of this: "can this expression be used as a statement without a
/// semicolon" -- is used as an early bail-out when parsing statements so that,
/// for instance,
///
/// ```ignore (illustrative)
/// if true {...} else {...}
/// |x| 5
/// ```
///
/// isn't parsed as `(if true {...} else {...} | x) | 5`.
///
/// Surprising special case: even though braced macro calls like `m! {}`
/// normally do not introduce a boundary when found at the head of a match arm,
/// they do terminate the parsing of a statement.
///
/// ```ignore (illustrative)
/// match ... {
/// _ => m! {} (), // macro that expands to a function, which is then called
/// }
///
/// let _ = { m! {} () }; // macro call followed by unit
/// ```
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
match &e.kind {
MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace,
_ => !expr_is_complete(e),
}
}
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
use ast::ExprKind::*;
loop {
match &expr.kind {
AddrOf(_, _, e)

View file

@ -1407,7 +1407,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds,
fn_kind,
itctx,
precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
),
ImplTraitContext::Universal => {
if let Some(&(_, span)) = precise_capturing.as_deref() {
@ -1523,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bounds: &GenericBounds,
fn_kind: Option<FnDeclKind>,
itctx: ImplTraitContext,
precise_capturing_args: Option<&[PreciseCapturingArg]>,
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
@ -1533,7 +1533,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let captured_lifetimes_to_duplicate =
if let Some(precise_capturing) = precise_capturing_args {
if let Some((precise_capturing, _)) = precise_capturing_args {
// We'll actually validate these later on; all we need is the list of
// lifetimes to duplicate during this portion of lowering.
precise_capturing
@ -1607,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
span: Span,
opaque_ty_span: Span,
precise_capturing_args: Option<&[PreciseCapturingArg]>,
precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
) -> hir::TyKind<'hir> {
let opaque_ty_def_id = self.create_def(
@ -1698,8 +1698,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.with_remapping(captured_to_synthesized_mapping, |this| {
(
lower_item_bounds(this),
precise_capturing_args.map(|precise_capturing| {
this.lower_precise_capturing_args(precise_capturing)
precise_capturing_args.map(|(precise_capturing, span)| {
(
this.lower_precise_capturing_args(precise_capturing),
this.lower_span(span),
)
}),
)
});

View file

@ -55,8 +55,8 @@ impl PpAnn for NoAnn {}
pub struct Comments<'a> {
sm: &'a SourceMap,
comments: Vec<Comment>,
current: usize,
// Stored in reverse order so we can consume them by popping.
reversed_comments: Vec<Comment>,
}
/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
@ -182,21 +182,25 @@ fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment>
impl<'a> Comments<'a> {
pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
let comments = gather_comments(sm, filename, input);
Comments { sm, comments, current: 0 }
let mut comments = gather_comments(sm, filename, input);
comments.reverse();
Comments { sm, reversed_comments: comments }
}
// FIXME: This shouldn't probably clone lmao
fn next(&self) -> Option<Comment> {
self.comments.get(self.current).cloned()
fn peek(&self) -> Option<&Comment> {
self.reversed_comments.last()
}
fn next(&mut self) -> Option<Comment> {
self.reversed_comments.pop()
}
fn trailing_comment(
&self,
&mut self,
span: rustc_span::Span,
next_pos: Option<BytePos>,
) -> Option<Comment> {
if let Some(cmnt) = self.next() {
if let Some(cmnt) = self.peek() {
if cmnt.style != CommentStyle::Trailing {
return None;
}
@ -204,7 +208,7 @@ impl<'a> Comments<'a> {
let comment_line = self.sm.lookup_char_pos(cmnt.pos);
let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
return Some(cmnt);
return Some(self.next().unwrap());
}
}
@ -400,7 +404,8 @@ impl std::ops::DerefMut for State<'_> {
/// This trait is used for both AST and HIR pretty-printing.
pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
fn comments(&mut self) -> &mut Option<Comments<'a>>;
fn comments(&self) -> Option<&Comments<'a>>;
fn comments_mut(&mut self) -> Option<&mut Comments<'a>>;
fn ann_post(&mut self, ident: Ident);
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
@ -442,18 +447,18 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
let mut has_comment = false;
while let Some(cmnt) = self.next_comment() {
if cmnt.pos < pos {
has_comment = true;
self.print_comment(&cmnt);
} else {
while let Some(cmnt) = self.peek_comment() {
if cmnt.pos >= pos {
break;
}
has_comment = true;
let cmnt = self.next_comment().unwrap();
self.print_comment(cmnt);
}
has_comment
}
fn print_comment(&mut self, cmnt: &Comment) {
fn print_comment(&mut self, cmnt: Comment) {
match cmnt.style {
CommentStyle::Mixed => {
if !self.is_beginning_of_line() {
@ -517,19 +522,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.hardbreak();
}
}
if let Some(cmnts) = self.comments() {
cmnts.current += 1;
}
}
fn peek_comment<'b>(&'b self) -> Option<&'b Comment> where 'a: 'b {
self.comments().and_then(|c| c.peek())
}
fn next_comment(&mut self) -> Option<Comment> {
self.comments().as_mut().and_then(|c| c.next())
self.comments_mut().and_then(|c| c.next())
}
fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
if let Some(cmnts) = self.comments() {
if let Some(cmnts) = self.comments_mut() {
if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
self.print_comment(&cmnt);
self.print_comment(cmnt);
}
}
}
@ -537,11 +543,11 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
fn print_remaining_comments(&mut self) {
// If there aren't any remaining comments, then we need to manually
// make sure there is a line break at the end.
if self.next_comment().is_none() {
if self.peek_comment().is_none() {
self.hardbreak();
}
while let Some(cmnt) = self.next_comment() {
self.print_comment(&cmnt)
self.print_comment(cmnt)
}
}
@ -852,8 +858,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::NtBlock(e) => self.block_to_string(e),
token::NtStmt(e) => self.stmt_to_string(e),
token::NtPat(e) => self.pat_to_string(e),
&token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
token::NtLifetime(e) => e.to_string(),
token::NtLiteral(e) => self.expr_to_string(e),
token::NtVis(e) => self.vis_to_string(e),
}
@ -915,10 +919,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::Literal(lit) => literal_to_string(lit).into(),
/* Name components */
token::Ident(s, is_raw) => {
IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
token::Ident(name, is_raw) => {
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
}
token::Lifetime(s) => s.to_string().into(),
token::NtIdent(ident, is_raw) => {
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
}
token::Lifetime(name) => name.to_string().into(),
token::NtLifetime(ident) => ident.name.to_string().into(),
/* Other */
token::DocComment(comment_kind, attr_style, data) => {
@ -926,7 +934,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}
token::Eof => "<eof>".into(),
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
}
}
@ -994,8 +1002,12 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}
impl<'a> PrintState<'a> for State<'a> {
fn comments(&mut self) -> &mut Option<Comments<'a>> {
&mut self.comments
fn comments(&self) -> Option<&Comments<'a>> {
self.comments.as_ref()
}
fn comments_mut(&mut self) -> Option<&mut Comments<'a>> {
self.comments.as_mut()
}
fn ann_post(&mut self, ident: Ident) {
@ -1238,7 +1250,11 @@ impl<'a> State<'a> {
if let Some((init, els)) = loc.kind.init_else_opt() {
self.nbsp();
self.word_space("=");
self.print_expr(init, FixupContext::default());
self.print_expr_cond_paren(
init,
els.is_some() && classify::expr_trailing_brace(init).is_some(),
FixupContext::default(),
);
if let Some(els) = els {
self.cbox(INDENT_UNIT);
self.ibox(INDENT_UNIT);

View file

@ -780,7 +780,7 @@ impl<'a> State<'a> {
}
_ => {
self.end(); // Close the ibox for the pattern.
self.print_expr(body, FixupContext::new_stmt());
self.print_expr(body, FixupContext::new_match_arm());
self.word(",");
}
}

View file

@ -49,6 +49,38 @@ pub(crate) struct FixupContext {
/// No parentheses required.
leftmost_subexpression_in_stmt: bool,
/// Print expression such that it can be parsed as a match arm.
///
/// This is almost equivalent to `stmt`, but the grammar diverges a tiny bit
/// between statements and match arms when it comes to braced macro calls.
/// Macro calls with brace delimiter terminate a statement without a
/// semicolon, but do not terminate a match-arm without comma.
///
/// ```ignore (illustrative)
/// m! {} - 1; // two statements: a macro call followed by -1 literal
///
/// match () {
/// _ => m! {} - 1, // binary subtraction operator
/// }
/// ```
match_arm: bool,
/// This is almost equivalent to `leftmost_subexpression_in_stmt`, other
/// than for braced macro calls.
///
/// If we have `m! {} - 1` as an expression, the leftmost subexpression
/// `m! {}` will need to be parenthesized in the statement case but not the
/// match-arm case.
///
/// ```ignore (illustrative)
/// (m! {}) - 1; // subexpression needs parens
///
/// match () {
/// _ => m! {} - 1, // no parens
/// }
/// ```
leftmost_subexpression_in_match_arm: bool,
/// This is the difference between:
///
/// ```ignore (illustrative)
@ -68,6 +100,8 @@ impl Default for FixupContext {
FixupContext {
stmt: false,
leftmost_subexpression_in_stmt: false,
match_arm: false,
leftmost_subexpression_in_match_arm: false,
parenthesize_exterior_struct_lit: false,
}
}
@ -76,13 +110,16 @@ impl Default for FixupContext {
impl FixupContext {
/// Create the initial fixup for printing an expression in statement
/// position.
///
/// This is currently also used for printing an expression as a match-arm,
/// but this is incorrect and leads to over-parenthesizing.
pub fn new_stmt() -> Self {
FixupContext { stmt: true, ..FixupContext::default() }
}
/// Create the initial fixup for printing an expression as the right-hand
/// side of a match arm.
pub fn new_match_arm() -> Self {
FixupContext { match_arm: true, ..FixupContext::default() }
}
/// Create the initial fixup for printing an expression as the "condition"
/// of an `if` or `while`. There are a few other positions which are
/// grammatically equivalent and also use this, such as the iterator
@ -106,6 +143,9 @@ impl FixupContext {
FixupContext {
stmt: false,
leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
match_arm: false,
leftmost_subexpression_in_match_arm: self.match_arm
|| self.leftmost_subexpression_in_match_arm,
..self
}
}
@ -119,7 +159,13 @@ impl FixupContext {
/// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
/// `$a.f($b)`.
pub fn subsequent_subexpression(self) -> Self {
FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..self }
FixupContext {
stmt: false,
leftmost_subexpression_in_stmt: false,
match_arm: false,
leftmost_subexpression_in_match_arm: false,
..self
}
}
/// Determine whether parentheses are needed around the given expression to
@ -128,7 +174,8 @@ impl FixupContext {
/// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has
/// examples.
pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool {
self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr)
(self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr))
|| (self.leftmost_subexpression_in_match_arm && classify::expr_is_complete(expr))
}
/// Determine whether parentheses are needed around the given `let`

View file

@ -1010,7 +1010,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
clauses.iter().any(|pred| {
match pred.kind().skip_binder() {
ty::ClauseKind::Trait(data) if data.self_ty() == ty => {}
ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
ty::ClauseKind::Projection(data)
if data.projection_term.self_ty() == ty => {}
_ => return false,
}
tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region))

View file

@ -2059,10 +2059,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// We currently do not store the `DefId` in the `ConstraintCategory`
// for performances reasons. The error reporting code used by NLL only
// uses the span, so this doesn't cause any problems at the moment.
Some(ObligationCauseCode::SpannedWhereClause(
CRATE_DEF_ID.to_def_id(),
predicate_span,
))
Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span))
} else {
None
}

View file

@ -51,6 +51,14 @@ jobs:
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: rustup set default-host x86_64-pc-windows-gnu
- name: Use x86_64 compiler on macOS
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
run: rustup set default-host x86_64-apple-darwin
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare

View file

@ -98,12 +98,20 @@ jobs:
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: rustup set default-host x86_64-pc-windows-gnu
- name: Use x86_64 compiler on macOS
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
run: rustup set default-host x86_64-apple-darwin
- name: Install toolchain and emulator
if: matrix.apt_deps != null
run: |
sudo apt-get update
sudo apt-get install -y ${{ matrix.apt_deps }}
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare
@ -230,12 +238,20 @@ jobs:
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: rustup set default-host x86_64-pc-windows-gnu
- name: Use x86_64 compiler on macOS
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
run: rustup set default-host x86_64-apple-darwin
- name: Install MinGW toolchain
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64
- name: Select XCode version
if: matrix.os == 'macos-latest'
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare dependencies
run: ./y.sh prepare

View file

@ -20,7 +20,7 @@ jobs:
uses: actions/cache@v4
with:
path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
- name: Prepare dependencies
run: ./y.sh prepare
@ -43,7 +43,7 @@ jobs:
uses: actions/cache@v4
with:
path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
- name: Install ripgrep
run: |

View file

@ -1,8 +1,4 @@
# Build artifacts during normal use
/y.bin
/y.bin.dSYM
/y.exe
/y.pdb
/download
/build
/dist

View file

@ -11,3 +11,6 @@ path = "main.rs"
unstable-features = [] # for rust-analyzer
# Do not add any dependencies
[profile.dev]
debug = 1

View file

@ -267,12 +267,16 @@ fn build_clif_sysroot_for_triple(
prefix.to_str().unwrap()
));
}
rustflags.push("-Zunstable-options".to_owned());
for (name, values) in EXTRA_CHECK_CFGS {
rustflags.push(check_cfg_arg(name, *values));
}
compiler.rustflags.extend(rustflags);
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
if channel == "release" {
build_cmd.arg("--release");
}
build_cmd.arg("--features").arg("compiler-builtins-no-asm backtrace panic-unwind");
build_cmd.arg("--features").arg("backtrace panic-unwind");
build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
if compiler.triple.contains("apple") {
@ -326,3 +330,34 @@ fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
Some(target_libs)
}
// Copied from https://github.com/rust-lang/rust/blob/4fd98a4b1b100f5329c6efae18031791f64372d2/src/bootstrap/src/utils/helpers.rs#L569-L585
/// Create a `--check-cfg` argument invocation for a given name
/// and it's values.
fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
// Creating a string of the values by concatenating each value:
// ',values("tvos","watchos")' or '' (nothing) when there are no values.
let next = match values {
Some(values) => {
let mut tmp = values.iter().flat_map(|val| [",", "\"", val, "\""]).collect::<String>();
tmp.insert_str(1, "values(");
tmp.push(')');
tmp
}
None => "".to_string(),
};
format!("--check-cfg=cfg({name}{next})")
}
const EXTRA_CHECK_CFGS: &[(&str, Option<&[&str]>)] = &[
("bootstrap", None),
("stdarch_intel_sde", None),
("no_fp_fmt_parse", None),
("no_global_oom_handling", None),
("no_rc", None),
("no_sync", None),
("netbsd10", None),
("backtrace_in_libstd", None),
("target_arch", Some(&["xtensa"])),
];

View file

@ -147,9 +147,11 @@ fn main() {
let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) {
(Ok(_), Ok(_), Ok(_)) => None,
(Err(_), Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
_ => {
eprintln!("All of CARGO, RUSTC and RUSTDOC need to be set or none must be set");
(_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
vars => {
eprintln!(
"If RUSTC or RUSTDOC is set, both need to be set and in addition CARGO needs to be set: {vars:?}"
);
process::exit(1);
}
};

View file

@ -77,7 +77,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
),
TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
TestCase::jit_bin("jit.std_example", "example/std_example.rs", "arg"),
TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
TestCase::build_bin_and_run(

View file

@ -4,6 +4,7 @@
never_type,
linkage,
extern_types,
naked_functions,
thread_local,
repr_simd,
raw_ref_op
@ -340,6 +341,7 @@ fn main() {
))]
unsafe {
global_asm_test();
naked_test();
}
// Both statics have a reference that points to the same anonymous allocation.
@ -395,6 +397,14 @@ global_asm! {
"
}
#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64"))]
#[naked]
extern "C" fn naked_test() {
unsafe {
asm!("ret", options(noreturn));
}
}
#[repr(C)]
enum c_void {
_1,

View file

@ -210,6 +210,21 @@ struct I64X2(i64, i64);
#[allow(improper_ctypes_definitions)]
extern "C" fn foo(_a: I64X2) {}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.2")]
#[cfg(not(jit))]
unsafe fn test_crc32() {
assert!(is_x86_feature_detected!("sse4.2"));
let a = 42u32;
let b = 0xdeadbeefu64;
assert_eq!(_mm_crc32_u8(a, b as u8), 4135334616);
assert_eq!(_mm_crc32_u16(a, b as u16), 1200687288);
assert_eq!(_mm_crc32_u32(a, b as u32), 2543798776);
assert_eq!(_mm_crc32_u64(a as u64, b as u64), 241952147);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
@ -244,10 +259,14 @@ unsafe fn test_simd() {
test_mm256_shuffle_epi8();
test_mm256_permute2x128_si256();
test_mm256_permutevar8x32_epi32();
#[rustfmt::skip]
let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
assert_eq!(mask1, 1);
#[cfg(not(jit))]
test_crc32();
}
#[cfg(target_arch = "x86_64")]
@ -447,6 +466,16 @@ unsafe fn test_mm256_permute2x128_si256() {
assert_eq_m256i(r, e);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn test_mm256_permutevar8x32_epi32() {
let a = _mm256_setr_epi32(100, 200, 300, 400, 500, 600, 700, 800);
let idx = _mm256_setr_epi32(7, 6, 5, 4, 3, 2, 1, 0);
let r = _mm256_setr_epi32(800, 700, 600, 500, 400, 300, 200, 100);
let e = _mm256_permutevar8x32_epi32(a, idx);
assert_eq_m256i(r, e);
}
fn test_checked_mul() {
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
assert_eq!(u, None);

View file

@ -42,9 +42,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "cc"
version = "1.0.90"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
[[package]]
name = "cfg-if"

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2024-04-23"
channel = "nightly-2024-05-13"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

@ -44,6 +44,7 @@ rm tests/incremental/hashes/statics.rs # same
rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support
rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
rm tests/ui/delegation/fn-header.rs
# unsized locals
rm -r tests/run-pass-valgrind/unsized-locals
@ -87,6 +88,7 @@ rm -r tests/run-make/no-builtins-attribute # same
rm tests/ui/abi/stack-protector.rs # requires stack protector support
rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes
rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific
rm -r tests/run-make/print-to-output # requires --print relocation-models
# requires asm, llvm-ir and/or llvm-bc emit support
# =============================================
@ -151,7 +153,7 @@ index 9607ff02f96..b7d97caf9a2 100644
let mut cmd = setup_common();
- let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
- cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
Self { cmd }
Self { cmd, stdin: None }
}
EOF

View file

@ -412,7 +412,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
Err(instance) => Some(instance),
}
}
InstanceDef::DropGlue(_, None) => {
InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => {
// empty drop glue - a nop.
let dest = target.expect("Non terminating drop_in_place_real???");
let ret_block = fx.get_block(dest);
@ -597,7 +597,9 @@ pub(crate) fn codegen_drop<'tcx>(
let ty = drop_place.layout().ty;
let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
if let ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) =
drop_instance.def
{
// we don't actually need to drop anything
} else {
match ty.kind() {

View file

@ -6,6 +6,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::ModuleError;
use rustc_ast::InlineAsmOptions;
use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
@ -14,6 +15,7 @@ use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphizat
use crate::constant::ConstantCx;
use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
use crate::inline_asm::codegen_naked_asm;
use crate::prelude::*;
use crate::pretty_clif::CommentWriter;
@ -32,7 +34,7 @@ pub(crate) fn codegen_fn<'tcx>(
cached_func: Function,
module: &mut dyn Module,
instance: Instance<'tcx>,
) -> CodegenedFunction {
) -> Option<CodegenedFunction> {
debug_assert!(!instance.args.has_infer());
let symbol_name = tcx.symbol_name(instance).name.to_string();
@ -48,6 +50,37 @@ 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 {
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();
@ -128,7 +161,7 @@ pub(crate) fn codegen_fn<'tcx>(
// Verify function
verify_func(tcx, &clif_comments, &func);
CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }
Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx })
}
pub(crate) fn compile_fn(

View file

@ -6,7 +6,7 @@ use rustc_session::Session;
// FIXME don't panic when a worker thread panics
pub(super) struct ConcurrencyLimiter {
helper_thread: Option<HelperThread>,
helper_thread: Option<Mutex<HelperThread>>,
state: Arc<Mutex<state::ConcurrencyLimiterState>>,
available_token_condvar: Arc<Condvar>,
finished: bool,
@ -39,14 +39,14 @@ impl ConcurrencyLimiter {
})
.unwrap();
ConcurrencyLimiter {
helper_thread: Some(helper_thread),
helper_thread: Some(Mutex::new(helper_thread)),
state,
available_token_condvar,
finished: false,
}
}
pub(super) fn acquire(&mut self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
pub(super) fn acquire(&self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
let mut state = self.state.lock().unwrap();
loop {
state.assert_invariants();
@ -73,16 +73,11 @@ impl ConcurrencyLimiter {
}
}
self.helper_thread.as_mut().unwrap().request_token();
self.helper_thread.as_ref().unwrap().lock().unwrap().request_token();
state = self.available_token_condvar.wait(state).unwrap();
}
}
pub(super) fn job_already_done(&mut self) {
let mut state = self.state.lock().unwrap();
state.job_already_done();
}
pub(crate) fn finished(mut self) {
self.helper_thread.take();
@ -190,14 +185,6 @@ mod state {
self.assert_invariants();
}
pub(super) fn job_already_done(&mut self) {
self.assert_invariants();
self.pending_jobs -= 1;
self.assert_invariants();
self.drop_excess_capacity();
self.assert_invariants();
}
pub(super) fn poison(&mut self, error: String) {
self.poisoned = true;
self.stored_error = Some(error);

View file

@ -64,8 +64,13 @@ impl Default for BackendConfig {
BackendConfig {
codegen_mode: CodegenMode::Aot,
jit_args: {
let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
args.split(' ').map(|arg| arg.to_string()).collect()
match std::env::var("CG_CLIF_JIT_ARGS") {
Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
Err(std::env::VarError::NotPresent) => vec![],
Err(std::env::VarError::NotUnicode(s)) => {
panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
}
}
},
enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),

View file

@ -258,7 +258,7 @@ fn data_id_for_static(
) -> DataId {
let attrs = tcx.codegen_fn_attrs(def_id);
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let instance = Instance::mono(tcx, def_id);
let symbol_name = tcx.symbol_name(instance).name;
if let Some(import_linkage) = attrs.import_linkage {

View file

@ -28,16 +28,20 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
} => {
let ptr = place.place_field(fx, FieldIdx::new(tag_field));
let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val;
let to = if ptr.layout().abi.is_signed() {
ty::ScalarInt::try_from_int(
ptr.layout().size.sign_extend(to) as i128,
ptr.layout().size,
)
.unwrap()
} else {
ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
let to = match ptr.layout().ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
let lsb = fx.bcx.ins().iconst(types::I64, to as u64 as i64);
let msb = fx.bcx.ins().iconst(types::I64, (to >> 64) as u64 as i64);
fx.bcx.ins().iconcat(lsb, msb)
}
ty::Uint(_) | ty::Int(_) => {
let clif_ty = fx.clif_type(ptr.layout().ty).unwrap();
let raw_val = ptr.layout().size.truncate(to);
fx.bcx.ins().iconst(clif_ty, raw_val as i64)
}
_ => unreachable!(),
};
let discr = CValue::const_val(fx, ptr.layout(), to);
let discr = CValue::by_val(to, ptr.layout());
ptr.write_cvalue(fx, discr);
}
Variants::Multiple {
@ -85,16 +89,21 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
.ty
.discriminant_for_variant(fx.tcx, *index)
.map_or(u128::from(index.as_u32()), |discr| discr.val);
let discr_val = if dest_layout.abi.is_signed() {
ty::ScalarInt::try_from_int(
dest_layout.size.sign_extend(discr_val) as i128,
dest_layout.size,
)
.unwrap()
} else {
ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
let val = match dest_layout.ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
let lsb = fx.bcx.ins().iconst(types::I64, discr_val as u64 as i64);
let msb = fx.bcx.ins().iconst(types::I64, (discr_val >> 64) as u64 as i64);
fx.bcx.ins().iconcat(lsb, msb)
}
ty::Uint(_) | ty::Int(_) => {
let clif_ty = fx.clif_type(dest_layout.ty).unwrap();
let raw_val = dest_layout.size.truncate(discr_val);
fx.bcx.ins().iconst(clif_ty, raw_val as i64)
}
_ => unreachable!(),
};
let res = CValue::const_val(fx, dest_layout, discr_val);
let res = CValue::by_val(val, dest_layout);
dest.write_cvalue(fx, res);
return;
}

View file

@ -15,6 +15,7 @@ use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{par_map, IntoDynSyncSend};
use rustc_metadata::fs::copy_to_stdout;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@ -481,15 +482,16 @@ fn module_codegen(
for (mono_item, _) in mono_items {
match mono_item {
MonoItem::Fn(inst) => {
let codegened_function = crate::base::codegen_fn(
if let Some(codegened_function) = crate::base::codegen_fn(
tcx,
&mut cx,
&mut type_dbg,
Function::new(),
&mut module,
inst,
);
codegened_functions.push(codegened_function);
) {
codegened_functions.push(codegened_function);
}
}
MonoItem::Static(def_id) => {
let data_id = crate::constant::codegen_static(tcx, &mut module, def_id);
@ -604,39 +606,39 @@ pub(crate) fn run_aot(
let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len());
let (todo_cgus, done_cgus) =
cgus.into_iter().enumerate().partition::<Vec<_>, _>(|&(i, _)| match cgu_reuse[i] {
_ if backend_config.disable_incr_cache => true,
CguReuse::No => true,
CguReuse::PreLto | CguReuse::PostLto => false,
});
let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(tcx.sess, todo_cgus.len()));
let modules = tcx.sess.time("codegen mono items", || {
cgus.iter()
.enumerate()
.map(|(i, cgu)| {
let cgu_reuse =
if backend_config.disable_incr_cache { CguReuse::No } else { cgu_reuse[i] };
match cgu_reuse {
CguReuse::No => {
let dep_node = cgu.codegen_dep_node(tcx);
tcx.dep_graph
.with_task(
dep_node,
tcx,
(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(tcx.dcx()),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
)
.0
}
CguReuse::PreLto | CguReuse::PostLto => {
concurrency_limiter.job_already_done();
OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
}
}
})
.collect::<Vec<_>>()
let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| {
let dep_node = cgu.codegen_dep_node(tcx);
tcx.dep_graph
.with_task(
dep_node,
tcx,
(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
concurrency_limiter.acquire(tcx.dcx()),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
)
.0
});
modules.extend(
done_cgus
.into_iter()
.map(|(_, cgu)| OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))),
);
modules
});
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
@ -705,6 +707,6 @@ pub(crate) fn run_aot(
metadata_module,
metadata,
crate_info: CrateInfo::new(tcx, target_cpu),
concurrency_limiter,
concurrency_limiter: concurrency_limiter.0,
})
}

View file

@ -83,13 +83,6 @@ fn create_jit_module(
);
crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&mut jit_module,
&mut cx.unwind_context,
true,
true,
);
(jit_module, cx)
}
@ -153,6 +146,14 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
tcx.dcx().fatal("Inline asm is not supported in JIT mode");
}
crate::main_shim::maybe_create_entry_wrapper(
tcx,
&mut jit_module,
&mut cx.unwind_context,
true,
true,
);
tcx.dcx().abort_if_errors();
jit_module.finalize_definitions().unwrap();
@ -231,16 +232,16 @@ 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());
let codegened_func = crate::base::codegen_fn(
if let Some(codegened_func) = crate::base::codegen_fn(
tcx,
cx,
&mut TypeDebugContext::default(),
cached_func,
module,
instance,
);
crate::base::compile_fn(cx, cached_context, module, codegened_func);
) {
crate::base::compile_fn(cx, cached_context, module, codegened_func);
}
});
}

View file

@ -5,6 +5,7 @@
//! [`codegen_static`]: crate::constant::codegen_static
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::mono::{MonoItem, MonoItemData};
use crate::prelude::*;
@ -33,7 +34,20 @@ fn predefine_mono_items<'tcx>(
data.visibility,
is_compiler_builtins,
);
module.declare_function(name, linkage, &sig).unwrap();
let is_naked = tcx
.codegen_fn_attrs(instance.def_id())
.flags
.contains(CodegenFnAttrFlags::NAKED);
module
.declare_function(
name,
// Naked functions are defined in a separate object
// file from the codegen unit rustc expects them to
// be defined in.
if is_naked { Linkage::Import } else { linkage },
&sig,
)
.unwrap();
}
MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
}

View file

@ -81,7 +81,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
);
}
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let instance = Instance::mono(tcx, def_id);
let symbol = tcx.symbol_name(instance);
global_asm.push_str(symbol.name);
}

View file

@ -127,7 +127,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
}
InlineAsmOperand::SymStatic { def_id } => {
assert!(fx.tcx.is_static(def_id));
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
let instance = Instance::mono(fx.tcx, def_id);
CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() }
}
InlineAsmOperand::Label { .. } => {
@ -169,6 +169,7 @@ 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();
@ -209,6 +210,121 @@ 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::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(value.const_),
);
let const_value = cv
.eval(tcx, ty::ParamEnv::reveal_all(), value.span)
.expect("erroneous constant missed by mono item collection");
let value = rustc_codegen_ssa::common::asm_const_to_str(
tcx,
span,
const_value,
RevealAllLayoutCx(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::ParamEnv::reveal_all(),
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::ParamEnv::reveal_all(),
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 inline_asm_index = cx.inline_asm_index.get();
cx.inline_asm_index.set(inline_asm_index + 1);
let wrapper_name = format!(
"__inline_asm_{}_wrapper_n{}",
cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
inline_asm_index
);
let sig =
get_function_sig(tcx, module.target_config().default_call_conv, instance);
create_wrapper_function(
module,
&mut cx.unwind_context,
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,
@ -221,10 +337,13 @@ 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,
@ -348,6 +467,8 @@ 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()];
@ -468,30 +589,32 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
if is_x86 {
generated_asm.push_str(".intel_syntax noprefix\n");
}
Self::prologue(&mut generated_asm, self.arch);
if !self.is_naked {
Self::prologue(&mut generated_asm, self.arch);
// Save clobbered registers
if !self.options.contains(InlineAsmOptions::NORETURN) {
// 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);
}
}
// Write input registers
for (reg, slot) in self
.registers
.iter()
.zip(self.stack_slots_clobber.iter().copied())
.zip(self.stack_slots_input.iter().copied())
.filter_map(|(r, s)| r.zip(s))
{
Self::save_register(&mut generated_asm, self.arch, reg, slot);
Self::restore_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");
}
@ -553,30 +676,32 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
generated_asm.push_str(".intel_syntax noprefix\n");
}
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);
}
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);
}
// 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);
Self::epilogue(&mut generated_asm, self.arch);
} else {
Self::epilogue_noreturn(&mut generated_asm, self.arch);
}
}
if is_x86 {

View file

@ -374,6 +374,21 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
}
}
}
"llvm.x86.avx2.permd" => {
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permutevar8x32_epi32
intrinsic_args!(fx, args => (a, idx); intrinsic);
for j in 0..=7 {
let index = idx.value_typed_lane(fx, fx.tcx.types.u32, j).load_scalar(fx);
let index = fx.bcx.ins().uextend(fx.pointer_type, index);
let value = a.value_lane_dyn(fx, index).load_scalar(fx);
ret.place_typed_lane(fx, fx.tcx.types.u32, j).to_ptr().store(
fx,
value,
MemFlags::trusted(),
);
}
}
"llvm.x86.avx2.vperm2i128"
| "llvm.x86.avx.vperm2f128.ps.256"
| "llvm.x86.avx.vperm2f128.pd.256" => {
@ -832,6 +847,43 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
}
}
"llvm.x86.sse42.crc32.32.8"
| "llvm.x86.sse42.crc32.32.16"
| "llvm.x86.sse42.crc32.32.32"
| "llvm.x86.sse42.crc32.64.64" => {
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1419&text=_mm_crc32_u32
intrinsic_args!(fx, args => (crc, v); intrinsic);
let crc = crc.load_scalar(fx);
let v = v.load_scalar(fx);
let asm = match intrinsic {
"llvm.x86.sse42.crc32.32.8" => "crc32 eax, dl",
"llvm.x86.sse42.crc32.32.16" => "crc32 eax, dx",
"llvm.x86.sse42.crc32.32.32" => "crc32 eax, edx",
"llvm.x86.sse42.crc32.64.64" => "crc32 rax, rdx",
_ => unreachable!(),
};
codegen_inline_asm_inner(
fx,
&[InlineAsmTemplatePiece::String(asm.to_string())],
&[
CInlineAsmOperand::InOut {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
_late: true,
in_value: crc,
out_place: Some(ret),
},
CInlineAsmOperand::In {
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
value: v,
},
],
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
);
}
"llvm.x86.sse42.pcmpestri128" => {
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestri&ig_expand=939
intrinsic_args!(fx, args => (a, la, b, lb, _imm8); intrinsic);

View file

@ -331,9 +331,9 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn TargetIs
sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err));
});
if target_triple.architecture == target_lexicon::Architecture::X86_64 {
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
builder.enable("nehalem").unwrap();
// Only set the target cpu on x86_64 as Cranelift is missing
// the target cpu list for most other targets.
builder.enable(sess.target.cpu.as_ref()).unwrap();
}
builder
}

View file

@ -29,7 +29,7 @@ pub(crate) fn maybe_create_entry_wrapper(
if main_def_id.is_local() {
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
if !is_jit && module.get_name(tcx.symbol_name(instance).name).is_none() {
if module.get_name(tcx.symbol_name(instance).name).is_none() {
return;
}
} else if !is_primary_cgu {

View file

@ -317,14 +317,6 @@ impl<'tcx> CValue<'tcx> {
let clif_ty = fx.clif_type(layout.ty).unwrap();
if let ty::Bool = layout.ty.kind() {
assert!(
const_val == ty::ScalarInt::FALSE || const_val == ty::ScalarInt::TRUE,
"Invalid bool 0x{:032X}",
const_val
);
}
let val = match layout.ty.kind() {
ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
let const_val = const_val.assert_bits(layout.size);

View file

@ -1,8 +1,6 @@
@echo off
echo [BUILD] build system >&2
mkdir build 2>nul
rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021 || goto :error
build\y.exe %* || goto :error
cargo run --manifest-path build_system/Cargo.toml -- %* || goto :error
goto :EOF
:error

7
compiler/rustc_codegen_cranelift/y.ps1 Normal file → Executable file
View file

@ -1,12 +1,7 @@
$ErrorActionPreference = "Stop"
$host.ui.WriteErrorLine("[BUILD] build system")
New-Item -ItemType Directory -Force -Path build | Out-Null
& rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
& build\y.exe $args
& cargo run --manifest-path build_system/Cargo.toml -- $args
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}

View file

@ -2,5 +2,4 @@
set -e
echo "[BUILD] build system" 1>&2
rustc build_system/main.rs -o y.bin -Cdebuginfo=1 --edition 2021
exec ./y.bin "$@"
exec cargo run --manifest-path build_system/Cargo.toml -- "$@"

View file

@ -283,7 +283,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
if src_f.layout.ty == dst_f.layout.ty {
bx.typed_place_copy(dst_f, src_f);
bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout);
} else {
coerce_unsized_into(bx, src_f, dst_f);
}

View file

@ -1454,9 +1454,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi),
None => arg.layout.align.abi,
};
let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
op.val.store(bx, scratch);
(scratch.val.llval, scratch.val.align, true)
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
op.val.store(bx, scratch.with_type(arg.layout));
(scratch.llval, scratch.align, true)
}
PassMode::Cast { .. } => {
let scratch = PlaceRef::alloca(bx, arg.layout);
@ -1475,10 +1475,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// For `foo(packed.large_field)`, and types with <4 byte alignment on x86,
// alignment requirements may be higher than the type's alignment, so copy
// to a higher-aligned alloca.
let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
let op_place = PlaceRef { val: op_place_val, layout: op.layout };
bx.typed_place_copy(scratch, op_place);
(scratch.val.llval, scratch.val.align, true)
let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
bx.typed_place_copy(scratch, op_place_val, op.layout);
(scratch.llval, scratch.align, true)
} else {
(op_place_val.llval, op_place_val.align, true)
}
@ -1567,7 +1566,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if place_val.llextra.is_some() {
bug!("closure arguments must be sized");
}
let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout };
let tuple_ptr = place_val.with_type(tuple.layout);
for i in 0..tuple.layout.fields.count() {
let field_ptr = tuple_ptr.project_field(bx, i);
let field = bx.load_operand(field_ptr);

View file

@ -1,4 +1,4 @@
use super::operand::{OperandRef, OperandValue};
use super::operand::OperandRef;
use super::place::PlaceRef;
use super::FunctionCx;
use crate::errors;
@ -93,9 +93,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// into the (unoptimized) direct swapping implementation, so we disable it.
|| bx.sess().target.arch == "spirv"
{
let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout);
let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout);
bx.typed_place_swap(x_place, y_place);
let align = pointee_layout.align.abi;
let x_place = args[0].val.deref(align);
let y_place = args[1].val.deref(align);
bx.typed_place_swap(x_place, y_place, pointee_layout);
return Ok(());
}
}
@ -113,15 +114,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::va_end => bx.va_end(args[0].immediate()),
sym::size_of_val => {
let tp_ty = fn_args.type_at(0);
let meta =
if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (_, meta) = args[0].val.pointer_parts();
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llsize
}
sym::min_align_of_val => {
let tp_ty = fn_args.type_at(0);
let meta =
if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
let (_, meta) = args[0].val.pointer_parts();
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llalign
}

View file

@ -61,7 +61,7 @@ pub enum OperandValue<V> {
ZeroSized,
}
impl<V> OperandValue<V> {
impl<V: CodegenObject> OperandValue<V> {
/// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values.
/// If this is Ref, return the place.
#[inline]
@ -86,6 +86,43 @@ impl<V> OperandValue<V> {
};
OperandValue::Pair(a, b)
}
/// Treat this value as a pointer and return the data pointer and
/// optional metadata as backend values.
///
/// If you're making a place, use [`Self::deref`] instead.
pub fn pointer_parts(self) -> (V, Option<V>) {
match self {
OperandValue::Immediate(llptr) => (llptr, None),
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
_ => bug!("OperandValue cannot be a pointer: {self:?}"),
}
}
/// Treat this value as a pointer and return the place to which it points.
///
/// The pointer immediate doesn't inherently know its alignment,
/// so you need to pass it in. If you want to get it from a type's ABI
/// alignment, then maybe you want [`OperandRef::deref`] instead.
///
/// This is the inverse of [`PlaceValue::address`].
pub fn deref(self, align: Align) -> PlaceValue<V> {
let (llval, llextra) = self.pointer_parts();
PlaceValue { llval, llextra, align }
}
pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeMethods<'tcx>>(
&self,
cx: &Cx,
ty: TyAndLayout<'tcx>,
) -> bool {
match self {
OperandValue::ZeroSized => ty.is_zst(),
OperandValue::Immediate(_) => cx.is_backend_immediate(ty),
OperandValue::Pair(_, _) => cx.is_backend_scalar_pair(ty),
OperandValue::Ref(_) => cx.is_backend_ref(ty),
}
}
}
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
@ -235,6 +272,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
}
}
/// Asserts that this operand is a pointer (or reference) and returns
/// the place to which it points. (This requires no code to be emitted
/// as we represent places using the pointer to the place.)
///
/// This uses [`Ty::builtin_deref`] to include the type of the place and
/// assumes the place is aligned to the pointee's usual ABI alignment.
///
/// If you don't need the type, see [`OperandValue::pointer_parts`]
/// or [`OperandValue::deref`].
pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
if self.layout.ty.is_box() {
// Derefer should have removed all Box derefs
@ -247,15 +293,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));
let (llptr, llextra) = match self.val {
OperandValue::Immediate(llptr) => (llptr, None),
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
};
let layout = cx.layout_of(projected_ty);
let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi };
PlaceRef { val, layout }
self.val.deref(layout.align.abi).with_type(layout)
}
/// If this operand is a `Pair`, we return an aggregate with the two values.
@ -448,8 +487,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
if val.llextra.is_some() {
bug!("cannot directly store unsized values");
}
let source_place = PlaceRef { val, layout: dest.layout };
bx.typed_place_copy_with_flags(dest, source_place, flags);
bx.typed_place_copy_with_flags(dest.val, val, dest.layout, flags);
}
OperandValue::Immediate(s) => {
let val = bx.from_immediate(s);

View file

@ -10,12 +10,15 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding};
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
/// The location and extra runtime properties of the place.
///
/// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
///
/// As a location in memory, this has no specific type. If you want to
/// load or store it using a typed operation, use [`Self::with_type`].
#[derive(Copy, Clone, Debug)]
pub struct PlaceValue<V> {
/// A pointer to the contents of the place.
@ -35,6 +38,41 @@ impl<V: CodegenObject> PlaceValue<V> {
pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> {
PlaceValue { llval, llextra: None, align }
}
/// Allocates a stack slot in the function for a value
/// of the specified size and alignment.
///
/// The allocation itself is untyped.
pub fn alloca<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
size: Size,
align: Align,
) -> PlaceValue<V> {
let llval = bx.alloca(size, align);
PlaceValue::new_sized(llval, align)
}
/// Creates a `PlaceRef` to this location with the given type.
pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
debug_assert!(
layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
"Had pointer metadata {:?} for sized type {layout:?}",
self.llextra,
);
PlaceRef { val: self, layout }
}
/// Gets the pointer to this place as an [`OperandValue::Immediate`]
/// or, for those needing metadata, an [`OperandValue::Pair`].
///
/// This is the inverse of [`OperandValue::deref`].
pub fn address(self) -> OperandValue<V> {
if let Some(llextra) = self.llextra {
OperandValue::Pair(self.llval, llextra)
} else {
OperandValue::Immediate(self.llval)
}
}
}
#[derive(Copy, Clone, Debug)]
@ -52,9 +90,7 @@ pub struct PlaceRef<'tcx, V> {
impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
assert!(layout.is_sized());
let val = PlaceValue::new_sized(llval, layout.align.abi);
PlaceRef { val, layout }
PlaceRef::new_sized_aligned(llval, layout, layout.align.abi)
}
pub fn new_sized_aligned(
@ -63,8 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
align: Align,
) -> PlaceRef<'tcx, V> {
assert!(layout.is_sized());
let val = PlaceValue::new_sized(llval, align);
PlaceRef { val, layout }
PlaceValue::new_sized(llval, align).with_type(layout)
}
// FIXME(eddyb) pass something else for the name so no work is done
@ -72,18 +107,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
Self::alloca_aligned(bx, layout, layout.align.abi)
}
pub fn alloca_aligned<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
align: Align,
) -> Self {
assert!(layout.is_sized(), "tried to statically allocate unsized place");
let tmp = bx.alloca(layout.size, align);
Self::new_sized_aligned(tmp, layout, align)
PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout)
}
/// Returns a place for an indirect reference to an unsized place.
@ -132,18 +158,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
} else {
bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes()))
};
PlaceRef {
val: PlaceValue {
let val = PlaceValue {
llval,
llextra: if bx.cx().type_has_metadata(field.ty) {
self.val.llextra
} else {
None
},
llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None },
align: effective_field_align,
},
layout: field,
}
};
val.with_type(field)
};
// Simple cases, which don't need DST adjustment:
@ -198,7 +218,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
let ptr = bx.inbounds_ptradd(self.val.llval, offset);
let val =
PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align };
PlaceRef { val, layout: field }
val.with_type(field)
}
/// Obtain the actual discriminant of a value.
@ -387,18 +407,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
layout.size
};
PlaceRef {
val: PlaceValue {
llval: bx.inbounds_gep(
let llval = bx.inbounds_gep(
bx.cx().backend_type(self.layout),
self.val.llval,
&[bx.cx().const_usize(0), llindex],
),
llextra: None,
align: self.val.align.restrict_for_offset(offset),
},
layout,
}
);
let align = self.val.align.restrict_for_offset(offset);
PlaceValue::new_sized(llval, align).with_type(layout)
}
pub fn project_downcast<Bx: BuilderMethods<'a, 'tcx, Value = V>>(

View file

@ -74,8 +74,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if val.llextra.is_some() {
bug!("unsized coercion on an unsized rvalue");
}
let source = PlaceRef { val, layout: operand.layout };
base::coerce_unsized_into(bx, source, dest);
base::coerce_unsized_into(bx, val.with_type(operand.layout), dest);
}
OperandValue::ZeroSized => {
bug!("unsized coercion on a ZST rvalue");
@ -184,10 +183,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandValue::Immediate(..) | OperandValue::Pair(..) => {
// When we have immediate(s), the alignment of the source is irrelevant,
// so we can store them using the destination's alignment.
src.val.store(
bx,
PlaceRef::new_sized_aligned(dst.val.llval, src.layout, dst.val.align),
);
src.val.store(bx, dst.val.with_type(src.layout));
}
}
}
@ -225,8 +221,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandValue::Ref(source_place_val) => {
debug_assert_eq!(source_place_val.llextra, None);
debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
let fake_place = PlaceRef { val: source_place_val, layout: cast };
Some(bx.load_operand(fake_place).val)
Some(bx.load_operand(source_place_val.with_type(cast)).val)
}
OperandValue::ZeroSized => {
let OperandValueKind::ZeroSized = operand_kind else {
@ -452,23 +447,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => {
assert!(bx.cx().is_backend_scalar_pair(cast));
let (lldata, llextra) = match operand.val {
OperandValue::Pair(lldata, llextra) => {
// unsize from a fat pointer -- this is a
// "trait-object-to-supertrait" coercion.
(lldata, Some(llextra))
}
OperandValue::Immediate(lldata) => {
// "standard" unsize
(lldata, None)
}
OperandValue::Ref(..) => {
bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
}
OperandValue::ZeroSized => {
bug!("zero-sized operand {:?} in `codegen_rvalue_operand`", operand);
}
};
let (lldata, llextra) = operand.val.pointer_parts();
let (lldata, llextra) =
base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra);
OperandValue::Pair(lldata, llextra)
@ -489,12 +468,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::CastKind::DynStar => {
let (lldata, llextra) = match operand.val {
OperandValue::Ref(..) => todo!(),
OperandValue::Immediate(v) => (v, None),
OperandValue::Pair(v, l) => (v, Some(l)),
OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"),
};
let (lldata, llextra) = operand.val.pointer_parts();
let (lldata, llextra) =
base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra);
OperandValue::Pair(lldata, llextra)
@ -722,24 +696,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandRef { val: OperandValue::Immediate(static_), layout }
}
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
mir::Rvalue::Aggregate(box mir::AggregateKind::RawPtr(..), ref fields) => {
let ty = rvalue.ty(self.mir, self.cx.tcx());
let layout = self.cx.layout_of(self.monomorphize(ty));
let [data, meta] = &*fields.raw else {
bug!("RawPtr fields: {fields:?}");
};
let data = self.codegen_operand(bx, data);
let meta = self.codegen_operand(bx, meta);
match (data.val, meta.val) {
(p @ OperandValue::Immediate(_), OperandValue::ZeroSized) => {
OperandRef { val: p, layout }
}
(OperandValue::Immediate(p), OperandValue::Immediate(m)) => {
OperandRef { val: OperandValue::Pair(p, m), layout }
}
_ => bug!("RawPtr operands {data:?} {meta:?}"),
}
}
mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),
mir::Rvalue::Aggregate(_, ref fields) => {
let ty = rvalue.ty(self.mir, self.cx.tcx());
@ -774,6 +730,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
);
let val = OperandValue::from_immediates(inputs);
debug_assert!(
val.is_expected_variant_for_type(self.cx, layout),
"Made wrong variant {val:?} for type {layout:?}",
);
OperandRef { val, layout }
}
mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
@ -812,16 +772,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
) -> OperandRef<'tcx, Bx::Value> {
let cg_place = self.codegen_place(bx, place.as_ref());
let val = cg_place.val.address();
let ty = cg_place.layout.ty;
debug_assert!(
if bx.cx().type_has_metadata(ty) {
matches!(val, OperandValue::Pair(..))
} else {
matches!(val, OperandValue::Immediate(..))
},
"Address of place was unexpectedly {val:?} for pointee type {ty:?}",
);
// Note: places are indirect, so storing the `llval` into the
// destination effectively creates a reference.
let val = if !bx.cx().type_has_metadata(ty) {
OperandValue::Immediate(cg_place.val.llval)
} else {
OperandValue::Pair(cg_place.val.llval, cg_place.val.llextra.unwrap())
};
OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) }
}

View file

@ -186,6 +186,15 @@ pub trait BuilderMethods<'a, 'tcx>:
align: Align,
flags: MemFlags,
) -> Self::Value;
fn store_to_place_with_flags(
&mut self,
val: Self::Value,
place: PlaceValue<Self::Value>,
flags: MemFlags,
) -> Self::Value {
debug_assert_eq!(place.llextra, None);
self.store_with_flags(val, place.llval, place.align, flags)
}
fn atomic_store(
&mut self,
val: Self::Value,
@ -286,35 +295,36 @@ pub trait BuilderMethods<'a, 'tcx>:
/// (For example, typed load-stores with alias metadata.)
fn typed_place_copy(
&mut self,
dst: PlaceRef<'tcx, Self::Value>,
src: PlaceRef<'tcx, Self::Value>,
dst: PlaceValue<Self::Value>,
src: PlaceValue<Self::Value>,
layout: TyAndLayout<'tcx>,
) {
self.typed_place_copy_with_flags(dst, src, MemFlags::empty());
self.typed_place_copy_with_flags(dst, src, layout, MemFlags::empty());
}
fn typed_place_copy_with_flags(
&mut self,
dst: PlaceRef<'tcx, Self::Value>,
src: PlaceRef<'tcx, Self::Value>,
dst: PlaceValue<Self::Value>,
src: PlaceValue<Self::Value>,
layout: TyAndLayout<'tcx>,
flags: MemFlags,
) {
debug_assert!(src.val.llextra.is_none(), "cannot directly copy from unsized values");
debug_assert!(dst.val.llextra.is_none(), "cannot directly copy into unsized values");
debug_assert_eq!(dst.layout.size, src.layout.size);
debug_assert!(layout.is_sized(), "cannot typed-copy an unsigned type");
debug_assert!(src.llextra.is_none(), "cannot directly copy from unsized values");
debug_assert!(dst.llextra.is_none(), "cannot directly copy into unsized values");
if flags.contains(MemFlags::NONTEMPORAL) {
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
let ty = self.backend_type(dst.layout);
let val = self.load_from_place(ty, src.val);
self.store_with_flags(val, dst.val.llval, dst.val.align, flags);
} else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout)
{
let ty = self.backend_type(layout);
let val = self.load_from_place(ty, src);
self.store_to_place_with_flags(val, dst, flags);
} else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(layout) {
// If we're not optimizing, the aliasing information from `memcpy`
// isn't useful, so just load-store the value for smaller code.
let temp = self.load_operand(src);
temp.val.store_with_flags(self, dst, flags);
} else if !dst.layout.is_zst() {
let bytes = self.const_usize(dst.layout.size.bytes());
self.memcpy(dst.val.llval, dst.val.align, src.val.llval, src.val.align, bytes, flags);
let temp = self.load_operand(src.with_type(layout));
temp.val.store_with_flags(self, dst.with_type(layout), flags);
} else if !layout.is_zst() {
let bytes = self.const_usize(layout.size.bytes());
self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags);
}
}
@ -327,18 +337,19 @@ pub trait BuilderMethods<'a, 'tcx>:
/// cases (in non-debug), preferring the fallback body instead.
fn typed_place_swap(
&mut self,
left: PlaceRef<'tcx, Self::Value>,
right: PlaceRef<'tcx, Self::Value>,
left: PlaceValue<Self::Value>,
right: PlaceValue<Self::Value>,
layout: TyAndLayout<'tcx>,
) {
let mut temp = self.load_operand(left);
let mut temp = self.load_operand(left.with_type(layout));
if let OperandValue::Ref(..) = temp.val {
// The SSA value isn't stand-alone, so we need to copy it elsewhere
let alloca = PlaceRef::alloca(self, left.layout);
self.typed_place_copy(alloca, left);
let alloca = PlaceRef::alloca(self, layout);
self.typed_place_copy(alloca.val, left, layout);
temp = self.load_operand(alloca);
}
self.typed_place_copy(left, right);
temp.val.store(self, right);
self.typed_place_copy(left, right, layout);
temp.val.store(self, right.with_type(layout));
}
fn select(

View file

@ -1,9 +1,12 @@
use crate::interpret::{self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic};
use crate::interpret::{
self, throw_machine_stop, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic,
};
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
use rustc_middle::mir::*;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
/// Macro for machine-specific `InterpError` without allocation.

View file

@ -11,6 +11,7 @@ use rustc_span::{Span, Symbol};
use super::CompileTimeInterpreter;
use crate::errors::{self, FrameNote, ReportErrorExt};
use crate::interpret::{err_inval, err_machine_stop};
use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
/// The CTFE machine has some custom error kinds.

View file

@ -3,6 +3,7 @@ use std::sync::atomic::Ordering::Relaxed;
use either::{Left, Right};
use rustc_hir::def::DefKind;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
use rustc_middle::query::TyCtxtAt;
@ -24,7 +25,7 @@ use crate::interpret::{
InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
StackPopCleanup,
};
use crate::interpret::{eval_nullary_intrinsic, InternResult};
use crate::interpret::{eval_nullary_intrinsic, throw_exhaust, InternResult};
use crate::CTRL_C_RECEIVED;
// Returns a pointer to where the result lives

View file

@ -10,6 +10,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::mir::AssertMessage;
use rustc_middle::query::TyCtxtAt;
@ -24,8 +25,9 @@ use rustc_target::spec::abi::Abi as CallAbi;
use crate::errors::{LongRunning, LongRunningWarn};
use crate::fluent_generated as fluent;
use crate::interpret::{
self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal,
Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom,
throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
};
use super::error::*;

View file

@ -1,5 +1,6 @@
// Not in interpret to make sure we do not use private implementation details
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::mir::interpret::InterpErrorInfo;
use rustc_middle::query::{Key, TyCtxtAt};

View file

@ -1,4 +1,5 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};

View file

@ -7,11 +7,13 @@ use rustc_middle::mir::CastKind;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, Ty};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::Integer;
use rustc_type_ir::TyKind::*;
use super::{
util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
err_inval, throw_ub, throw_ub_custom, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate,
InterpCx, Machine, OpTy, PlaceTy,
};
use crate::fluent_generated as fluent;

View file

@ -1,12 +1,15 @@
//! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines).
use rustc_middle::mir;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
use rustc_middle::ty::{self, ScalarInt, Ty};
use rustc_target::abi::{self, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable};
use super::{
err_ub, throw_ub, ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable,
};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Writes the discriminant of the given variant.

View file

@ -17,15 +17,17 @@ use rustc_middle::ty::layout::{
TyAndLayout,
};
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_session::Limit;
use rustc_span::Span;
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
use super::{
GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable,
Provenance, Scalar, StackPopJump,
err_inval, throw_inval, throw_ub, throw_ub_custom, throw_unsup, GlobalId, Immediate,
InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind,
OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance, Scalar,
StackPopJump,
};
use crate::errors;
use crate::util;

View file

@ -24,7 +24,7 @@ use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
use super::{err_ub, AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
use crate::const_eval;
use crate::errors::NestedStaticInThreadLocal;

View file

@ -8,6 +8,7 @@ use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_middle::{
bug,
mir::{self, BinOp, ConstValue, NonDivergingIntrinsic},
ty::layout::TyAndLayout,
};
@ -15,9 +16,10 @@ use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::Size;
use super::{
memory::MemoryKind, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg,
ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer,
PointerArithmetic, Scalar,
err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom,
throw_ub_format, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, ConstAllocation,
GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic,
Scalar,
};
use crate::fluent_generated as fluent;

View file

@ -18,9 +18,9 @@ use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi;
use super::{
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg,
Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy,
Pointer, Provenance,
throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocKind, AllocRange, Allocation,
ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy,
MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
};
/// Data returned by Machine::stack_pop,

View file

@ -16,6 +16,7 @@ use std::ptr;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir::def::DefKind;
use rustc_middle::bug;
use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size};
@ -23,9 +24,10 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
use crate::fluent_generated as fluent;
use super::{
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg,
CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar,
alloc_range, err_ub, err_ub_custom, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
PointerArithmetic, Provenance, Scalar,
};
#[derive(Debug, PartialEq, Copy, Clone)]

View file

@ -10,13 +10,14 @@ use rustc_middle::mir::interpret::ScalarSizeMismatch;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_middle::{mir, ty};
use rustc_target::abi::{self, Abi, HasDataLayout, Size};
use super::{
alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, InterpCx, InterpResult,
MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable,
Provenance, Scalar,
alloc_range, err_ub, from_known_layout, mir_assign_valid_types, throw_ub, CtfeProvenance,
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy,
Pointer, Projectable, Provenance, Scalar,
};
/// An `Immediate` represents a single immediate self-contained Rust value.

View file

@ -3,10 +3,11 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::sym;
use rustc_target::abi::Abi;
use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
use super::{err_ub, throw_ub, throw_ub_custom, ImmTy, Immediate, InterpCx, Machine, PlaceTy};
use crate::fluent_generated as fluent;

View file

@ -11,12 +11,14 @@ use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{Abi, Align, HasDataLayout, Size};
use super::{
alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance,
ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar,
alloc_range, mir_assign_valid_types, throw_ub, AllocRef, AllocRefMut, CheckAlignMsg,
CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment,
OffsetMode, OpTy, Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable,
Scalar,
};
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]

View file

@ -14,10 +14,14 @@ use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_middle::{bug, span_bug};
use rustc_target::abi::Size;
use rustc_target::abi::{self, VariantIdx};
use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
use super::{
throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
Provenance, Scalar,
};
/// Describes the constraints placed on offset-projections.
#[derive(Copy, Clone, Debug)]

View file

@ -7,6 +7,7 @@ use either::Either;
use rustc_index::IndexSlice;
use rustc_middle::mir;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use super::{

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use either::Either;
use rustc_middle::span_bug;
use rustc_middle::{
mir,
ty::{
@ -19,8 +20,9 @@ use rustc_target::abi::{
use rustc_target::spec::abi::Abi;
use super::{
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
Projectable, Provenance, Scalar, StackPopCleanup,
throw_ub, throw_ub_custom, throw_unsup_format, CtfeProvenance, FnVal, ImmTy, InterpCx,
InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, Scalar,
StackPopCleanup,
};
use crate::fluent_generated as fluent;

View file

@ -1,5 +1,4 @@
use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult};
use crate::interpret::{MemPlaceMeta, MemoryKind};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
@ -9,7 +8,7 @@ use rustc_middle::ty::{
};
use std::ops::ControlFlow;
use super::{InterpCx, MPlaceTy};
use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
/// Checks whether a type contains generic parameters which must be instantiated.
///

View file

@ -13,6 +13,7 @@ use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
@ -27,9 +28,9 @@ use rustc_target::abi::{
use std::hash::Hash;
use super::{
format_interp_error, machine::AllocMap, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy,
Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable,
Scalar, ValueVisitor,
err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, CheckInAllocMsg,
GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
Pointer, Projectable, Scalar, ValueVisitor,
};
// for the validation errors

View file

@ -9,7 +9,7 @@ use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
use std::num::NonZero;
use super::{InterpCx, MPlaceTy, Machine, Projectable};
use super::{throw_inval, InterpCx, MPlaceTy, Machine, Projectable};
/// How to traverse a value and what to do when we are at the leaves.
pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {

View file

@ -22,8 +22,6 @@ Rust MIR: a lowered representation of Rust.
#[macro_use]
extern crate tracing;
#[macro_use]
extern crate rustc_middle;
pub mod const_eval;
mod errors;

View file

@ -8,10 +8,11 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt};
use rustc_mir_dataflow::Analysis;
use rustc_span::{sym, Span, Symbol};
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
@ -738,7 +739,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let cause = ObligationCause::new(
terminator.source_info.span,
self.body.source.def_id().expect_local(),
ObligationCauseCode::WhereClause(callee),
ObligationCauseCode::WhereClause(callee, DUMMY_SP),
);
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
ocx.register_obligations(traits::predicates_for_generics(

View file

@ -8,6 +8,7 @@ use rustc_attr as attr;
use rustc_errors::DiagCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
use rustc_span::Symbol;

View file

@ -8,6 +8,7 @@ use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::{self, CallSource};
use rustc_middle::span_bug;
use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
use rustc_middle::ty::{
self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef,

View file

@ -5,6 +5,7 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;

View file

@ -9,6 +9,7 @@ use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
use rustc_middle::{bug, span_bug};
use rustc_target::abi::{Size, FIRST_VARIANT};
use rustc_target::spec::abi::Abi;

View file

@ -1,4 +1,5 @@
use rustc_hir::LangItem;
use rustc_middle::bug;
use rustc_middle::mir;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::LayoutOf;

View file

@ -1,3 +1,4 @@
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};

View file

@ -1,6 +1,7 @@
use rustc_data_structures::intern::Interned;
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::DisambiguatedDefPathData;
use rustc_middle::bug;
use rustc_middle::ty::{
self,
print::{PrettyPrinter, Print, PrintError, Printer},

View file

@ -9,7 +9,7 @@ arrayvec = { version = "0.7", default-features = false }
bitflags = "2.4.1"
either = "1.0"
elsa = "=1.7.1"
ena = "0.14.2"
ena = "0.14.3"
indexmap = { version = "2.0.0" }
jobserver_crate = { version = "0.1.28", package = "jobserver" }
libc = "0.2"

View file

@ -11,6 +11,7 @@
#![allow(internal_features)]
#![feature(decl_macro)]
#![feature(let_chains)]
#![feature(panic_backtrace_config)]
#![feature(panic_update_hook)]
#![feature(result_flattening)]
@ -1317,8 +1318,8 @@ pub fn install_ice_hook(
// by the user. Compiler developers and other rustc users can
// opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
// (e.g. `RUST_BACKTRACE=1`)
if std::env::var_os("RUST_BACKTRACE").is_none() {
std::env::set_var("RUST_BACKTRACE", "full");
if env::var_os("RUST_BACKTRACE").is_none() {
panic::set_backtrace_style(panic::BacktraceStyle::Full);
}
let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());

View file

@ -1,4 +1,4 @@
#### Note: this error code is no longer emitted by the compiler`
#### Note: this error code is no longer emitted by the compiler
Plugin `..` only found in rlib format, but must be available in dylib format.

View file

@ -100,6 +100,12 @@ impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
}
}
impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTraitRef<I> {
fn into_diag_arg(self) -> DiagArgValue {
self.to_string().into_diag_arg()
}
}
into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
impl IntoDiagArg for bool {

View file

@ -201,10 +201,17 @@ impl<'a> StripUnconfigured<'a> {
inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
}
AttrTokenTree::Token(ref token, _)
if let TokenKind::Interpolated(nt) = &token.kind =>
{
panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
AttrTokenTree::Token(
Token {
kind:
TokenKind::NtIdent(..)
| TokenKind::NtLifetime(..)
| TokenKind::Interpolated(..),
..
},
_,
) => {
panic!("Nonterminal should have been flattened: {:?}", tree);
}
AttrTokenTree::Token(token, spacing) => {
Some(AttrTokenTree::Token(token, spacing)).into_iter()

View file

@ -73,12 +73,6 @@ pub(super) fn failed_to_match_macro<'cx>(
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_)))
{
if let TokenKind::Interpolated(node) = &expected_token.kind {
err.span_label(node.1, "");
}
if let TokenKind::Interpolated(node) = &token.kind {
err.span_label(node.1, "");
}
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");

View file

@ -75,10 +75,9 @@ pub(crate) use ParseResult::*;
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::ErrorGuaranteed;
use rustc_lint_defs::pluralize;
use rustc_parse::parser::{ParseNtResult, Parser};
@ -392,7 +391,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
#[derive(Debug, Clone)]
pub(crate) enum NamedMatch {
MatchedSeq(Vec<NamedMatch>),
MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
MatchedSingle(ParseNtResult),
}
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@ -686,11 +685,7 @@ impl TtParser {
}
Ok(nt) => nt,
};
mp.push_match(
next_metavar,
seq_depth,
MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
);
mp.push_match(next_metavar, seq_depth, MatchedSingle(nt));
mp.idx += 1;
} else {
unreachable!()

View file

@ -261,6 +261,16 @@ pub(super) fn transcribe<'a>(
// without wrapping them into groups.
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
}
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
marker.visit_span(&mut sp);
let kind = token::NtIdent(*ident, *is_raw);
TokenTree::token_alone(kind, sp)
}
MatchedSingle(ParseNtResult::Lifetime(ident)) => {
marker.visit_span(&mut sp);
let kind = token::NtLifetime(*ident);
TokenTree::token_alone(kind, sp)
}
MatchedSingle(ParseNtResult::Nt(nt)) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities.

View file

@ -127,7 +127,7 @@ impl MultiItemModifier for DeriveProcMacro {
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
_ => unreachable!(),
};
TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
} else {
item.to_tokens()
};

View file

@ -220,6 +220,12 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
Ident(sym, is_raw) => {
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
}
NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
sym: ident.name,
is_raw: is_raw.into(),
span: ident.span,
})),
Lifetime(name) => {
let ident = symbol::Ident::new(name, span).without_first_quote();
trees.extend([
@ -227,6 +233,15 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
]);
}
NtLifetime(ident) => {
let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span);
trees.push(TokenTree::Group(Group {
delimiter: pm::Delimiter::None,
stream: Some(stream),
span: DelimSpan::from_single(span),
}))
}
Literal(token::Lit { kind, symbol, suffix }) => {
trees.push(TokenTree::Literal(self::Literal {
kind: FromInternal::from_internal(kind),
@ -259,23 +274,15 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
}));
}
Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
trees.push(TokenTree::Ident(Ident {
sym: ident.name,
is_raw: matches!(is_raw, IdentIsRaw::Yes),
span: ident.span,
}))
}
Interpolated(nt) => {
let stream = TokenStream::from_nonterminal_ast(&nt.0);
let stream = TokenStream::from_nonterminal_ast(&nt);
// A hack used to pass AST fragments to attribute and derive
// macros as a single nonterminal token instead of a token
// stream. Such token needs to be "unwrapped" and not
// represented as a delimited group.
// FIXME: It needs to be removed, but there are some
// compatibility issues (see #73345).
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) {
trees.extend(Self::from_internal((stream, rustc)));
} else {
trees.push(TokenTree::Group(Group {

View file

@ -2631,7 +2631,7 @@ pub struct OpaqueTy<'hir> {
/// lowered as an associated type.
pub in_trait: bool,
/// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
pub precise_capturing_args: Option<&'hir [PreciseCapturingArg<'hir>]>,
pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
@ -2641,6 +2641,15 @@ pub enum PreciseCapturingArg<'hir> {
Param(PreciseCapturingNonLifetimeArg),
}
impl PreciseCapturingArg<'_> {
pub fn hir_id(self) -> HirId {
match self {
PreciseCapturingArg::Lifetime(lt) => lt.hir_id,
PreciseCapturingArg::Param(param) => param.hir_id,
}
}
}
/// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
/// resolution to. Lifetimes don't have this problem, and for them, it's actually
/// kind of detrimental to use a custom node type versus just using [`Lifetime`],

View file

@ -533,7 +533,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_id(item.hir_id()));
try_visit!(walk_generics(visitor, generics));
walk_list!(visitor, visit_param_bound, bounds);
if let Some(precise_capturing_args) = precise_capturing_args {
if let Some((precise_capturing_args, _)) = precise_capturing_args {
for arg in precise_capturing_args {
try_visit!(visitor.visit_precise_capturing_arg(arg));
}

View file

@ -14,6 +14,7 @@ use rustc_infer::traits::Obligation;
use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::span_bug;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@ -485,7 +486,7 @@ fn sanity_check_found_hidden_type<'tcx>(
fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
let hir::OpaqueTy { precise_capturing_args, .. } =
*tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let Some(precise_capturing_args) = precise_capturing_args else {
let Some((precise_capturing_args, _)) = precise_capturing_args else {
// No precise capturing args; nothing to validate
return;
};

View file

@ -19,6 +19,7 @@ use rustc_middle::ty::{
self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use rustc_trait_selection::regions::InferCtxtRegionExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@ -819,7 +820,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
ObligationCause::new(
self.span,
self.body_id,
ObligationCauseCode::SpannedWhereClause(proj.def_id, pred_span),
ObligationCauseCode::WhereClause(proj.def_id, pred_span),
),
self.param_env,
pred,
@ -2011,11 +2012,7 @@ pub(super) fn check_type_bounds<'tcx>(
},
);
let mk_cause = |span: Span| {
let code = if span.is_dummy() {
ObligationCauseCode::WhereClause(trait_ty.def_id)
} else {
ObligationCauseCode::SpannedWhereClause(trait_ty.def_id, span)
};
let code = ObligationCauseCode::WhereClause(trait_ty.def_id, span);
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
};
@ -2209,7 +2206,7 @@ fn param_env_with_gat_bounds<'tcx>(
_ => predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args),
projection_term: ty::AliasTerm::new(tcx, trait_ty.def_id, rebased_args),
term: normalize_impl_ty.into(),
},
bound_vars,
@ -2251,8 +2248,7 @@ fn try_report_async_mismatch<'tcx>(
};
for error in errors {
if let ObligationCauseCode::SpannedWhereClause(def_id, _) =
*error.root_obligation.cause.code()
if let ObligationCauseCode::WhereClause(def_id, _) = *error.root_obligation.cause.code()
&& def_id == async_future_def_id
&& let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred()
&& let Some(proj) = proj.no_bound_vars()

View file

@ -3,6 +3,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
use rustc_middle::span_bug;
use rustc_middle::traits::{ObligationCause, Reveal};
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,

Some files were not shown because too many files have changed in this diff Show more