Auto merge of #142442 - matthiaskrgr:rollup-6yodjfx, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - rust-lang/rust#134847 (Implement asymmetrical precedence for closures and jumps) - rust-lang/rust#141491 (Delegate `<CStr as Debug>` to `ByteStr`) - rust-lang/rust#141770 (Merge `Cfg::render_long_html` and `Cfg::render_long_plain` methods common code) - rust-lang/rust#142069 (Introduce `-Zmacro-stats`) - rust-lang/rust#142158 (Tracking the old name of renamed unstable library features) - rust-lang/rust#142221 ([AIX] strip underlying xcoff object) - rust-lang/rust#142340 (miri: we can use apfloat's mul_add now) - rust-lang/rust#142379 (Add bootstrap option to compile a tool with features) - rust-lang/rust#142410 (intrinsics: rename min_align_of to align_of) - rust-lang/rust#142413 (rustc-dev-guide subtree update) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c359117819
97 changed files with 1094 additions and 311 deletions
|
|
@ -3234,9 +3234,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.2.2+llvm-462a31f5a5ab"
|
||||
version = "0.2.3+llvm-462a31f5a5ab"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
|
||||
checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"smallvec",
|
||||
|
|
|
|||
|
|
@ -381,6 +381,15 @@
|
|||
# "miri", "cargo-miri" # for dev/nightly channels
|
||||
#]
|
||||
|
||||
# Specify build configuration specific for some tool, such as enabled features.
|
||||
# This option has no effect on which tools are enabled: refer to the `tools` option for that.
|
||||
#
|
||||
# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
|
||||
#
|
||||
# The default value for the `features` array is `[]`. However, please note that other flags in
|
||||
# `bootstrap.toml` might influence the features enabled for some tools.
|
||||
#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
#verbose = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ pub struct Path {
|
|||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == *name
|
||||
&& segment == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
// Succeeds if the path has segments that are arg-free and match the given symbols.
|
||||
impl PartialEq<&[Symbol]> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, names: &&[Symbol]) -> bool {
|
||||
self.segments.len() == names.len()
|
||||
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.segments.len().hash_stable(hcx, hasher);
|
||||
|
|
@ -166,6 +175,14 @@ pub struct PathSegment {
|
|||
pub args: Option<P<GenericArgs>>,
|
||||
}
|
||||
|
||||
// Succeeds if the path segment is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for PathSegment {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
self.args.is_none() && self.ident.name == *name
|
||||
}
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
|
||||
|
|
@ -1441,11 +1458,15 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => ExprPrecedence::Jump,
|
||||
ExprKind::Break(_ /*label*/, value)
|
||||
| ExprKind::Ret(value)
|
||||
| ExprKind::Yield(YieldKind::Prefix(value))
|
||||
| ExprKind::Yeet(value) => match value {
|
||||
Some(_) => ExprPrecedence::Jump,
|
||||
None => ExprPrecedence::Unambiguous,
|
||||
},
|
||||
|
||||
ExprKind::Become(_) => ExprPrecedence::Jump,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
|
|
@ -1502,6 +1523,7 @@ impl Expr {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Yield(YieldKind::Postfix(..))
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
|
|||
State::new().item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
|
||||
State::new().assoc_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
|
||||
State::new().foreign_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn stmt_to_string(s: &ast::Stmt) -> String {
|
||||
State::new().stmt_to_string(s)
|
||||
}
|
||||
|
||||
pub fn path_to_string(p: &ast::Path) -> String {
|
||||
State::new().path_to_string(p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
Self::to_string(|s| s.print_item(i))
|
||||
}
|
||||
|
||||
fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
|
||||
Self::to_string(|s| s.print_assoc_item(i))
|
||||
}
|
||||
|
||||
fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
|
||||
Self::to_string(|s| s.print_foreign_item(i))
|
||||
}
|
||||
|
||||
fn path_to_string(&self, p: &ast::Path) -> String {
|
||||
Self::to_string(|s| s.print_path(p, false, 0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_ast::util::classify;
|
|||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{
|
||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
|
||||
FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
};
|
||||
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
|
|
@ -214,13 +214,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
// parenthesize `func` if this is a statement context in which without
|
||||
// parentheses, a statement boundary would occur inside `func` or
|
||||
|
|
@ -237,8 +230,16 @@ impl<'a> State<'a> {
|
|||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
|
||||
let func_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(func, needs_paren, func_fixup);
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
|
|
@ -281,9 +282,24 @@ impl<'a> State<'a> {
|
|||
rhs: &ast::Expr,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
let operator_can_begin_expr = match op {
|
||||
| BinOpKind::Sub // -x
|
||||
| BinOpKind::Mul // *x
|
||||
| BinOpKind::And // &&x
|
||||
| BinOpKind::Or // || x
|
||||
| BinOpKind::BitAnd // &x
|
||||
| BinOpKind::BitOr // |x| x
|
||||
| BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST
|
||||
| BinOpKind::Lt // <T as Trait>::CONST
|
||||
=> true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr);
|
||||
|
||||
let binop_prec = op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
let left_prec = left_fixup.precedence(lhs);
|
||||
let right_prec = fixup.precedence(rhs);
|
||||
|
||||
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
|
|
@ -312,18 +328,18 @@ impl<'a> State<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup);
|
||||
self.space();
|
||||
self.word_space(op.as_str());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression());
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +360,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -590,8 +606,8 @@ impl<'a> State<'a> {
|
|||
self.word_space("=");
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
|
|
@ -604,8 +620,8 @@ impl<'a> State<'a> {
|
|||
self.word_space(op.node.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
|
|
@ -618,10 +634,11 @@ impl<'a> State<'a> {
|
|||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression(),
|
||||
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
|
||||
expr_fixup,
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index, FixupContext::default());
|
||||
|
|
@ -634,10 +651,11 @@ impl<'a> State<'a> {
|
|||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.leftmost_subexpression(),
|
||||
start_fixup.precedence(e) < fake_prec,
|
||||
start_fixup,
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
|
|
@ -647,8 +665,8 @@ impl<'a> State<'a> {
|
|||
if let Some(e) = end {
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(e) < fake_prec,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -665,11 +683,10 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence() < ExprPrecedence::Jump
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
// Parenthesize `break 'inner: loop { break 'inner 1 } + 1`
|
||||
// ^---------------------------------^
|
||||
opt_label.is_none() && classify::leading_labeled_expr(expr),
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -684,11 +701,7 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
|
|
@ -697,21 +710,13 @@ impl<'a> State<'a> {
|
|||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
result,
|
||||
result.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(result, fixup.rightmost_subexpression());
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
|
||||
|
|
@ -761,11 +766,7 @@ impl<'a> State<'a> {
|
|||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::Expr;
|
||||
use rustc_ast::util::{classify, parser};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence};
|
||||
use rustc_ast::{Expr, ExprKind, YieldKind};
|
||||
|
||||
// The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`.
|
||||
// Fixups should be turned on in a targeted fashion where needed.
|
||||
|
|
@ -93,6 +94,24 @@ pub(crate) struct FixupContext {
|
|||
/// }
|
||||
/// ```
|
||||
parenthesize_exterior_struct_lit: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = (return) - 1; // without paren, this would return -1
|
||||
///
|
||||
/// let _ = return + 1; // no paren because '+' cannot begin expr
|
||||
/// ```
|
||||
next_operator_can_begin_expr: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = 1 + return 1; // no parens if rightmost subexpression
|
||||
///
|
||||
/// let _ = 1 + (return 1) + 1; // needs parens
|
||||
/// ```
|
||||
next_operator_can_continue_expr: bool,
|
||||
}
|
||||
|
||||
impl FixupContext {
|
||||
|
|
@ -134,6 +153,8 @@ impl FixupContext {
|
|||
match_arm: false,
|
||||
leftmost_subexpression_in_match_arm: self.match_arm
|
||||
|| self.leftmost_subexpression_in_match_arm,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
|
@ -148,19 +169,34 @@ impl FixupContext {
|
|||
leftmost_subexpression_in_stmt: false,
|
||||
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing any
|
||||
/// subexpression that is neither a leftmost subexpression nor surrounded in
|
||||
/// delimiters.
|
||||
/// Transform this fixup into the one that should apply when printing a
|
||||
/// leftmost subexpression followed by punctuation that is legal as the
|
||||
/// first token of an expression.
|
||||
pub(crate) fn leftmost_subexpression_with_operator(
|
||||
self,
|
||||
next_operator_can_begin_expr: bool,
|
||||
) -> Self {
|
||||
FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() }
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing the
|
||||
/// rightmost subexpression of the current expression.
|
||||
///
|
||||
/// This is for any subexpression that has a different first token than the
|
||||
/// current expression, and is not surrounded by a paren/bracket/brace. For
|
||||
/// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
|
||||
/// `$a.f($b)`.
|
||||
pub(crate) fn subsequent_subexpression(self) -> Self {
|
||||
/// The rightmost subexpression is any subexpression that has a different
|
||||
/// first token than the current expression, but has the same last token.
|
||||
///
|
||||
/// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
|
||||
/// rightmost subexpression.
|
||||
///
|
||||
/// Not every expression has a rightmost subexpression. For example neither
|
||||
/// `[$b]` nor `$a.f($b)` have one.
|
||||
pub(crate) fn rightmost_subexpression(self) -> Self {
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
|
|
@ -193,6 +229,39 @@ impl FixupContext {
|
|||
/// "let chain".
|
||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||
|| parser::needs_par_as_let_scrutinee(self.precedence(expr))
|
||||
}
|
||||
|
||||
/// Determines the effective precedence of a subexpression. Some expressions
|
||||
/// have higher or lower precedence when adjacent to particular operators.
|
||||
pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence {
|
||||
if self.next_operator_can_begin_expr {
|
||||
// Decrease precedence of value-less jumps when followed by an
|
||||
// operator that would otherwise get interpreted as beginning a
|
||||
// value for the jump.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Jump;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.next_operator_can_continue_expr {
|
||||
// Increase precedence of expressions that extend to the end of
|
||||
// current statement or group.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..))
|
||||
| ExprKind::Range(None, ..) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Prefix;
|
||||
}
|
||||
}
|
||||
|
||||
expr.precedence()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ pub enum StabilityLevel {
|
|||
/// fn foobar() {}
|
||||
/// ```
|
||||
implied_by: Option<Symbol>,
|
||||
old_name: Option<Symbol>,
|
||||
},
|
||||
/// `#[stable]`
|
||||
Stable {
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
let mut issue_num = None;
|
||||
let mut is_soft = false;
|
||||
let mut implied_by = None;
|
||||
let mut old_name = None;
|
||||
for param in args.list()?.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
|
|
@ -345,11 +346,12 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
Some(sym::implied_by) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?
|
||||
}
|
||||
Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?,
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param.span(),
|
||||
item: param.path().to_string(),
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by"],
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
|
@ -374,6 +376,7 @@ pub(crate) fn parse_unstability<S: Stage>(
|
|||
issue: issue_num,
|
||||
is_soft,
|
||||
implied_by,
|
||||
old_name,
|
||||
};
|
||||
Some((feature, level))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -644,9 +644,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -204,11 +204,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 16);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(
|
||||
intrinsics::min_align_of_val(&a) as u8,
|
||||
intrinsics::min_align_of::<&str>() as u8
|
||||
);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta);
|
||||
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
|
||||
}
|
||||
sym::min_align_of_val => {
|
||||
sym::align_of_val => {
|
||||
intrinsic_args!(fx, args => (ptr); intrinsic);
|
||||
|
||||
let layout = fx.layout_of(generic_args.type_at(0));
|
||||
|
|
@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
intrinsic_args!(fx, args => (vtable); intrinsic);
|
||||
let vtable = vtable.load_scalar(fx);
|
||||
|
||||
let align = crate::vtable::min_align_of_obj(fx, vtable);
|
||||
let align = crate::vtable::align_of_obj(fx, vtable);
|
||||
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
// load size/align from vtable
|
||||
(
|
||||
crate::vtable::size_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::min_align_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::align_of_obj(fx, info.unwrap()),
|
||||
)
|
||||
}
|
||||
ty::Slice(_) | ty::Str => {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
|
||||
fx.bcx.ins().load(
|
||||
fx.pointer_type,
|
||||
|
|
|
|||
|
|
@ -655,9 +655,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ fn main() {
|
|||
let slice = &[0, 1] as &[i32];
|
||||
let slice_ptr = slice as *const [i32] as *const i32;
|
||||
|
||||
let align = intrinsics::min_align_of::<*const i32>();
|
||||
let align = intrinsics::align_of::<*const i32>();
|
||||
assert_eq!(slice_ptr as usize % align, 0);
|
||||
|
||||
//return;
|
||||
|
|
@ -194,8 +194,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -1065,11 +1065,11 @@ fn link_natively(
|
|||
match strip {
|
||||
Strip::Debuginfo => {
|
||||
// FIXME: AIX's strip utility only offers option to strip line number information.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"])
|
||||
}
|
||||
Strip::Symbols => {
|
||||
// Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"])
|
||||
}
|
||||
Strip::None => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
llsize
|
||||
}
|
||||
sym::min_align_of_val => {
|
||||
sym::align_of_val => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let (_, meta) = args[0].val.pointer_parts();
|
||||
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&val, dest)?;
|
||||
}
|
||||
|
||||
sym::min_align_of_val | sym::size_of_val => {
|
||||
sym::align_of_val | sym::size_of_val => {
|
||||
// Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
|
||||
// dereferenceable!
|
||||
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
|
||||
|
|
@ -129,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
|
||||
|
||||
let result = match intrinsic_name {
|
||||
sym::min_align_of_val => align.bytes(),
|
||||
sym::align_of_val => align.bytes(),
|
||||
sym::size_of_val => size.bytes(),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,37 @@
|
|||
//! This is an extremely bare-bones alternative to the `thousands` crate on
|
||||
//! crates.io, for printing large numbers in a readable fashion.
|
||||
//! This is a bare-bones alternative to the `thousands` crate on crates.io, for
|
||||
//! printing large numbers in a readable fashion.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// Converts the number to a string, with underscores as the thousands separator.
|
||||
pub fn format_with_underscores(n: usize) -> String {
|
||||
let mut s = n.to_string();
|
||||
let mut i = s.len();
|
||||
while i > 3 {
|
||||
fn format_with_underscores(mut s: String) -> String {
|
||||
// Ignore a leading '-'.
|
||||
let start = if s.starts_with('-') { 1 } else { 0 };
|
||||
|
||||
// Stop after the first non-digit, e.g. '.' or 'e' for floats.
|
||||
let non_digit = s[start..].find(|c: char| !c.is_digit(10));
|
||||
let end = if let Some(non_digit) = non_digit { start + non_digit } else { s.len() };
|
||||
|
||||
// Insert underscores within `start..end`.
|
||||
let mut i = end;
|
||||
while i > start + 3 {
|
||||
i -= 3;
|
||||
s.insert(i, '_');
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Print a `usize` with underscore separators.
|
||||
pub fn usize_with_underscores(n: usize) -> String {
|
||||
format_with_underscores(format!("{n}"))
|
||||
}
|
||||
|
||||
/// Print an `isize` with underscore separators.
|
||||
pub fn isize_with_underscores(n: isize) -> String {
|
||||
format_with_underscores(format!("{n}"))
|
||||
}
|
||||
|
||||
/// Print an `f64` with precision 1 (one decimal place) and underscore separators.
|
||||
pub fn f64p1_with_underscores(n: f64) -> String {
|
||||
format_with_underscores(format!("{n:.1}"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,51 @@ use super::*;
|
|||
|
||||
#[test]
|
||||
fn test_format_with_underscores() {
|
||||
assert_eq!("0", format_with_underscores(0));
|
||||
assert_eq!("1", format_with_underscores(1));
|
||||
assert_eq!("99", format_with_underscores(99));
|
||||
assert_eq!("345", format_with_underscores(345));
|
||||
assert_eq!("1_000", format_with_underscores(1_000));
|
||||
assert_eq!("12_001", format_with_underscores(12_001));
|
||||
assert_eq!("999_999", format_with_underscores(999_999));
|
||||
assert_eq!("1_000_000", format_with_underscores(1_000_000));
|
||||
assert_eq!("12_345_678", format_with_underscores(12_345_678));
|
||||
assert_eq!("", format_with_underscores("".to_string()));
|
||||
assert_eq!("0", format_with_underscores("0".to_string()));
|
||||
assert_eq!("12_345.67e14", format_with_underscores("12345.67e14".to_string()));
|
||||
assert_eq!("-1_234.5678e10", format_with_underscores("-1234.5678e10".to_string()));
|
||||
assert_eq!("------", format_with_underscores("------".to_string()));
|
||||
assert_eq!("abcdefgh", format_with_underscores("abcdefgh".to_string()));
|
||||
assert_eq!("-1b", format_with_underscores("-1b".to_string()));
|
||||
assert_eq!("-3_456xyz", format_with_underscores("-3456xyz".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_usize_with_underscores() {
|
||||
assert_eq!("0", usize_with_underscores(0));
|
||||
assert_eq!("1", usize_with_underscores(1));
|
||||
assert_eq!("99", usize_with_underscores(99));
|
||||
assert_eq!("345", usize_with_underscores(345));
|
||||
assert_eq!("1_000", usize_with_underscores(1_000));
|
||||
assert_eq!("12_001", usize_with_underscores(12_001));
|
||||
assert_eq!("999_999", usize_with_underscores(999_999));
|
||||
assert_eq!("1_000_000", usize_with_underscores(1_000_000));
|
||||
assert_eq!("12_345_678", usize_with_underscores(12_345_678));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_isize_with_underscores() {
|
||||
assert_eq!("0", isize_with_underscores(0));
|
||||
assert_eq!("-1", isize_with_underscores(-1));
|
||||
assert_eq!("99", isize_with_underscores(99));
|
||||
assert_eq!("345", isize_with_underscores(345));
|
||||
assert_eq!("-1_000", isize_with_underscores(-1_000));
|
||||
assert_eq!("12_001", isize_with_underscores(12_001));
|
||||
assert_eq!("-999_999", isize_with_underscores(-999_999));
|
||||
assert_eq!("1_000_000", isize_with_underscores(1_000_000));
|
||||
assert_eq!("-12_345_678", isize_with_underscores(-12_345_678));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64p1_with_underscores() {
|
||||
assert_eq!("0.0", f64p1_with_underscores(0f64));
|
||||
assert_eq!("0.0", f64p1_with_underscores(0.00000001));
|
||||
assert_eq!("-0.0", f64p1_with_underscores(-0.00000001));
|
||||
assert_eq!("1.0", f64p1_with_underscores(0.9999999));
|
||||
assert_eq!("-1.0", f64p1_with_underscores(-0.9999999));
|
||||
assert_eq!("345.5", f64p1_with_underscores(345.4999999));
|
||||
assert_eq!("-100_000.0", f64p1_with_underscores(-100_000f64));
|
||||
assert_eq!("123_456_789.1", f64p1_with_underscores(123456789.123456789));
|
||||
assert_eq!("-123_456_789.1", f64p1_with_underscores(-123456789.123456789));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_ast::tokenstream::TokenStream;
|
|||
use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
|
||||
use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
|
||||
use rustc_feature::Features;
|
||||
|
|
@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind {
|
|||
/// A trivial attribute "macro" that does nothing,
|
||||
/// only keeps the attribute and marks it as inert,
|
||||
/// thus making it ineligible for further expansion.
|
||||
/// E.g. `#[default]`, `#[rustfmt::skip]`.
|
||||
NonMacroAttr,
|
||||
|
||||
/// A token-based derive macro.
|
||||
|
|
@ -1189,6 +1190,8 @@ pub struct ExtCtxt<'a> {
|
|||
/// in the AST, but insert it here so that we know
|
||||
/// not to expand it again.
|
||||
pub(super) expanded_inert_attrs: MarkedAttrs,
|
||||
/// `-Zmacro-stats` data.
|
||||
pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals
|
||||
}
|
||||
|
||||
impl<'a> ExtCtxt<'a> {
|
||||
|
|
@ -1218,6 +1221,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
expansions: FxIndexMap::default(),
|
||||
expanded_inert_attrs: MarkedAttrs::new(),
|
||||
buffered_early_lint: vec![],
|
||||
macro_stats: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,13 +42,22 @@ use crate::module::{
|
|||
DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod,
|
||||
};
|
||||
use crate::placeholders::{PlaceholderExpander, placeholder};
|
||||
use crate::stats::*;
|
||||
|
||||
macro_rules! ast_fragments {
|
||||
(
|
||||
$($Kind:ident($AstTy:ty) {
|
||||
$kind_name:expr;
|
||||
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
|
||||
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
|
||||
$(one
|
||||
fn $mut_visit_ast:ident;
|
||||
fn $visit_ast:ident;
|
||||
fn $ast_to_string:path;
|
||||
)?
|
||||
$(many
|
||||
fn $flat_map_ast_elt:ident;
|
||||
fn $visit_ast_elt:ident($($args:tt)*);
|
||||
fn $ast_to_string_elt:path;
|
||||
)?
|
||||
fn $make_ast:ident;
|
||||
})*
|
||||
) => {
|
||||
|
|
@ -61,7 +70,7 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
/// "Discriminant" of an AST fragment.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AstFragmentKind {
|
||||
OptExpr,
|
||||
MethodReceiverExpr,
|
||||
|
|
@ -151,6 +160,21 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub(crate) fn to_string(&self) -> String {
|
||||
match self {
|
||||
AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr),
|
||||
AstFragment::OptExpr(None) => unreachable!(),
|
||||
AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr),
|
||||
$($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)*
|
||||
$($(
|
||||
AstFragment::$Kind(ast) => {
|
||||
// The closure unwraps a `P` if present, or does nothing otherwise.
|
||||
elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast))
|
||||
}
|
||||
)?)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
|
||||
|
|
@ -163,76 +187,98 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
ast_fragments! {
|
||||
Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
|
||||
Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
|
||||
Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
|
||||
Expr(P<ast::Expr>) {
|
||||
"expression";
|
||||
one fn visit_expr; fn visit_expr; fn pprust::expr_to_string;
|
||||
fn make_expr;
|
||||
}
|
||||
Pat(P<ast::Pat>) {
|
||||
"pattern";
|
||||
one fn visit_pat; fn visit_pat; fn pprust::pat_to_string;
|
||||
fn make_pat;
|
||||
}
|
||||
Ty(P<ast::Ty>) {
|
||||
"type";
|
||||
one fn visit_ty; fn visit_ty; fn pprust::ty_to_string;
|
||||
fn make_ty;
|
||||
}
|
||||
Stmts(SmallVec<[ast::Stmt; 1]>) {
|
||||
"statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
|
||||
"statement";
|
||||
many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string;
|
||||
fn make_stmts;
|
||||
}
|
||||
Items(SmallVec<[P<ast::Item>; 1]>) {
|
||||
"item"; many fn flat_map_item; fn visit_item(); fn make_items;
|
||||
"item";
|
||||
many fn flat_map_item; fn visit_item(); fn pprust::item_to_string;
|
||||
fn make_items;
|
||||
}
|
||||
TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"trait item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Trait);
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait);
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_trait_items;
|
||||
}
|
||||
ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"impl item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_impl_items;
|
||||
}
|
||||
TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"impl item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_trait_impl_items;
|
||||
}
|
||||
ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
|
||||
"foreign item";
|
||||
many fn flat_map_foreign_item;
|
||||
fn visit_foreign_item();
|
||||
many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string;
|
||||
fn make_foreign_items;
|
||||
}
|
||||
Arms(SmallVec<[ast::Arm; 1]>) {
|
||||
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
|
||||
"match arm";
|
||||
many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string;
|
||||
fn make_arms;
|
||||
}
|
||||
ExprFields(SmallVec<[ast::ExprField; 1]>) {
|
||||
"field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
|
||||
"field expression";
|
||||
many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string;
|
||||
fn make_expr_fields;
|
||||
}
|
||||
PatFields(SmallVec<[ast::PatField; 1]>) {
|
||||
"field pattern";
|
||||
many fn flat_map_pat_field;
|
||||
fn visit_pat_field();
|
||||
many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string;
|
||||
fn make_pat_fields;
|
||||
}
|
||||
GenericParams(SmallVec<[ast::GenericParam; 1]>) {
|
||||
"generic parameter";
|
||||
many fn flat_map_generic_param;
|
||||
fn visit_generic_param();
|
||||
many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string;
|
||||
fn make_generic_params;
|
||||
}
|
||||
Params(SmallVec<[ast::Param; 1]>) {
|
||||
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
|
||||
"function parameter";
|
||||
many fn flat_map_param; fn visit_param(); fn unreachable_to_string;
|
||||
fn make_params;
|
||||
}
|
||||
FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
|
||||
"field";
|
||||
many fn flat_map_field_def;
|
||||
fn visit_field_def();
|
||||
many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string;
|
||||
fn make_field_defs;
|
||||
}
|
||||
Variants(SmallVec<[ast::Variant; 1]>) {
|
||||
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
|
||||
"variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string;
|
||||
fn make_variants;
|
||||
}
|
||||
WherePredicates(SmallVec<[ast::WherePredicate; 1]>) {
|
||||
"where predicate";
|
||||
many fn flat_map_where_predicate;
|
||||
fn visit_where_predicate();
|
||||
many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string;
|
||||
fn make_where_predicates;
|
||||
}
|
||||
Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
|
||||
}
|
||||
Crate(ast::Crate) {
|
||||
"crate";
|
||||
one fn visit_crate; fn visit_crate; fn unreachable_to_string;
|
||||
fn make_crate;
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SupportsMacroExpansion {
|
||||
|
|
@ -270,7 +316,7 @@ impl AstFragmentKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
||||
pub(crate) fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
||||
self,
|
||||
items: I,
|
||||
) -> AstFragment {
|
||||
|
|
@ -686,13 +732,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar));
|
||||
}
|
||||
|
||||
let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats;
|
||||
|
||||
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
|
||||
ExpandResult::Ready(match invoc.kind {
|
||||
InvocationKind::Bang { mac, span } => match ext {
|
||||
SyntaxExtensionKind::Bang(expander) => {
|
||||
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
|
||||
Ok(tok_result) => {
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
|
||||
let fragment =
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span);
|
||||
if macro_stats {
|
||||
update_bang_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
mac,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
||||
}
|
||||
|
|
@ -708,13 +767,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
};
|
||||
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
|
||||
result
|
||||
if let Some(fragment) = fragment_kind.make_from(tok_result) {
|
||||
if macro_stats {
|
||||
update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment);
|
||||
}
|
||||
fragment
|
||||
} else {
|
||||
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
|
||||
fragment_kind.dummy(span, guar)
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
|
@ -746,24 +807,39 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
_ => item.to_tokens(),
|
||||
};
|
||||
let attr_item = attr.unwrap_normal_item();
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
||||
}
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
match expander.expand(self.cx, span, inner_tokens, tokens) {
|
||||
Ok(tok_result) => self.parse_ast_fragment(
|
||||
tok_result,
|
||||
fragment_kind,
|
||||
&attr_item.path,
|
||||
span,
|
||||
),
|
||||
Ok(tok_result) => {
|
||||
let fragment = self.parse_ast_fragment(
|
||||
tok_result,
|
||||
fragment_kind,
|
||||
&attr_item.path,
|
||||
span,
|
||||
);
|
||||
if macro_stats {
|
||||
update_attr_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&attr_item.path,
|
||||
&attr,
|
||||
item,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
||||
}
|
||||
}
|
||||
SyntaxExtensionKind::LegacyAttr(expander) => {
|
||||
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
|
||||
Ok(meta) => {
|
||||
let item_clone = macro_stats.then(|| item.clone());
|
||||
let items = match expander.expand(self.cx, span, &meta, item, false) {
|
||||
ExpandResult::Ready(items) => items,
|
||||
ExpandResult::Retry(item) => {
|
||||
|
|
@ -782,7 +858,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span });
|
||||
fragment_kind.dummy(span, guar)
|
||||
} else {
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
let fragment = fragment_kind.expect_from_annotatables(items);
|
||||
if macro_stats {
|
||||
update_attr_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&meta.path,
|
||||
&attr,
|
||||
item_clone.unwrap(),
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
|
@ -792,6 +880,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
SyntaxExtensionKind::NonMacroAttr => {
|
||||
// `-Zmacro-stats` ignores these because they don't do any real expansion.
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
fragment_kind.expect_from_annotatables(iter::once(item))
|
||||
|
|
@ -822,7 +911,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
};
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
let fragment = fragment_kind.expect_from_annotatables(items);
|
||||
if macro_stats {
|
||||
update_derive_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&meta.path,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
|
@ -852,6 +951,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let single_delegations = build_single_delegations::<Node>(
|
||||
self.cx, deleg, &item, &suffixes, item.span, true,
|
||||
);
|
||||
// `-Zmacro-stats` ignores these because they don't seem important.
|
||||
fragment_kind.expect_from_annotatables(
|
||||
single_delegations
|
||||
.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ mod errors;
|
|||
mod mbe;
|
||||
mod placeholders;
|
||||
mod proc_macro_server;
|
||||
mod stats;
|
||||
|
||||
pub use mbe::macro_rules::compile_declarative_macro;
|
||||
pub mod base;
|
||||
|
|
|
|||
171
compiler/rustc_expand/src/stats.rs
Normal file
171
compiler/rustc_expand/src/stats.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::{Span, Symbol, kw, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::base::{Annotatable, ExtCtxt};
|
||||
use crate::expand::{AstFragment, AstFragmentKind};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MacroStat {
|
||||
/// Number of uses of the macro.
|
||||
pub uses: usize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `lines(output) - lines(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub lines: isize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `bytes(output) - bytes(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub bytes: isize,
|
||||
}
|
||||
|
||||
pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String {
|
||||
let mut s = String::new();
|
||||
for (i, elem) in elems.iter().enumerate() {
|
||||
if i > 0 {
|
||||
s.push('\n');
|
||||
}
|
||||
s.push_str(&f(elem));
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub(crate) fn unreachable_to_string<T>(_: &T) -> String {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn update_bang_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
mac: P<ast::MacCall>,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Does this path match any of the include macros, e.g. `include!`?
|
||||
// Ignore them. They would have large numbers but are entirely
|
||||
// unsurprising and uninteresting.
|
||||
let is_include_path = mac.path == sym::include
|
||||
|| mac.path == sym::include_bytes
|
||||
|| mac.path == sym::include_str
|
||||
|| mac.path == [sym::std, sym::include].as_slice() // std::include
|
||||
|| mac.path == [sym::std, sym::include_bytes].as_slice() // std::include_bytes
|
||||
|| mac.path == [sym::std, sym::include_str].as_slice(); // std::include_str
|
||||
if is_include_path {
|
||||
return;
|
||||
}
|
||||
|
||||
// The call itself (e.g. `println!("hi")`) is the input. Need to wrap
|
||||
// `mac` in something printable; `ast::Expr` is as good as anything
|
||||
// else.
|
||||
let expr = Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::MacCall(mac),
|
||||
span: Default::default(),
|
||||
attrs: Default::default(),
|
||||
tokens: None,
|
||||
};
|
||||
let input = pprust::expr_to_string(&expr);
|
||||
|
||||
// Get `mac` back out of `expr`.
|
||||
let ast::Expr { kind: ExprKind::MacCall(mac), .. } = expr else { unreachable!() };
|
||||
|
||||
update_macro_stats(ecx, MacroKind::Bang, fragment_kind, span, &mac.path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_attr_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
attr: &ast::Attribute,
|
||||
item: Annotatable,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Does this path match `#[derive(...)]` in any of its forms? If so,
|
||||
// ignore it because the individual derives will go through the
|
||||
// `Invocation::Derive` handling separately.
|
||||
let is_derive_path = *path == sym::derive
|
||||
// ::core::prelude::v1::derive
|
||||
|| *path == [kw::PathRoot, sym::core, sym::prelude, sym::v1, sym::derive].as_slice();
|
||||
if is_derive_path {
|
||||
return;
|
||||
}
|
||||
|
||||
// The attribute plus the item itself constitute the input, which we
|
||||
// measure.
|
||||
let input = format!(
|
||||
"{}\n{}",
|
||||
pprust::attribute_to_string(attr),
|
||||
fragment_kind.expect_from_annotatables(iter::once(item)).to_string(),
|
||||
);
|
||||
update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_derive_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Use something like `#[derive(Clone)]` for the measured input, even
|
||||
// though it may have actually appeared in a multi-derive attribute
|
||||
// like `#[derive(Clone, Copy, Debug)]`.
|
||||
let input = format!("#[derive({})]", pprust::path_to_string(path));
|
||||
update_macro_stats(ecx, MacroKind::Derive, fragment_kind, span, path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
macro_kind: MacroKind,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
input: &str,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
fn lines_and_bytes(s: &str) -> (usize, usize) {
|
||||
(s.trim_end().split('\n').count(), s.len())
|
||||
}
|
||||
|
||||
// Measure the size of the output by pretty-printing it and counting
|
||||
// the lines and bytes.
|
||||
let name = Symbol::intern(&pprust::path_to_string(path));
|
||||
let output = fragment.to_string();
|
||||
let (in_l, in_b) = lines_and_bytes(input);
|
||||
let (out_l, out_b) = lines_and_bytes(&output);
|
||||
|
||||
// This code is useful for debugging `-Zmacro-stats`. For every
|
||||
// invocation it prints the full input and output.
|
||||
if false {
|
||||
let name = ExpnKind::Macro(macro_kind, name).descr();
|
||||
let crate_name = &ecx.ecfg.crate_name;
|
||||
let span = ecx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_string(span, rustc_span::FileNameDisplayPreference::Local);
|
||||
eprint!(
|
||||
"\
|
||||
-------------------------------\n\
|
||||
{name}: [{crate_name}] ({fragment_kind:?}) {span}\n\
|
||||
-------------------------------\n\
|
||||
{input}\n\
|
||||
-- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\
|
||||
{output}\n\
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
// The recorded size is the difference between the input and the output.
|
||||
let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default());
|
||||
entry.uses += 1;
|
||||
entry.lines += out_l as isize - in_l as isize;
|
||||
entry.bytes += out_b as isize - in_b as isize;
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
|||
| sym::box_new
|
||||
| sym::breakpoint
|
||||
| sym::size_of
|
||||
| sym::min_align_of
|
||||
| sym::align_of
|
||||
| sym::needs_drop
|
||||
| sym::caller_location
|
||||
| sym::add_with_overflow
|
||||
|
|
@ -200,10 +200,8 @@ pub(crate) fn check_intrinsic_type(
|
|||
sym::abort => (0, 0, vec![], tcx.types.never),
|
||||
sym::unreachable => (0, 0, vec![], tcx.types.never),
|
||||
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
|
||||
sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
|
||||
(1, 0, vec![], tcx.types.usize)
|
||||
}
|
||||
sym::size_of_val | sym::min_align_of_val => {
|
||||
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
|
||||
sym::size_of_val | sym::align_of_val => {
|
||||
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
|
||||
}
|
||||
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use std::{env, fs, iter};
|
|||
use rustc_ast as ast;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::parallel;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
|
||||
use rustc_data_structures::{parallel, thousands};
|
||||
use rustc_expand::base::{ExtCtxt, LintStoreExpand};
|
||||
use rustc_feature::Features;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
|
|
@ -35,7 +35,8 @@ use rustc_session::parse::feature_err;
|
|||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::{
|
||||
DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
|
||||
DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
|
||||
Symbol, sym,
|
||||
};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use rustc_trait_selection::traits;
|
||||
|
|
@ -205,7 +206,7 @@ fn configure_and_expand(
|
|||
// Expand macros now!
|
||||
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
|
||||
|
||||
// The rest is error reporting
|
||||
// The rest is error reporting and stats
|
||||
|
||||
sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
|
||||
buffered_lints.append(&mut ecx.buffered_early_lint);
|
||||
|
|
@ -228,6 +229,10 @@ fn configure_and_expand(
|
|||
}
|
||||
}
|
||||
|
||||
if ecx.sess.opts.unstable_opts.macro_stats {
|
||||
print_macro_stats(&ecx);
|
||||
}
|
||||
|
||||
krate
|
||||
});
|
||||
|
||||
|
|
@ -288,6 +293,76 @@ fn configure_and_expand(
|
|||
krate
|
||||
}
|
||||
|
||||
fn print_macro_stats(ecx: &ExtCtxt<'_>) {
|
||||
use std::fmt::Write;
|
||||
|
||||
// No instability because we immediately sort the produced vector.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let mut macro_stats: Vec<_> = ecx
|
||||
.macro_stats
|
||||
.iter()
|
||||
.map(|((name, kind), stat)| {
|
||||
// This gives the desired sort order: sort by bytes, then lines, etc.
|
||||
(stat.bytes, stat.lines, stat.uses, name, *kind)
|
||||
})
|
||||
.collect();
|
||||
macro_stats.sort_unstable();
|
||||
macro_stats.reverse(); // bigger items first
|
||||
|
||||
let prefix = "macro-stats";
|
||||
let name_w = 32;
|
||||
let uses_w = 7;
|
||||
let lines_w = 11;
|
||||
let avg_lines_w = 11;
|
||||
let bytes_w = 11;
|
||||
let avg_bytes_w = 11;
|
||||
let banner_w = name_w + uses_w + lines_w + avg_lines_w + bytes_w + avg_bytes_w;
|
||||
|
||||
// We write all the text into a string and print it with a single
|
||||
// `eprint!`. This is an attempt to minimize interleaved text if multiple
|
||||
// rustc processes are printing macro-stats at the same time (e.g. with
|
||||
// `RUSTFLAGS='-Zmacro-stats' cargo build`). It still doesn't guarantee
|
||||
// non-interleaving, though.
|
||||
let mut s = String::new();
|
||||
_ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
|
||||
_ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name);
|
||||
_ = writeln!(
|
||||
s,
|
||||
"{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
|
||||
"Macro Name", "Uses", "Lines", "Avg Lines", "Bytes", "Avg Bytes",
|
||||
);
|
||||
_ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
|
||||
// It's helpful to print something when there are no entries, otherwise it
|
||||
// might look like something went wrong.
|
||||
if macro_stats.is_empty() {
|
||||
_ = writeln!(s, "{prefix} (none)");
|
||||
}
|
||||
for (bytes, lines, uses, name, kind) in macro_stats {
|
||||
let mut name = ExpnKind::Macro(kind, *name).descr();
|
||||
let avg_lines = lines as f64 / uses as f64;
|
||||
let avg_bytes = bytes as f64 / uses as f64;
|
||||
if name.len() >= name_w {
|
||||
// If the name is long, print it on a line by itself, then
|
||||
// set the name to empty and print things normally, to show the
|
||||
// stats on the next line.
|
||||
_ = writeln!(s, "{prefix} {:<name_w$}", name);
|
||||
name = String::new();
|
||||
}
|
||||
_ = writeln!(
|
||||
s,
|
||||
"{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
|
||||
name,
|
||||
thousands::usize_with_underscores(uses),
|
||||
thousands::isize_with_underscores(lines),
|
||||
thousands::f64p1_with_underscores(avg_lines),
|
||||
thousands::isize_with_underscores(bytes),
|
||||
thousands::f64p1_with_underscores(avg_bytes),
|
||||
);
|
||||
}
|
||||
_ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
|
||||
eprint!("{s}");
|
||||
}
|
||||
|
||||
fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
|
||||
let sess = tcx.sess;
|
||||
let (resolver, krate) = &*tcx.resolver_for_lowering().borrow();
|
||||
|
|
|
|||
|
|
@ -709,6 +709,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
untracked!(llvm_time_trace, true);
|
||||
untracked!(ls, vec!["all".to_owned()]);
|
||||
untracked!(macro_backtrace, true);
|
||||
untracked!(macro_stats, true);
|
||||
untracked!(meta_stats, true);
|
||||
untracked!(mir_include_spans, MirIncludeSpans::On);
|
||||
untracked!(nll_facts, true);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_data_structures::memmap::{Mmap, MmapMut};
|
||||
use rustc_data_structures::sync::{join, par_for_each_in};
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_data_structures::thousands::format_with_underscores;
|
||||
use rustc_data_structures::thousands::usize_with_underscores;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
|
||||
|
|
@ -789,7 +789,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
"{} {:<23}{:>10} ({:4.1}%)",
|
||||
prefix,
|
||||
label,
|
||||
format_with_underscores(size),
|
||||
usize_with_underscores(size),
|
||||
perc(size)
|
||||
);
|
||||
}
|
||||
|
|
@ -798,7 +798,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
"{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
|
||||
prefix,
|
||||
"Total",
|
||||
format_with_underscores(total_bytes),
|
||||
usize_with_underscores(total_bytes),
|
||||
perc(zero_bytes)
|
||||
);
|
||||
eprintln!("{prefix}");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub mod lib_features {
|
|||
#[derive(HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum FeatureStability {
|
||||
AcceptedSince(Symbol),
|
||||
Unstable,
|
||||
Unstable { old_name: Option<Symbol> },
|
||||
}
|
||||
|
||||
#[derive(HashStable, Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
match stability {
|
||||
Some(Stability {
|
||||
level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by },
|
||||
level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
|
||||
feature,
|
||||
..
|
||||
}) => {
|
||||
|
|
|
|||
|
|
@ -150,12 +150,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
|
|||
});
|
||||
terminator.kind = TerminatorKind::Goto { target };
|
||||
}
|
||||
sym::size_of | sym::min_align_of => {
|
||||
sym::size_of | sym::align_of => {
|
||||
let target = target.unwrap();
|
||||
let tp_ty = generic_args.type_at(0);
|
||||
let null_op = match intrinsic.name {
|
||||
sym::size_of => NullOp::SizeOf,
|
||||
sym::min_align_of => NullOp::AlignOf,
|
||||
sym::align_of => NullOp::AlignOf,
|
||||
_ => bug!("unexpected intrinsic"),
|
||||
};
|
||||
block.statements.push(Statement {
|
||||
|
|
|
|||
|
|
@ -719,6 +719,9 @@ passes_unknown_external_lang_item =
|
|||
passes_unknown_feature =
|
||||
unknown feature `{$feature}`
|
||||
|
||||
passes_unknown_feature_alias =
|
||||
feature `{$alias}` has been renamed to `{$feature}`
|
||||
|
||||
passes_unknown_lang_item =
|
||||
definition of an unknown lang item: `{$name}`
|
||||
.label = definition of unknown lang item `{$name}`
|
||||
|
|
|
|||
|
|
@ -1434,6 +1434,15 @@ pub(crate) struct UnknownFeature {
|
|||
pub feature: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_unknown_feature_alias, code = E0635)]
|
||||
pub(crate) struct RenamedFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub feature: Symbol,
|
||||
pub alias: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_implied_feature_not_exist)]
|
||||
pub(crate) struct ImpliedFeatureNotExist {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
use rustc_ast::visit::BoundKind;
|
||||
use rustc_ast::{self as ast, NodeId, visit as ast_visit};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::thousands::format_with_underscores;
|
||||
use rustc_data_structures::thousands::usize_with_underscores;
|
||||
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -140,10 +140,10 @@ impl<'k> StatCollector<'k> {
|
|||
"{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
|
||||
prefix,
|
||||
label,
|
||||
format_with_underscores(size),
|
||||
usize_with_underscores(size),
|
||||
percent(size, total_size),
|
||||
format_with_underscores(node.stats.count),
|
||||
format_with_underscores(node.stats.size)
|
||||
usize_with_underscores(node.stats.count),
|
||||
usize_with_underscores(node.stats.size)
|
||||
);
|
||||
if !node.subnodes.is_empty() {
|
||||
// We will soon sort, so the initial order does not matter.
|
||||
|
|
@ -159,9 +159,9 @@ impl<'k> StatCollector<'k> {
|
|||
"{} - {:<18}{:>10} ({:4.1}%){:>14}",
|
||||
prefix,
|
||||
label,
|
||||
format_with_underscores(size),
|
||||
usize_with_underscores(size),
|
||||
percent(size, total_size),
|
||||
format_with_underscores(subnode.count),
|
||||
usize_with_underscores(subnode.count),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -171,8 +171,8 @@ impl<'k> StatCollector<'k> {
|
|||
"{} {:<18}{:>10} {:>14}",
|
||||
prefix,
|
||||
"Total",
|
||||
format_with_underscores(total_size),
|
||||
format_with_underscores(total_count),
|
||||
usize_with_underscores(total_size),
|
||||
usize_with_underscores(total_count),
|
||||
);
|
||||
eprintln!("{prefix}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||
};
|
||||
|
||||
let feature_stability = match level {
|
||||
StabilityLevel::Unstable { .. } => FeatureStability::Unstable,
|
||||
StabilityLevel::Unstable { old_name, .. } => FeatureStability::Unstable { old_name },
|
||||
StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
|
||||
StableSince::Version(v) => Symbol::intern(&v.to_string()),
|
||||
StableSince::Current => sym::env_CFG_RELEASE,
|
||||
|
|
@ -71,7 +71,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||
});
|
||||
}
|
||||
}
|
||||
(FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => {
|
||||
(FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable { .. }, _))) => {
|
||||
self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
|
||||
span,
|
||||
feature,
|
||||
|
|
@ -79,7 +79,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||
prev_declared: "unstable",
|
||||
});
|
||||
}
|
||||
(FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => {
|
||||
(FeatureStability::Unstable { .. }, Some((FeatureStability::AcceptedSince(_), _))) => {
|
||||
self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
|
||||
span,
|
||||
feature,
|
||||
|
|
@ -88,7 +88,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
|||
});
|
||||
}
|
||||
// duplicate `unstable` feature is ok.
|
||||
(FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {}
|
||||
(FeatureStability::Unstable { .. }, Some((FeatureStability::Unstable { .. }, _))) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -718,6 +718,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
|||
issue: NonZero::new(27812),
|
||||
is_soft: false,
|
||||
implied_by: None,
|
||||
old_name: None,
|
||||
},
|
||||
feature: sym::rustc_private,
|
||||
};
|
||||
|
|
@ -1161,8 +1162,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
|||
defined_features: &LibFeatures,
|
||||
all_implications: &UnordMap<Symbol, Symbol>,
|
||||
) {
|
||||
for (feature, since) in defined_features.to_sorted_vec() {
|
||||
if let FeatureStability::AcceptedSince(since) = since
|
||||
for (feature, stability) in defined_features.to_sorted_vec() {
|
||||
if let FeatureStability::AcceptedSince(since) = stability
|
||||
&& let Some(span) = remaining_lib_features.get(&feature)
|
||||
{
|
||||
// Warn if the user has enabled an already-stable lib feature.
|
||||
|
|
@ -1181,6 +1182,12 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
|||
// implications from this crate.
|
||||
remaining_implications.remove(&feature);
|
||||
|
||||
if let FeatureStability::Unstable { old_name: Some(alias) } = stability {
|
||||
if let Some(span) = remaining_lib_features.swap_remove(&alias) {
|
||||
tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
|
||||
}
|
||||
}
|
||||
|
||||
if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -974,7 +974,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
) {
|
||||
let span = path.span;
|
||||
if let Some(stability) = &ext.stability {
|
||||
if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
|
||||
if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } =
|
||||
stability.level
|
||||
{
|
||||
let feature = stability.feature;
|
||||
|
||||
|
|
|
|||
|
|
@ -2305,6 +2305,8 @@ options! {
|
|||
(space separated)"),
|
||||
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
|
||||
"show macro backtraces (default: no)"),
|
||||
macro_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||
"print some statistics about macro expansions (default: no)"),
|
||||
maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
|
||||
"save as much information as possible about the correspondence between MIR and HIR \
|
||||
as source scopes (default: no)"),
|
||||
|
|
|
|||
|
|
@ -1135,7 +1135,7 @@ impl ExpnKind {
|
|||
}
|
||||
|
||||
/// The kind of macro invocation or definition.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum MacroKind {
|
||||
/// A bang macro `foo!()`.
|
||||
|
|
|
|||
|
|
@ -429,6 +429,8 @@ symbols! {
|
|||
aggregate_raw_ptr,
|
||||
alias,
|
||||
align,
|
||||
align_of,
|
||||
align_of_val,
|
||||
alignment,
|
||||
all,
|
||||
alloc,
|
||||
|
|
@ -1353,8 +1355,6 @@ symbols! {
|
|||
message,
|
||||
meta,
|
||||
metadata_type,
|
||||
min_align_of,
|
||||
min_align_of_val,
|
||||
min_const_fn,
|
||||
min_const_generics,
|
||||
min_const_unsafe_fn,
|
||||
|
|
@ -1512,6 +1512,7 @@ symbols! {
|
|||
offset_of_nested,
|
||||
offset_of_slice,
|
||||
ok_or_else,
|
||||
old_name,
|
||||
omit_gdb_pretty_printer_section,
|
||||
on,
|
||||
on_unimplemented,
|
||||
|
|
@ -2288,6 +2289,7 @@ symbols! {
|
|||
usize_legacy_fn_max_value,
|
||||
usize_legacy_fn_min_value,
|
||||
usize_legacy_mod,
|
||||
v1,
|
||||
v8plus,
|
||||
va_arg,
|
||||
va_copy,
|
||||
|
|
@ -2675,7 +2677,7 @@ impl Interner {
|
|||
assert_eq!(
|
||||
strings.len(),
|
||||
init.len() + extra.len(),
|
||||
"`init` or `extra` contain duplicate symbols",
|
||||
"there are duplicate symbols in the rustc symbol list and the extra symbols added by the driver",
|
||||
);
|
||||
Interner(Lock::new(InternerInner { arena: Default::default(), strings }))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -714,6 +714,8 @@ impl ops::Deref for CString {
|
|||
}
|
||||
}
|
||||
|
||||
/// Delegates to the [`CStr`] implementation of [`fmt::Debug`],
|
||||
/// showing invalid UTF-8 as hex escapes.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Debug for CString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
|||
|
|
@ -162,10 +162,12 @@ impl fmt::Display for FromBytesUntilNulError {
|
|||
}
|
||||
}
|
||||
|
||||
/// Shows the underlying bytes as a normal string, with invalid UTF-8
|
||||
/// presented as hex escape sequences.
|
||||
#[stable(feature = "cstr_debug", since = "1.3.0")]
|
||||
impl fmt::Debug for CStr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\"{}\"", self.to_bytes().escape_ascii())
|
||||
fmt::Debug::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -926,8 +926,7 @@ pub const unsafe fn slice_get_unchecked<
|
|||
pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
|
||||
|
||||
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
|
||||
/// a size of `count` * `size_of::<T>()` and an alignment of
|
||||
/// `min_align_of::<T>()`
|
||||
/// a size of `count` * `size_of::<T>()` and an alignment of `align_of::<T>()`.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
/// # Safety
|
||||
|
|
@ -941,8 +940,7 @@ pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
|
|||
#[rustc_nounwind]
|
||||
pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize);
|
||||
/// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
|
||||
/// a size of `count * size_of::<T>()` and an alignment of
|
||||
/// `min_align_of::<T>()`
|
||||
/// a size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`.
|
||||
///
|
||||
/// The volatile parameter is set to `true`, so it will not be optimized out
|
||||
/// unless size is equal to zero.
|
||||
|
|
@ -952,8 +950,7 @@ pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
|
|||
#[rustc_nounwind]
|
||||
pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
|
||||
/// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
|
||||
/// size of `count * size_of::<T>()` and an alignment of
|
||||
/// `min_align_of::<T>()`.
|
||||
/// size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
/// # Safety
|
||||
|
|
@ -2649,7 +2646,7 @@ pub const fn size_of<T>() -> usize;
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic_const_stable_indirect]
|
||||
#[rustc_intrinsic]
|
||||
pub const fn min_align_of<T>() -> usize;
|
||||
pub const fn align_of<T>() -> usize;
|
||||
|
||||
/// Returns the number of variants of the type `T` cast to a `usize`;
|
||||
/// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
|
||||
|
|
@ -2689,7 +2686,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
|
|||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_intrinsic_const_stable_indirect]
|
||||
pub const unsafe fn min_align_of_val<T: ?Sized>(ptr: *const T) -> usize;
|
||||
pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
|
||||
|
||||
/// Gets a static string slice containing the name of a type.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")]
|
||||
pub fn min_align_of<T>() -> usize {
|
||||
intrinsics::min_align_of::<T>()
|
||||
intrinsics::align_of::<T>()
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
|
||||
|
|
@ -436,7 +436,7 @@ pub fn min_align_of<T>() -> usize {
|
|||
#[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")]
|
||||
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
// SAFETY: val is a reference, so it's a valid raw pointer
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
unsafe { intrinsics::align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of a type in bytes.
|
||||
|
|
@ -458,7 +458,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
#[rustc_promotable]
|
||||
#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
|
||||
pub const fn align_of<T>() -> usize {
|
||||
intrinsics::min_align_of::<T>()
|
||||
intrinsics::align_of::<T>()
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
|
||||
|
|
@ -477,10 +477,9 @@ pub const fn align_of<T>() -> usize {
|
|||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")]
|
||||
#[allow(deprecated)]
|
||||
pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
||||
// SAFETY: val is a reference, so it's a valid raw pointer
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
unsafe { intrinsics::align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
|
||||
|
|
@ -527,7 +526,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
|
|||
#[unstable(feature = "layout_for_ptr", issue = "69835")]
|
||||
pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
|
||||
// SAFETY: the caller must provide a valid raw pointer
|
||||
unsafe { intrinsics::min_align_of_val(val) }
|
||||
unsafe { intrinsics::align_of_val(val) }
|
||||
}
|
||||
|
||||
/// Returns `true` if dropping values of type `T` matters.
|
||||
|
|
@ -637,8 +636,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
|
|||
#[inline(always)]
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated_in_future)]
|
||||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_zeroed"]
|
||||
#[track_caller]
|
||||
#[rustc_const_stable(feature = "const_mem_zeroed", since = "1.75.0")]
|
||||
|
|
@ -677,8 +674,6 @@ pub const unsafe fn zeroed<T>() -> T {
|
|||
#[must_use]
|
||||
#[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated_in_future)]
|
||||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_uninitialized"]
|
||||
#[track_caller]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> {
|
|||
// is a no-op conversion in the `Try` implementation.
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<B, C> ops::Try for ControlFlow<B, C> {
|
||||
type Output = C;
|
||||
type Residual = ControlFlow<B, convert::Infallible>;
|
||||
|
|
@ -117,7 +117,7 @@ impl<B, C> ops::Try for ControlFlow<B, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
// Note: manually specifying the residual type instead of using the default to work around
|
||||
// https://github.com/rust-lang/rust/issues/99940
|
||||
impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ pub use self::try_trait::Residual;
|
|||
#[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
|
||||
pub use self::try_trait::Yeet;
|
||||
pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
pub use self::try_trait::{FromResidual, Try};
|
||||
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||
pub use self::unsize::CoerceUnsized;
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ use crate::ops::ControlFlow;
|
|||
/// R::from_output(accum)
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
#[rustc_on_unimplemented(
|
||||
on(
|
||||
all(from_desugaring = "TryBlock"),
|
||||
|
|
@ -130,7 +130,7 @@ use crate::ops::ControlFlow;
|
|||
#[lang = "Try"]
|
||||
pub trait Try: FromResidual {
|
||||
/// The type of the value produced by `?` when *not* short-circuiting.
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
type Output;
|
||||
|
||||
/// The type of the value passed to [`FromResidual::from_residual`]
|
||||
|
|
@ -154,7 +154,7 @@ pub trait Try: FromResidual {
|
|||
/// then typically you can use `Foo<std::convert::Infallible>` as its `Residual`
|
||||
/// type: that type will have a "hole" in the correct place, and will maintain the
|
||||
/// "foo-ness" of the residual so other types need to opt-in to interconversion.
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
type Residual;
|
||||
|
||||
/// Constructs the type from its `Output` type.
|
||||
|
|
@ -186,7 +186,7 @@ pub trait Try: FromResidual {
|
|||
/// assert_eq!(r, Some(4));
|
||||
/// ```
|
||||
#[lang = "from_output"]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
fn from_output(output: Self::Output) -> Self;
|
||||
|
||||
/// Used in `?` to decide whether the operator should produce a value
|
||||
|
|
@ -213,7 +213,7 @@ pub trait Try: FromResidual {
|
|||
/// );
|
||||
/// ```
|
||||
#[lang = "branch"]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +303,7 @@ pub trait Try: FromResidual {
|
|||
),
|
||||
)]
|
||||
#[rustc_diagnostic_item = "FromResidual"]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
pub trait FromResidual<R = <Self as Try>::Residual> {
|
||||
/// Constructs the type from a compatible `Residual` type.
|
||||
///
|
||||
|
|
@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
|
|||
/// );
|
||||
/// ```
|
||||
#[lang = "from_residual"]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
fn from_residual(residual: R) -> Self;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2532,7 +2532,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T> ops::Try for Option<T> {
|
||||
type Output = T;
|
||||
type Residual = Option<convert::Infallible>;
|
||||
|
|
@ -2551,7 +2551,7 @@ impl<T> ops::Try for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
// Note: manually specifying the residual type instead of using the default to work around
|
||||
// https://github.com/rust-lang/rust/issues/99940
|
||||
impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> {
|
||||
|
|
|
|||
|
|
@ -2051,7 +2051,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E> ops::Try for Result<T, E> {
|
||||
type Output = T;
|
||||
type Residual = Result<convert::Infallible, E>;
|
||||
|
|
@ -2070,7 +2070,7 @@ impl<T, E> ops::Try for Result<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl<T> From<T> for Poll<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E> ops::Try for Poll<Result<T, E>> {
|
||||
type Output = Poll<T>;
|
||||
type Residual = Result<convert::Infallible, E>;
|
||||
|
|
@ -249,7 +249,7 @@ impl<T, E> ops::Try for Poll<Result<T, E>> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> {
|
||||
#[inline]
|
||||
fn from_residual(x: Result<convert::Infallible, E>) -> Self {
|
||||
|
|
@ -259,7 +259,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
|
||||
type Output = Poll<Option<T>>;
|
||||
type Residual = Result<convert::Infallible, E>;
|
||||
|
|
@ -280,7 +280,7 @@ impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
|
||||
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>>
|
||||
for Poll<Option<Result<T, F>>>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ fn compares_as_u8s() {
|
|||
#[test]
|
||||
fn debug() {
|
||||
let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF";
|
||||
assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
|
||||
assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n…\xff""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -136,6 +136,19 @@ impl Step for ToolBuild {
|
|||
_ => panic!("unexpected Mode for tool build"),
|
||||
}
|
||||
|
||||
// build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to
|
||||
// enable for a specific tool. `extra_features` instead is not controlled by the toml and
|
||||
// provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for
|
||||
// rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build
|
||||
// to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true).
|
||||
let mut features = builder
|
||||
.config
|
||||
.tool
|
||||
.get(self.tool)
|
||||
.and_then(|tool| tool.features.clone())
|
||||
.unwrap_or_default();
|
||||
features.extend(self.extra_features.clone());
|
||||
|
||||
let mut cargo = prepare_tool_cargo(
|
||||
builder,
|
||||
self.compiler,
|
||||
|
|
@ -144,7 +157,7 @@ impl Step for ToolBuild {
|
|||
Kind::Build,
|
||||
path,
|
||||
self.source_type,
|
||||
&self.extra_features,
|
||||
&features,
|
||||
);
|
||||
|
||||
// The stage0 compiler changes infrequently and does not directly depend on code
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub use crate::core::config::flags::Subcommand;
|
|||
use crate::core::config::flags::{Color, Flags};
|
||||
use crate::core::config::target_selection::TargetSelectionList;
|
||||
use crate::core::config::toml::TomlConfig;
|
||||
use crate::core::config::toml::build::Build;
|
||||
use crate::core::config::toml::build::{Build, Tool};
|
||||
use crate::core::config::toml::change_id::ChangeId;
|
||||
use crate::core::config::toml::rust::{
|
||||
LldMode, RustOptimize, check_incompatible_options_for_ci_rustc,
|
||||
|
|
@ -101,6 +101,9 @@ pub struct Config {
|
|||
pub bootstrap_cache_path: Option<PathBuf>,
|
||||
pub extended: bool,
|
||||
pub tools: Option<HashSet<String>>,
|
||||
/// Specify build configuration specific for some tool, such as enabled features, see [Tool].
|
||||
/// The key in the map is the name of the tool, and the value is tool-specific configuration.
|
||||
pub tool: HashMap<String, Tool>,
|
||||
pub sanitizers: bool,
|
||||
pub profiler: bool,
|
||||
pub omit_git_hash: bool,
|
||||
|
|
@ -676,6 +679,7 @@ impl Config {
|
|||
bootstrap_cache_path,
|
||||
extended,
|
||||
tools,
|
||||
tool,
|
||||
verbose,
|
||||
sanitizers,
|
||||
profiler,
|
||||
|
|
@ -822,6 +826,7 @@ impl Config {
|
|||
set(&mut config.full_bootstrap, full_bootstrap);
|
||||
set(&mut config.extended, extended);
|
||||
config.tools = tools;
|
||||
set(&mut config.tool, tool);
|
||||
set(&mut config.verbose, verbose);
|
||||
set(&mut config.sanitizers, sanitizers);
|
||||
set(&mut config.profiler, profiler);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
//! various feature flags. These options apply across different stages and components
|
||||
//! unless specifically overridden by other configuration sections or command-line flags.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::core::config::toml::ReplaceOpt;
|
||||
|
|
@ -42,6 +44,7 @@ define_config! {
|
|||
bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path",
|
||||
extended: Option<bool> = "extended",
|
||||
tools: Option<HashSet<String>> = "tools",
|
||||
tool: Option<HashMap<String, Tool>> = "tool",
|
||||
verbose: Option<usize> = "verbose",
|
||||
sanitizers: Option<bool> = "sanitizers",
|
||||
profiler: Option<bool> = "profiler",
|
||||
|
|
@ -70,3 +73,11 @@ define_config! {
|
|||
exclude: Option<Vec<PathBuf>> = "exclude",
|
||||
}
|
||||
}
|
||||
|
||||
define_config! {
|
||||
/// Configuration specific for some tool, e.g. which features to enable during build.
|
||||
#[derive(Default, Clone)]
|
||||
struct Tool {
|
||||
features: Option<Vec<String>> = "features",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,4 +421,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||
severity: ChangeSeverity::Info,
|
||||
summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 142379,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "Added new option `tool.TOOL_NAME.features` to specify the features to compile a tool with",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0
|
||||
14346303d760027e53214e705109a62c0f00b214
|
||||
|
|
|
|||
|
|
@ -142,7 +142,8 @@ The most common cause is that you rebased after a change and ran `git add .` wit
|
|||
`x` to update the submodules. Alternatively, you might have run `cargo fmt` instead of `x fmt`
|
||||
and modified files in a submodule, then committed the changes.
|
||||
|
||||
To fix it, do the following things:
|
||||
To fix it, do the following things (if you changed a submodule other than cargo,
|
||||
replace `src/tools/cargo` with the path to that submodule):
|
||||
|
||||
1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo`
|
||||
2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~`
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ default behavior without any commands is to:
|
|||
2. Run `rustc -Zunpretty=normal` on the output of the previous step.
|
||||
3. The output of the previous two steps should be the same.
|
||||
4. Run `rustc -Zno-codegen` on the output to make sure that it can type check
|
||||
(this is similar to running `cargo check`).
|
||||
(similar to `cargo check`).
|
||||
|
||||
If any of the commands above fail, then the test fails.
|
||||
|
||||
|
|
|
|||
24
src/doc/unstable-book/src/compiler-flags/macro-stats.md
Normal file
24
src/doc/unstable-book/src/compiler-flags/macro-stats.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# `macro-stats`
|
||||
|
||||
This feature is perma-unstable and has no tracking issue.
|
||||
|
||||
----
|
||||
|
||||
Some macros, especially procedural macros, can generate a surprising amount of
|
||||
code, which can slow down compile times. This is hard to detect because the
|
||||
generated code is normally invisible to the programmer.
|
||||
|
||||
This flag helps identify such cases. When enabled, the compiler measures the
|
||||
effect on code size of all used macros and prints a table summarizing that
|
||||
effect. For each distinct macro, it counts how many times it is used, and the
|
||||
net effect on code size (in terms of lines of code, and bytes of code). The
|
||||
code size evaluation uses the compiler's internal pretty-printing, and so will
|
||||
be independent of the formatting in the original code.
|
||||
|
||||
Note that the net effect of a macro may be negative. E.g. the `cfg!` and
|
||||
`#[test]` macros often strip out code.
|
||||
|
||||
If a macro is identified as causing a large increase in code size, it is worth
|
||||
using `cargo expand` to inspect the post-expansion code, which includes the
|
||||
code produced by all macros. It may be possible to optimize the macro to
|
||||
produce smaller code, or it may be possible to avoid using it altogether.
|
||||
|
|
@ -169,33 +169,36 @@ impl Cfg {
|
|||
msg
|
||||
}
|
||||
|
||||
/// Renders the configuration for long display, as a long HTML description.
|
||||
pub(crate) fn render_long_html(&self) -> String {
|
||||
fn render_long_inner(&self, format: Format) -> String {
|
||||
let on = if self.omit_preposition() {
|
||||
""
|
||||
" "
|
||||
} else if self.should_use_with_in_description() {
|
||||
"with "
|
||||
" with "
|
||||
} else {
|
||||
"on "
|
||||
" on "
|
||||
};
|
||||
|
||||
let mut msg = format!("Available {on}<strong>{}</strong>", Display(self, Format::LongHtml));
|
||||
let mut msg = if matches!(format, Format::LongHtml) {
|
||||
format!("Available{on}<strong>{}</strong>", Display(self, format))
|
||||
} else {
|
||||
format!("Available{on}{}", Display(self, format))
|
||||
};
|
||||
if self.should_append_only_to_description() {
|
||||
msg.push_str(" only");
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
/// Renders the configuration for long display, as a long HTML description.
|
||||
pub(crate) fn render_long_html(&self) -> String {
|
||||
let mut msg = self.render_long_inner(Format::LongHtml);
|
||||
msg.push('.');
|
||||
msg
|
||||
}
|
||||
|
||||
/// Renders the configuration for long display, as a long plain text description.
|
||||
pub(crate) fn render_long_plain(&self) -> String {
|
||||
let on = if self.should_use_with_in_description() { "with" } else { "on" };
|
||||
|
||||
let mut msg = format!("Available {on} {}", Display(self, Format::LongPlain));
|
||||
if self.should_append_only_to_description() {
|
||||
msg.push_str(" only");
|
||||
}
|
||||
msg
|
||||
self.render_long_inner(Format::LongPlain)
|
||||
}
|
||||
|
||||
fn should_capitalize_first_letter(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -2638,7 +2638,7 @@ mod size_asserts {
|
|||
static_assert_size!(GenericParamDef, 40);
|
||||
static_assert_size!(Generics, 16);
|
||||
static_assert_size!(Item, 8);
|
||||
static_assert_size!(ItemInner, 136);
|
||||
static_assert_size!(ItemInner, 144);
|
||||
static_assert_size!(ItemKind, 48);
|
||||
static_assert_size!(PathSegment, 32);
|
||||
static_assert_size!(Type, 32);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ generate! {
|
|||
Visitor,
|
||||
Weak,
|
||||
abs,
|
||||
align_of,
|
||||
ambiguous_glob_reexports,
|
||||
append,
|
||||
arg,
|
||||
|
|
|
|||
|
|
@ -272,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let a = this.read_scalar(a)?.to_f32()?;
|
||||
let b = this.read_scalar(b)?.to_f32()?;
|
||||
let c = this.read_scalar(c)?.to_f32()?;
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
|
||||
let res = a.mul_add(b, c).value;
|
||||
let res = this.adjust_nan(res, &[a, b, c]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
|
@ -282,8 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let a = this.read_scalar(a)?.to_f64()?;
|
||||
let b = this.read_scalar(b)?.to_f64()?;
|
||||
let c = this.read_scalar(c)?.to_f64()?;
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
|
||||
let res = a.mul_add(b, c).value;
|
||||
let res = this.adjust_nan(res, &[a, b, c]);
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
|
@ -295,8 +293,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let c = this.read_scalar(c)?.to_f32()?;
|
||||
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
|
||||
let res = if fuse {
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
a.mul_add(b, c).value
|
||||
} else {
|
||||
((a * b).value + c).value
|
||||
};
|
||||
|
|
@ -310,8 +307,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let c = this.read_scalar(c)?.to_f64()?;
|
||||
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
|
||||
let res = if fuse {
|
||||
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
a.mul_add(b, c).value
|
||||
} else {
|
||||
((a * b).value + c).value
|
||||
};
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let b = b.to_f32()?;
|
||||
let c = c.to_f32()?;
|
||||
let res = if fuse {
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
a.mul_add(b, c).value
|
||||
} else {
|
||||
((a * b).value + c).value
|
||||
};
|
||||
|
|
@ -333,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let b = b.to_f64()?;
|
||||
let c = c.to_f64()?;
|
||||
let res = if fuse {
|
||||
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
|
||||
a.mul_add(b, c).value
|
||||
} else {
|
||||
((a * b).value + c).value
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
let mut _0: usize;
|
||||
|
||||
bb0: {
|
||||
- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable];
|
||||
- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable];
|
||||
+ _0 = AlignOf(T);
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
let mut _0: usize;
|
||||
|
||||
bb0: {
|
||||
- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable];
|
||||
- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable];
|
||||
+ _0 = AlignOf(T);
|
||||
+ goto -> bb1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub fn size_of<T>() -> usize {
|
|||
pub fn align_of<T>() -> usize {
|
||||
// CHECK-LABEL: fn align_of(
|
||||
// CHECK: {{_.*}} = AlignOf(T);
|
||||
core::intrinsics::min_align_of::<T>()
|
||||
core::intrinsics::align_of::<T>()
|
||||
}
|
||||
|
||||
// EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
|
|||
}
|
||||
scope 15 (inlined std::mem::size_of::<u8>) {
|
||||
}
|
||||
scope 16 (inlined align_of::<u8>) {
|
||||
scope 16 (inlined std::mem::align_of::<u8>) {
|
||||
}
|
||||
scope 17 (inlined slice_from_raw_parts::<u8>) {
|
||||
debug data => _3;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
|
|||
}
|
||||
scope 15 (inlined std::mem::size_of::<u8>) {
|
||||
}
|
||||
scope 16 (inlined align_of::<u8>) {
|
||||
scope 16 (inlined std::mem::align_of::<u8>) {
|
||||
}
|
||||
scope 17 (inlined slice_from_raw_parts::<u8>) {
|
||||
debug data => _3;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub fn main() {
|
|||
_ => {}
|
||||
};
|
||||
(4 as usize).match { _ => {} };
|
||||
(return).match { _ => {} };
|
||||
return.match { _ => {} };
|
||||
(a = 42).match { _ => {} };
|
||||
(|| {}).match { _ => {} };
|
||||
(42..101).match { _ => {} };
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@
|
|||
|
||||
// regression test for https://github.com/rust-lang/rust/issues/138112
|
||||
|
||||
//@ has 'foo/fn.foo.html' '//div[@class="stab portability"]' 'Available nowhere'
|
||||
//@ has 'foo/index.html'
|
||||
//@ has - '//*[@class="stab portability"]/@title' 'Available nowhere'
|
||||
|
||||
//@ count 'foo/fn.foo.html' '//*[@class="stab portability"]' 1
|
||||
//@ has 'foo/fn.foo.html' '//*[@class="stab portability"]' 'Available nowhere'
|
||||
#[doc(cfg(false))]
|
||||
pub fn foo() {}
|
||||
|
||||
// a cfg(true) will simply be ommited, as it is the same as no cfg.
|
||||
//@ !has 'foo/fn.bar.html' '//div[@class="stab portability"]' ''
|
||||
// a cfg(true) will simply be omitted, as it is the same as no cfg.
|
||||
//@ count 'foo/fn.bar.html' '//*[@class="stab portability"]' 0
|
||||
#[doc(cfg(true))]
|
||||
pub fn bar() {}
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ static EXPRS: &[&str] = &[
|
|||
"(2 += 2) += 2",
|
||||
// Return has lower precedence than a binary operator.
|
||||
"(return 2) + 2",
|
||||
"2 + (return 2)", // FIXME: no parenthesis needed.
|
||||
"(return) + 2", // FIXME: no parenthesis needed.
|
||||
"2 + return 2",
|
||||
"return + 2",
|
||||
// These mean different things.
|
||||
"return - 2",
|
||||
"(return) - 2",
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
|
|||
#[unstable(feature = "unstable", issue = "42")]
|
||||
#[rustc_const_unstable(feature = "unstable", issue = "42")]
|
||||
#[rustc_intrinsic]
|
||||
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
|
||||
pub const unsafe fn align_of_val<T>(x: *const T) -> usize;
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ static FOO: Foo = Foo::C;
|
|||
fn main() {
|
||||
assert_eq!(FOO, Foo::C);
|
||||
assert_eq!(mem::size_of::<Foo>(), 12);
|
||||
assert_eq!(mem::min_align_of::<Foo>(), 4);
|
||||
assert_eq!(mem::align_of::<Foo>(), 4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#![feature(extern_types)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
use std::intrinsics::{min_align_of_val, size_of_val};
|
||||
use std::intrinsics::{align_of_val, size_of_val};
|
||||
|
||||
extern "C" {
|
||||
type Opaque;
|
||||
}
|
||||
|
||||
const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
|
||||
const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
|
||||
const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque
|
|||
error[E0080]: `extern type` does not have known layout
|
||||
--> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32
|
||||
|
|
||||
LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
|
||||
LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ const fn const_main() {
|
|||
unstable_intrinsic::size_of_val(&x);
|
||||
//~^ERROR: unstable library feature `unstable`
|
||||
//~|ERROR: not yet stable as a const intrinsic
|
||||
unstable_intrinsic::min_align_of_val(&x);
|
||||
unstable_intrinsic::align_of_val(&x);
|
||||
//~^ERROR: unstable library feature `unstable`
|
||||
//~|ERROR: not yet stable as a const intrinsic
|
||||
|
||||
size_of_val(&x);
|
||||
//~^ERROR: cannot use `#[feature(local)]`
|
||||
min_align_of_val(&x);
|
||||
align_of_val(&x);
|
||||
//~^ERROR: cannot use `#[feature(local)]`
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
|
|||
#[unstable(feature = "local", issue = "42")]
|
||||
#[rustc_const_unstable(feature = "local", issue = "42")]
|
||||
#[rustc_intrinsic]
|
||||
pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
|
||||
pub const unsafe fn align_of_val<T>(x: *const T) -> usize;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ LL | unstable_intrinsic::size_of_val(&x);
|
|||
error[E0658]: use of unstable library feature `unstable`
|
||||
--> $DIR/const-unstable-intrinsic.rs:20:9
|
||||
|
|
||||
LL | unstable_intrinsic::min_align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unstable_intrinsic::align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
|
||||
= help: add `#![feature(unstable)]` to the crate attributes to enable
|
||||
|
|
@ -29,11 +29,11 @@ help: add `#![feature(unstable)]` to the crate attributes to enable
|
|||
LL + #![feature(unstable)]
|
||||
|
|
||||
|
||||
error: `min_align_of_val` is not yet stable as a const intrinsic
|
||||
error: `align_of_val` is not yet stable as a const intrinsic
|
||||
--> $DIR/const-unstable-intrinsic.rs:20:9
|
||||
|
|
||||
LL | unstable_intrinsic::min_align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unstable_intrinsic::align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add `#![feature(unstable)]` to the crate attributes to enable
|
||||
|
|
||||
|
|
@ -55,8 +55,8 @@ LL | const fn const_main() {
|
|||
error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
|
||||
--> $DIR/const-unstable-intrinsic.rs:26:9
|
||||
|
|
||||
LL | min_align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
LL | align_of_val(&x);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
|
||||
|
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ use std::intrinsics as rusti;
|
|||
mod m {
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub fn main() {
|
||||
assert_eq!(crate::rusti::min_align_of::<u64>(), 4);
|
||||
assert_eq!(crate::rusti::align_of::<u64>(), 4);
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86"))]
|
||||
pub fn main() {
|
||||
assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
|
||||
assert_eq!(crate::rusti::align_of::<u64>(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,21 +36,21 @@ mod m {
|
|||
mod m {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn main() {
|
||||
assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
|
||||
assert_eq!(crate::rusti::align_of::<u64>(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod m {
|
||||
pub fn main() {
|
||||
assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
|
||||
assert_eq!(crate::rusti::align_of::<u64>(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
mod m {
|
||||
pub fn main() {
|
||||
assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
|
||||
assert_eq!(crate::rusti::align_of::<u64>(), 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
|
|||
help: try using a const generic argument instead
|
||||
|
|
||||
LL - std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
|
||||
LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {});
|
||||
LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + || () }>(loop {}, loop {});
|
||||
|
|
||||
|
||||
error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
|
||||
|
|
@ -81,7 +81,7 @@ LL | std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ())
|
|||
help: try using a const generic argument instead
|
||||
|
|
||||
LL - std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ());
|
||||
LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {});
|
||||
LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + || () }>(loop {}, loop {});
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ error[E0080]: the type `MySlice<[bool]>` has an unknown layout
|
|||
LL | static CHECK: () = assert!(align_of::<P2>() == 1);
|
||||
| ^^^^^^^^^^^^^^^^ evaluation of `CHECK` failed inside this call
|
||||
|
|
||||
note: inside `align_of::<P2>`
|
||||
note: inside `std::mem::align_of::<P2>`
|
||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
use std::mem;
|
||||
|
||||
/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly
|
||||
/// `T` should satisfy `size_of T (mod align_of T) === 0` to be stored at `Vec<T>` properly
|
||||
/// Please consult the issue #20460
|
||||
fn check<T>() {
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
|
||||
assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
|
|
|
|||
3
tests/ui/stability-attribute/renamed_feature.rs
Normal file
3
tests/ui/stability-attribute/renamed_feature.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635]
|
||||
|
||||
fn main() {}
|
||||
9
tests/ui/stability-attribute/renamed_feature.stderr
Normal file
9
tests/ui/stability-attribute/renamed_feature.stderr
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
error[E0635]: feature `try_trait` has been renamed to `try_trait_v2`
|
||||
--> $DIR/renamed_feature.rs:1:12
|
||||
|
|
||||
LL | #![feature(try_trait)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0635`.
|
||||
3
tests/ui/stats/auxiliary/include.rs
Normal file
3
tests/ui/stats/auxiliary/include.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn zzz(x: u32) -> u32 {
|
||||
x
|
||||
}
|
||||
|
|
@ -82,10 +82,10 @@ hir-stats - Expr 32 (NN.N%) 1
|
|||
hir-stats - Let 32 (NN.N%) 1
|
||||
hir-stats - Semi 32 (NN.N%) 1
|
||||
hir-stats FnDecl 120 (NN.N%) 3 40
|
||||
hir-stats Attribute 128 (NN.N%) 4 32
|
||||
hir-stats FieldDef 128 (NN.N%) 2 64
|
||||
hir-stats GenericArgs 144 (NN.N%) 3 48
|
||||
hir-stats Variant 144 (NN.N%) 2 72
|
||||
hir-stats Attribute 160 (NN.N%) 4 40
|
||||
hir-stats GenericBound 256 (NN.N%) 4 64
|
||||
hir-stats - Trait 256 (NN.N%) 4
|
||||
hir-stats Block 288 (NN.N%) 6 48
|
||||
|
|
@ -117,5 +117,5 @@ hir-stats - Use 352 (NN.N%) 4
|
|||
hir-stats Path 1_040 (NN.N%) 26 40
|
||||
hir-stats PathSegment 1_776 (NN.N%) 37 48
|
||||
hir-stats ----------------------------------------------------------------
|
||||
hir-stats Total 8_644 172
|
||||
hir-stats Total 8_676 172
|
||||
hir-stats
|
||||
|
|
|
|||
130
tests/ui/stats/macro-stats.rs
Normal file
130
tests/ui/stats/macro-stats.rs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
//@ check-pass
|
||||
//@ compile-flags: -Zmacro-stats
|
||||
|
||||
#[test]
|
||||
fn test_foo() {
|
||||
let what = "this";
|
||||
let how = "completely";
|
||||
let when = "immediately";
|
||||
println!("{what} disappears {how} and {when}");
|
||||
}
|
||||
|
||||
#[rustfmt::skip] // non-macro attr, ignored by `-Zmacro-stats`
|
||||
fn rustfmt_skip() {
|
||||
// Nothing to see here.
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Hash)]
|
||||
enum E1 {
|
||||
#[default] // non-macro attr, ignored by `-Zmacro-stats`
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
struct E2 {
|
||||
a: u32,
|
||||
b: String,
|
||||
c: Vec<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone)] struct S0;
|
||||
#[derive(Clone)] struct S1(u32);
|
||||
#[derive(Clone)] struct S2(u32, u32);
|
||||
#[derive(Clone)] struct S3(u32, u32, u32);
|
||||
#[derive(Clone)] struct S4(u32, u32, u32, u32);
|
||||
#[derive(Clone)] struct S5(u32, u32, u32, u32, u32);
|
||||
|
||||
macro_rules! u32 {
|
||||
() => { u32 }
|
||||
}
|
||||
|
||||
macro_rules! none {
|
||||
() => { None }
|
||||
}
|
||||
fn opt(x: Option<u32>) {
|
||||
match x {
|
||||
Some(_) => {}
|
||||
none!() => {} // AstFragmentKind::Pat
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! this_is_a_really_really_long_macro_name {
|
||||
($t:ty) => {
|
||||
fn f(_: $t) {}
|
||||
}
|
||||
}
|
||||
this_is_a_really_really_long_macro_name!(u32!()); // AstFragmentKind::{Items,Ty}
|
||||
|
||||
macro_rules! trait_tys {
|
||||
() => {
|
||||
type A;
|
||||
type B;
|
||||
}
|
||||
}
|
||||
trait Tr {
|
||||
trait_tys!(); // AstFragmentKind::TraitItems
|
||||
}
|
||||
|
||||
macro_rules! impl_const { () => { const X: u32 = 0; } }
|
||||
struct U;
|
||||
impl U {
|
||||
impl_const!(); // AstFragmentKind::ImplItems
|
||||
}
|
||||
|
||||
macro_rules! trait_impl_tys {
|
||||
() => {
|
||||
type A = u32;
|
||||
type B = bool;
|
||||
}
|
||||
}
|
||||
struct Tr1;
|
||||
impl Tr for Tr1 {
|
||||
trait_impl_tys!(); // AstFragment::TraitImplItems
|
||||
}
|
||||
|
||||
macro_rules! foreign_item {
|
||||
() => { fn fc(a: u32) -> u32; }
|
||||
}
|
||||
extern "C" {
|
||||
foreign_item!(); // AstFragment::ForeignItems
|
||||
}
|
||||
|
||||
// Include macros are ignored by `-Zmacro-stats`.
|
||||
mod includes {
|
||||
mod z1 {
|
||||
include!("auxiliary/include.rs");
|
||||
}
|
||||
mod z2 {
|
||||
std::include!("auxiliary/include.rs");
|
||||
}
|
||||
|
||||
const B1: &[u8] = include_bytes!("auxiliary/include.rs");
|
||||
const B2: &[u8] = std::include_bytes!("auxiliary/include.rs");
|
||||
|
||||
const S1: &str = include_str!("auxiliary/include.rs");
|
||||
const S2: &str = std::include_str!("auxiliary/include.rs");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
macro_rules! n99 {
|
||||
() => { 99 }
|
||||
}
|
||||
let x = n99!() + n99!(); // AstFragmentKind::Expr
|
||||
|
||||
macro_rules! p {
|
||||
() => {
|
||||
// blah
|
||||
let x = 1;
|
||||
let y = x;
|
||||
let _ = y;
|
||||
}
|
||||
}
|
||||
p!(); // AstFragmentKind::Stmts
|
||||
|
||||
macro_rules! q {
|
||||
() => {};
|
||||
($($x:ident),*) => { $( let $x: u32 = 12345; )* };
|
||||
}
|
||||
q!(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
|
||||
}
|
||||
26
tests/ui/stats/macro-stats.stderr
Normal file
26
tests/ui/stats/macro-stats.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
macro-stats ===================================================================================
|
||||
macro-stats MACRO EXPANSION STATS: macro_stats
|
||||
macro-stats Macro Name Uses Lines Avg Lines Bytes Avg Bytes
|
||||
macro-stats -----------------------------------------------------------------------------------
|
||||
macro-stats #[derive(Clone)] 8 56 7.0 1_660 207.5
|
||||
macro-stats #[derive(PartialOrd)] 1 16 16.0 654 654.0
|
||||
macro-stats #[derive(Hash)] 2 15 7.5 547 273.5
|
||||
macro-stats #[derive(Ord)] 1 14 14.0 489 489.0
|
||||
macro-stats q! 1 24 24.0 435 435.0
|
||||
macro-stats #[derive(Default)] 2 14 7.0 367 183.5
|
||||
macro-stats #[derive(Eq)] 1 10 10.0 312 312.0
|
||||
macro-stats #[derive(Debug)] 1 7 7.0 261 261.0
|
||||
macro-stats #[derive(PartialEq)] 1 8 8.0 247 247.0
|
||||
macro-stats #[derive(Copy)] 1 1 1.0 46 46.0
|
||||
macro-stats p! 1 2 2.0 28 28.0
|
||||
macro-stats trait_impl_tys! 1 1 1.0 11 11.0
|
||||
macro-stats foreign_item! 1 0 0.0 6 6.0
|
||||
macro-stats impl_const! 1 0 0.0 4 4.0
|
||||
macro-stats trait_tys! 1 1 1.0 3 3.0
|
||||
macro-stats u32! 1 0 0.0 -3 -3.0
|
||||
macro-stats none! 1 0 0.0 -3 -3.0
|
||||
macro-stats n99! 2 0 0.0 -8 -4.0
|
||||
macro-stats this_is_a_really_really_long_macro_name!
|
||||
macro-stats 1 0 0.0 -30 -30.0
|
||||
macro-stats #[test] 1 -6 -6.0 -158 -158.0
|
||||
macro-stats ===================================================================================
|
||||
|
|
@ -11,7 +11,7 @@ fn addr_of<T>(ptr: &T) -> usize {
|
|||
fn is_aligned<T>(ptr: &T) -> bool {
|
||||
unsafe {
|
||||
let addr: usize = mem::transmute(ptr);
|
||||
(addr % mem::min_align_of::<T>()) == 0
|
||||
(addr % mem::align_of::<T>()) == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ pub fn main() {
|
|||
// Send it through the shape code
|
||||
let y = format!("{:?}", x);
|
||||
|
||||
println!("align inner = {:?}", intrinsics::min_align_of::<Inner>());
|
||||
println!("align inner = {:?}", intrinsics::align_of::<Inner>());
|
||||
println!("size outer = {:?}", mem::size_of::<Outer>());
|
||||
println!("y = {:?}", y);
|
||||
|
||||
// per clang/gcc the alignment of `inner` is 4 on x86.
|
||||
assert_eq!(intrinsics::min_align_of::<Inner>(), m::align());
|
||||
assert_eq!(intrinsics::align_of::<Inner>(), m::align());
|
||||
|
||||
// per clang/gcc the size of `outer` should be 12
|
||||
// because `inner`s alignment was 4.
|
||||
|
|
|
|||
|
|
@ -84,12 +84,12 @@ pub fn main() {
|
|||
|
||||
let y = format!("{:?}", x);
|
||||
|
||||
println!("align inner = {:?}", intrinsics::min_align_of::<Inner>());
|
||||
println!("align inner = {:?}", intrinsics::align_of::<Inner>());
|
||||
println!("size outer = {:?}", mem::size_of::<Outer>());
|
||||
println!("y = {:?}", y);
|
||||
|
||||
// per clang/gcc the alignment of `Inner` is 4 on x86.
|
||||
assert_eq!(intrinsics::min_align_of::<Inner>(), m::m::align());
|
||||
assert_eq!(intrinsics::align_of::<Inner>(), m::m::align());
|
||||
|
||||
// per clang/gcc the size of `Outer` should be 12
|
||||
// because `Inner`s alignment was 4.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn mk_rec() -> Rec {
|
|||
|
||||
fn is_u64_aligned(u: &Tag<u64>) -> bool {
|
||||
let p: usize = unsafe { mem::transmute(u) };
|
||||
let u64_align = std::mem::min_align_of::<u64>();
|
||||
let u64_align = std::mem::align_of::<u64>();
|
||||
return (p & (u64_align - 1)) == 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ fn variant_data_is_aligned<A,B>(amnt: usize, u: &Tag<A,B>) -> bool {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
let u64_align = std::mem::min_align_of::<u64>();
|
||||
let u64_align = std::mem::align_of::<u64>();
|
||||
let x = mk_rec(22u64, 23u64);
|
||||
assert!(is_aligned(u64_align, &x.tA));
|
||||
assert!(variant_data_is_aligned(u64_align, &x.tA));
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn mk_rec() -> Rec {
|
|||
|
||||
fn is_u64_aligned(u: &Tag) -> bool {
|
||||
let p: usize = unsafe { mem::transmute(u) };
|
||||
let u64_align = std::mem::min_align_of::<u64>();
|
||||
let u64_align = std::mem::align_of::<u64>();
|
||||
return (p & (u64_align - 1)) == 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ mod expressions {
|
|||
(static async || value);
|
||||
(static async move || value);
|
||||
|| -> u8 { value };
|
||||
1 + (|| {});
|
||||
1 + || {};
|
||||
}
|
||||
|
||||
/// ExprKind::Block
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue