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:
bors 2025-06-13 11:42:31 +00:00
commit c359117819
97 changed files with 1094 additions and 311 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -132,6 +132,7 @@ pub enum StabilityLevel {
/// fn foobar() {}
/// ```
implied_by: Option<Symbol>,
old_name: Option<Symbol>,
},
/// `#[stable]`
Stable {

View file

@ -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, &param, &mut implied_by)?
}
Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &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))
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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!()`.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1 +1 @@
c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0
14346303d760027e53214e705109a62c0f00b214

View file

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

View file

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

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

View file

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

View file

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

View file

@ -76,7 +76,6 @@ generate! {
Visitor,
Weak,
abs,
align_of,
ambiguous_glob_reexports,
append,
arg,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,7 +26,7 @@ pub fn main() {
_ => {}
};
(4 as usize).match { _ => {} };
(return).match { _ => {} };
return.match { _ => {} };
(a = 42).match { _ => {} };
(|| {}).match { _ => {} };
(42..101).match { _ => {} };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,3 @@
#![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635]
fn main() {}

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

View file

@ -0,0 +1,3 @@
fn zzz(x: u32) -> u32 {
x
}

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -190,7 +190,7 @@ mod expressions {
(static async || value);
(static async move || value);
|| -> u8 { value };
1 + (|| {});
1 + || {};
}
/// ExprKind::Block