Merge from rustc
This commit is contained in:
commit
1e7fba9e06
545 changed files with 9070 additions and 5305 deletions
2
.github/workflows/dependencies.yml
vendored
2
.github/workflows/dependencies.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
452
Cargo.lock
452
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -3250,6 +3250,7 @@ pub enum ItemKind {
|
|||
}
|
||||
|
||||
impl ItemKind {
|
||||
/// "a" or "an"
|
||||
pub fn article(&self) -> &'static str {
|
||||
use ItemKind::*;
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(..)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}),
|
||||
)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(",");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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: |
|
||||
|
|
|
|||
4
compiler/rustc_codegen_cranelift/.gitignore
vendored
4
compiler/rustc_codegen_cranelift/.gitignore
vendored
|
|
@ -1,8 +1,4 @@
|
|||
# Build artifacts during normal use
|
||||
/y.bin
|
||||
/y.bin.dSYM
|
||||
/y.exe
|
||||
/y.pdb
|
||||
/download
|
||||
/build
|
||||
/dist
|
||||
|
|
|
|||
|
|
@ -11,3 +11,6 @@ path = "main.rs"
|
|||
unstable-features = [] # for rust-analyzer
|
||||
|
||||
# Do not add any dependencies
|
||||
|
||||
[profile.dev]
|
||||
debug = 1
|
||||
|
|
|
|||
|
|
@ -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"])),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-04-23"
|
||||
channel = "nightly-2024-05-13"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(_) => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
7
compiler/rustc_codegen_cranelift/y.ps1
Normal file → Executable 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 -- "$@"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>>(
|
||||
|
|
|
|||
|
|
@ -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)) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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`],
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue