Auto merge of #3378 - rust-lang:rustup-2024-03-14, r=RalfJung

Automatic Rustup
This commit is contained in:
bors 2024-03-14 06:46:16 +00:00
commit 24071bdf88
497 changed files with 5459 additions and 2576 deletions

View file

@ -52,7 +52,7 @@ Copyright: 2019 The Crossbeam Project Developers
The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT OR Apache-2.0
Files: library/std/src/sys/locks/mutex/fuchsia.rs
Files: library/std/src/sys/sync/mutex/fuchsia.rs
Copyright: 2016 The Fuchsia Authors
The Rust Project Developers (see https://thanks.rust-lang.org)
License: BSD-2-Clause AND (MIT OR Apache-2.0)

View file

@ -816,15 +816,37 @@ where
break;
}
};
if let Some(pair) = common_prim {
// This is pretty conservative. We could go fancier
// by conflating things like i32 and u32, or even
// realising that (u8, u8) could just cohabit with
// u16 or even u32.
if pair != (prim, offset) {
if let Some((old_prim, common_offset)) = common_prim {
// All variants must be at the same offset
if offset != common_offset {
common_prim = None;
break;
}
// This is pretty conservative. We could go fancier
// by realising that (u8, u8) could just cohabit with
// u16 or even u32.
let new_prim = match (old_prim, prim) {
// Allow all identical primitives.
(x, y) if x == y => x,
// Allow integers of the same size with differing signedness.
// We arbitrarily choose the signedness of the first variant.
(p @ Primitive::Int(x, _), Primitive::Int(y, _)) if x == y => p,
// Allow integers mixed with pointers of the same layout.
// We must represent this using a pointer, to avoid
// roundtripping pointers through ptrtoint/inttoptr.
(p @ Primitive::Pointer(_), i @ Primitive::Int(..))
| (i @ Primitive::Int(..), p @ Primitive::Pointer(_))
if p.size(dl) == i.size(dl) && p.align(dl) == i.align(dl) =>
{
p
}
_ => {
common_prim = None;
break;
}
};
// We may be updating the primitive here, for example from int->ptr.
common_prim = Some((new_prim, common_offset));
} else {
common_prim = Some((prim, offset));
}

View file

@ -1021,7 +1021,7 @@ impl Stmt {
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum StmtKind {
/// A local (let) binding.
Local(P<Local>),
Let(P<Local>),
/// An item definition.
Item(P<Item>),
/// Expr without trailing semi-colon.

View file

@ -182,7 +182,7 @@ impl<T: HasTokens> HasTokens for Option<T> {
impl HasTokens for StmtKind {
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
match self {
StmtKind::Local(local) => local.tokens.as_ref(),
StmtKind::Let(local) => local.tokens.as_ref(),
StmtKind::Item(item) => item.tokens(),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
StmtKind::Empty => return None,
@ -191,7 +191,7 @@ impl HasTokens for StmtKind {
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
match self {
StmtKind::Local(local) => Some(&mut local.tokens),
StmtKind::Let(local) => Some(&mut local.tokens),
StmtKind::Item(item) => item.tokens_mut(),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
StmtKind::Empty => return None,
@ -355,7 +355,7 @@ impl HasAttrs for StmtKind {
fn attrs(&self) -> &[Attribute] {
match self {
StmtKind::Local(local) => &local.attrs,
StmtKind::Let(local) => &local.attrs,
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
StmtKind::Item(item) => item.attrs(),
StmtKind::Empty => &[],
@ -365,7 +365,7 @@ impl HasAttrs for StmtKind {
fn visit_attrs(&mut self, f: impl FnOnce(&mut AttrVec)) {
match self {
StmtKind::Local(local) => f(&mut local.attrs),
StmtKind::Let(local) => f(&mut local.attrs),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
StmtKind::Item(item) => item.visit_attrs(f),
StmtKind::Empty => {}

View file

@ -1567,7 +1567,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
vis: &mut T,
) -> SmallVec<[StmtKind; 1]> {
match kind {
StmtKind::Local(mut local) => smallvec![StmtKind::Local({
StmtKind::Let(mut local) => smallvec![StmtKind::Let({
vis.visit_local(&mut local);
local
})],

View file

@ -787,7 +787,7 @@ pub fn walk_block<'a, V: Visitor<'a>>(visitor: &mut V, block: &'a Block) -> V::R
pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
match &statement.kind {
StmtKind::Local(local) => try_visit!(visitor.visit_local(local)),
StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)),
StmtKind::Empty => {}

View file

@ -196,7 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
.get_partial_res(sym.id)
.and_then(|res| res.full_res())
.and_then(|res| match res {
Res::Def(DefKind::Static(_), def_id) => Some(def_id),
Res::Def(DefKind::Static { .. }, def_id) => Some(def_id),
_ => None,
});

View file

@ -32,11 +32,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut expr = None;
while let [s, tail @ ..] = ast_stmts {
match &s.kind {
StmtKind::Local(local) => {
StmtKind::Let(local) => {
let hir_id = self.lower_node_id(s.id);
let local = self.lower_local(local);
self.alias_attrs(hir_id, local.hir_id);
let kind = hir::StmtKind::Local(local);
let kind = hir::StmtKind::Let(local);
let span = self.lower_span(s.span);
stmts.push(hir::Stmt { hir_id, kind, span });
}

View file

@ -2356,7 +2356,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: self.lower_span(span),
ty: None,
};
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
}
fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {

View file

@ -1212,7 +1212,7 @@ impl<'a> State<'a> {
fn print_stmt(&mut self, st: &ast::Stmt) {
self.maybe_print_comment(st.span.lo());
match &st.kind {
ast::StmtKind::Local(loc) => {
ast::StmtKind::Let(loc) => {
self.print_outer_attributes(&loc.attrs);
self.space_if_not_bol();
self.ibox(INDENT_UNIT);

View file

@ -616,7 +616,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// FIXME: We make sure that this is a normal top-level binding,
// but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
if let hir::StmtKind::Local(hir::Local { span, ty, init: None, pat, .. }) =
if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) =
&ex.kind
&& let hir::PatKind::Binding(..) = pat.kind
&& span.contains(self.decl_span)

View file

@ -558,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
hir::intravisit::walk_stmt(self, stmt);
let expr = match stmt.kind {
hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr,
hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr,
_ => {
return;
}
@ -1305,7 +1305,7 @@ struct BindingFinder {
impl<'tcx> Visitor<'tcx> for BindingFinder {
type Result = ControlFlow<hir::HirId>;
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
if let hir::StmtKind::Local(local) = s.kind
if let hir::StmtKind::Let(local) = s.kind
&& local.pat.span == self.span
{
ControlFlow::Break(local.hir_id)

View file

@ -5,7 +5,7 @@ use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::PResult;
use rustc_expand::base::{self, *};
use rustc_expand::base::*;
use rustc_index::bit_set::GrowableBitSet;
use rustc_parse::parser::Parser;
use rustc_parse_format as parse;
@ -443,7 +443,7 @@ fn parse_reg<'a>(
fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>,
args: AsmArgs,
) -> Result<ast::InlineAsm, ErrorGuaranteed> {
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
@ -465,16 +465,20 @@ fn expand_preparsed_asm(
let msg = "asm template must be a string literal";
let template_sp = template_expr.span;
let (template_str, template_style, template_span) =
match expr_to_spanned_string(ecx, template_expr, msg) {
let (template_str, template_style, template_span) = {
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
return ExpandResult::Retry(());
};
match mac {
Ok(template_part) => template_part,
Err(err) => {
return Err(match err {
return ExpandResult::Ready(Err(match err {
Ok((err, _)) => err.emit(),
Err(guar) => guar,
});
}));
}
};
}
};
let str_style = match template_style {
ast::StrStyle::Cooked => None,
@ -562,7 +566,7 @@ fn expand_preparsed_asm(
e.span_label(err_sp, label);
}
let guar = e.emit();
return Err(guar);
return ExpandResult::Ready(Err(guar));
}
curarg = parser.curarg;
@ -729,24 +733,27 @@ fn expand_preparsed_asm(
}
}
Ok(ast::InlineAsm {
ExpandResult::Ready(Ok(ast::InlineAsm {
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
clobber_abis: args.clobber_abis,
options: args.options,
line_spans,
})
}))
}
pub(super) fn expand_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, false) {
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
Ok(args) => {
let expr = match expand_preparsed_asm(ecx, args) {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
return ExpandResult::Retry(());
};
let expr = match mac {
Ok(inline_asm) => P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
@ -762,34 +769,39 @@ pub(super) fn expand_asm<'cx>(
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}
pub(super) fn expand_global_asm<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, true) {
Ok(args) => match expand_preparsed_asm(ecx, args) {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
ident: Ident::empty(),
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
Ok(args) => {
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
return ExpandResult::Retry(());
};
match mac {
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
ident: Ident::empty(),
attrs: ast::AttrVec::new(),
id: ast::DUMMY_NODE_ID,
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
vis: ast::Visibility {
span: sp.shrink_to_lo(),
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
span: sp,
tokens: None,
},
span: sp,
tokens: None,
})]),
Err(guar) => DummyResult::any(sp, guar),
},
})]),
Err(guar) => DummyResult::any(sp, guar),
}
}
Err(err) => {
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}

View file

@ -9,7 +9,7 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_parse::parser::Parser;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
@ -19,12 +19,12 @@ pub fn expand_assert<'cx>(
cx: &'cx mut ExtCtxt<'_>,
span: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
Ok(assert) => assert,
Err(err) => {
let guar = err.emit();
return DummyResult::any(span, guar);
return ExpandResult::Ready(DummyResult::any(span, guar));
}
};
@ -92,7 +92,7 @@ pub fn expand_assert<'cx>(
expr_if_not(cx, call_site_span, cond_expr, then, None)
};
MacEager::expr(expr)
ExpandResult::Ready(MacEager::expr(expr))
}
struct Assert {

View file

@ -8,17 +8,17 @@ use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_attr as attr;
use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::Span;
pub fn expand_cfg(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
match parse_cfg(cx, sp, tts) {
ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
Ok(cfg) => {
let matches_cfg = attr::cfg_matches(
&cfg,
@ -32,7 +32,7 @@ pub fn expand_cfg(
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}
fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {

View file

@ -1,22 +1,26 @@
// The compiler code necessary to support the compile_error! extension.
use rustc_ast::tokenstream::TokenStream;
use rustc_expand::base::{get_single_str_from_tts, DummyResult, ExtCtxt, MacResult};
use rustc_expand::base::get_single_str_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::Span;
pub fn expand_compile_error<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") {
) -> MacroExpanderResult<'cx> {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
return ExpandResult::Retry(());
};
let var = match mac {
Ok(var) => var,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
#[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
let guar = cx.dcx().span_err(sp, var.to_string());
DummyResult::any(sp, guar)
ExpandResult::Ready(DummyResult::any(sp, guar))
}

View file

@ -1,6 +1,7 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{ExprKind, LitKind, UnOp};
use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_expand::base::get_exprs_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_session::errors::report_lit_error;
use rustc_span::symbol::Symbol;
@ -10,10 +11,13 @@ pub fn expand_concat(
cx: &mut ExtCtxt<'_>,
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
let es = match get_exprs_from_tts(cx, tts) {
) -> MacroExpanderResult<'static> {
let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let mut accumulator = String::new();
let mut missing_literal = vec![];
@ -70,12 +74,13 @@ pub fn expand_concat(
}
}
if !missing_literal.is_empty() {
ExpandResult::Ready(if !missing_literal.is_empty() {
let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
return DummyResult::any(sp, guar);
DummyResult::any(sp, guar)
} else if let Some(guar) = guar {
return DummyResult::any(sp, guar);
}
let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
DummyResult::any(sp, guar)
} else {
let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
})
}

View file

@ -1,5 +1,6 @@
use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult};
use rustc_expand::base::get_exprs_from_tts;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_session::errors::report_lit_error;
use rustc_span::{ErrorGuaranteed, Span};
@ -111,10 +112,13 @@ pub fn expand_concat_bytes(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
let es = match get_exprs_from_tts(cx, tts) {
) -> MacroExpanderResult<'static> {
let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let es = match mac {
Ok(es) => es,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let mut accumulator = Vec::new();
let mut missing_literals = vec![];
@ -170,12 +174,13 @@ pub fn expand_concat_bytes(
}
}
}
if !missing_literals.is_empty() {
ExpandResult::Ready(if !missing_literals.is_empty() {
let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
return MacEager::expr(DummyResult::raw_expr(sp, Some(guar)));
MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
} else if let Some(guar) = guar {
return MacEager::expr(DummyResult::raw_expr(sp, Some(guar)));
}
let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_byte_str(sp, accumulator))
MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
} else {
let sp = cx.with_def_site_ctxt(sp);
MacEager::expr(cx.expr_byte_str(sp, accumulator))
})
}

View file

@ -2,7 +2,7 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID};
use rustc_expand::base::{DummyResult, ExtCtxt, MacResult};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;
@ -12,10 +12,10 @@ pub fn expand_concat_idents<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
if tts.is_empty() {
let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
let mut res_str = String::new();
@ -25,7 +25,7 @@ pub fn expand_concat_idents<'cx>(
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
_ => {
let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
}
} else {
@ -37,7 +37,7 @@ pub fn expand_concat_idents<'cx>(
}
let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
}
@ -68,5 +68,5 @@ pub fn expand_concat_idents<'cx>(
}
}
Box::new(ConcatIdentsResult { ident })
ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
}

View file

@ -20,7 +20,7 @@ pub fn expand_panic<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
expand(mac, cx, sp, tts)
}
@ -33,7 +33,7 @@ pub fn expand_unreachable<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
expand(mac, cx, sp, tts)
}
@ -43,10 +43,10 @@ fn expand<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let sp = cx.with_call_site_ctxt(sp);
MacEager::expr(
ExpandResult::Ready(MacEager::expr(
cx.expr(
sp,
ExprKind::MacCall(P(MacCall {
@ -66,7 +66,7 @@ fn expand<'cx>(
}),
})),
),
)
))
}
pub fn use_panic_2021(mut span: Span) -> bool {

View file

@ -6,10 +6,8 @@
use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
use rustc_expand::base::{
expr_to_string, get_exprs_from_tts, get_single_str_from_tts, DummyResult, ExtCtxt, MacEager,
MacResult,
};
use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use std::env;
@ -31,10 +29,13 @@ pub fn expand_option_env<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") {
) -> MacroExpanderResult<'cx> {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
return ExpandResult::Retry(());
};
let var = match mac {
Ok(var) => var,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let sp = cx.with_def_site_ctxt(sp);
@ -61,35 +62,48 @@ pub fn expand_option_env<'cx>(
thin_vec![cx.expr_str(sp, value)],
),
};
MacEager::expr(e)
ExpandResult::Ready(MacEager::expr(e))
}
pub fn expand_env<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
let mut exprs = match get_exprs_from_tts(cx, tts) {
) -> MacroExpanderResult<'cx> {
let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
return ExpandResult::Retry(());
};
let mut exprs = match mac {
Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => {
let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
Ok(exprs) => exprs.into_iter(),
};
let var_expr = exprs.next().unwrap();
let var = match expr_to_string(cx, var_expr.clone(), "expected string literal") {
let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal")
else {
return ExpandResult::Retry(());
};
let var = match mac {
Ok((var, _)) => var,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let custom_msg = match exprs.next() {
None => None,
Some(second) => match expr_to_string(cx, second, "expected string literal") {
Ok((s, _)) => Some(s),
Err(guar) => return DummyResult::any(sp, guar),
},
Some(second) => {
let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal")
else {
return ExpandResult::Retry(());
};
match mac {
Ok((s, _)) => Some(s),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
}
}
};
let span = cx.with_def_site_ctxt(sp);
@ -120,11 +134,11 @@ pub fn expand_env<'cx>(
})
};
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
Some(value) => cx.expr_str(span, value),
};
MacEager::expr(e)
ExpandResult::Ready(MacEager::expr(e))
}
/// Returns `true` if an environment variable from `env!` is one used by Cargo.

View file

@ -9,7 +9,7 @@ use rustc_ast::{
};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
use rustc_expand::base::{self, *};
use rustc_expand::base::*;
use rustc_parse::parser::Recovered;
use rustc_parse_format as parse;
use rustc_span::symbol::{Ident, Symbol};
@ -40,6 +40,7 @@ use PositionUsedAs::*;
use crate::errors;
#[derive(Debug)]
struct MacroInput {
fmtstr: P<Expr>,
args: FormatArguments,
@ -160,54 +161,61 @@ fn make_format_args(
ecx: &mut ExtCtxt<'_>,
input: MacroInput,
append_newline: bool,
) -> Result<FormatArgs, ErrorGuaranteed> {
) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
let msg = "format argument must be a string literal";
let unexpanded_fmt_span = input.fmtstr.span;
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt.clone(), msg) {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
fmt
}
Ok(fmt) => fmt,
Err(err) => {
let guar = match err {
Ok((mut err, suggested)) => {
if !suggested {
if let ExprKind::Block(block, None) = &efmt.kind
&& block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
&& let ExprKind::Path(None, path) = &expr.kind
&& path.is_potential_trivial_const_arg()
{
err.multipart_suggestion(
"quote your inlined format argument to use as string literal",
vec![
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
let sugg_fmt = match args.explicit_args().len() {
0 => "{}".to_string(),
_ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
};
err.span_suggestion(
unexpanded_fmt_span.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{sugg_fmt}\", "),
Applicability::MaybeIncorrect,
);
let (fmt_str, fmt_style, fmt_span) = {
let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
return ExpandResult::Retry(());
};
match mac {
Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
fmt
}
Ok(fmt) => fmt,
Err(err) => {
let guar = match err {
Ok((mut err, suggested)) => {
if !suggested {
if let ExprKind::Block(block, None) = &efmt.kind
&& block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
&& let ExprKind::Path(None, path) = &expr.kind
&& path.is_potential_trivial_const_arg()
{
err.multipart_suggestion(
"quote your inlined format argument to use as string literal",
vec![
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
let sugg_fmt = match args.explicit_args().len() {
0 => "{}".to_string(),
_ => {
format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
}
};
err.span_suggestion(
unexpanded_fmt_span.shrink_to_lo(),
"you might be missing a string literal to format with",
format!("\"{sugg_fmt}\", "),
Applicability::MaybeIncorrect,
);
}
}
err.emit()
}
err.emit()
}
Err(guar) => guar,
};
return Err(guar);
Err(guar) => guar,
};
return ExpandResult::Ready(Err(guar));
}
}
};
@ -297,7 +305,7 @@ fn make_format_args(
}
}
let guar = ecx.dcx().emit_err(e);
return Err(guar);
return ExpandResult::Ready(Err(guar));
}
let to_span = |inner_span: rustc_parse_format::InnerSpan| {
@ -564,7 +572,7 @@ fn make_format_args(
}
}
Ok(FormatArgs { span: fmt_span, template, arguments: args })
ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args }))
}
fn invalid_placeholder_type_error(
@ -972,25 +980,32 @@ fn expand_format_args_impl<'cx>(
mut sp: Span,
tts: TokenStream,
nl: bool,
) -> Box<dyn base::MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
sp = ecx.with_def_site_ctxt(sp);
match parse_args(ecx, sp, tts) {
Ok(input) => match make_format_args(ecx, input, nl) {
Ok(format_args) => MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))),
Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
},
ExpandResult::Ready(match parse_args(ecx, sp, tts) {
Ok(input) => {
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
return ExpandResult::Retry(());
};
match mac {
Ok(format_args) => {
MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
}
Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
}
}
Err(err) => {
let guar = err.emit();
DummyResult::any(sp, guar)
}
}
})
}
pub fn expand_format_args<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
expand_format_args_impl(ecx, sp, tts, false)
}
@ -998,6 +1013,6 @@ pub fn expand_format_args_nl<'cx>(
ecx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
expand_format_args_impl(ecx, sp, tts, true)
}

View file

@ -1,14 +1,14 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust;
use rustc_expand::base;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
pub fn expand_log_syntax<'cx>(
_cx: &'cx mut base::ExtCtxt<'_>,
_cx: &'cx mut ExtCtxt<'_>,
sp: rustc_span::Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
println!("{}", pprust::tts_to_string(&tts));
// any so that `log_syntax` can be invoked as an expression and item.
base::DummyResult::any_valid(sp)
ExpandResult::Ready(DummyResult::any_valid(sp))
}

View file

@ -3,10 +3,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust;
use rustc_expand::base::{
check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt,
MacEager, MacResult,
};
use rustc_expand::base::{check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt};
use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult};
use rustc_expand::module::DirOwnership;
use rustc_parse::new_parser_from_file;
use rustc_parse::parser::{ForceCollect, Parser};
@ -26,14 +25,14 @@ pub fn expand_line(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "line!");
let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo());
MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
}
/* column!(): expands to the current column number */
@ -41,14 +40,14 @@ pub fn expand_column(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "column!");
let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo());
MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
}
/// file!(): expands to the current filename */
@ -58,7 +57,7 @@ pub fn expand_file(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "file!");
@ -66,35 +65,35 @@ pub fn expand_file(
let loc = cx.source_map().lookup_char_pos(topmost.lo());
use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
MacEager::expr(cx.expr_str(
ExpandResult::Ready(MacEager::expr(cx.expr_str(
topmost,
Symbol::intern(
&loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
),
))
)))
}
pub fn expand_stringify(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
let s = pprust::tts_to_string(&tts);
MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
}
pub fn expand_mod(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
check_zero_tts(cx, sp, tts, "module_path!");
let mod_path = &cx.current_expansion.module.mod_path;
let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
}
/// include! : parse the given file as an expr
@ -104,18 +103,21 @@ pub fn expand_include<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
let sp = cx.with_def_site_ctxt(sp);
let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
return ExpandResult::Retry(());
};
let file = match mac {
Ok(file) => file,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
// The file will be added to the code map by the parser
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
let guar = err.emit();
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
};
let p = new_parser_from_file(cx.psess(), &file, Some(sp));
@ -128,12 +130,12 @@ pub fn expand_include<'cx>(
cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
struct ExpandResult<'a> {
struct ExpandInclude<'a> {
p: Parser<'a>,
node_id: ast::NodeId,
}
impl<'a> MacResult for ExpandResult<'a> {
fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
impl<'a> MacResult for ExpandInclude<'a> {
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> {
let expr = parse_expr(&mut self.p).ok()?;
if self.p.token != token::Eof {
self.p.psess.buffer_lint(
@ -146,7 +148,7 @@ pub fn expand_include<'cx>(
Some(expr)
}
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
let mut ret = SmallVec::new();
loop {
match self.p.parse_item(ForceCollect::No) {
@ -170,7 +172,7 @@ pub fn expand_include<'cx>(
}
}
Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
}
/// `include_str!`: read the given file, insert it as a literal string expr
@ -178,20 +180,23 @@ pub fn expand_include_str(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
return ExpandResult::Retry(());
};
let file = match mac {
Ok(file) => file,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
let guar = err.emit();
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
};
match cx.source_map().load_binary_file(&file) {
ExpandResult::Ready(match cx.source_map().load_binary_file(&file) {
Ok(bytes) => match std::str::from_utf8(&bytes) {
Ok(src) => {
let interned_src = Symbol::intern(src);
@ -206,27 +211,30 @@ pub fn expand_include_str(
let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp, guar)
}
}
})
}
pub fn expand_include_bytes(
cx: &mut ExtCtxt<'_>,
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let sp = cx.with_def_site_ctxt(sp);
let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
return ExpandResult::Retry(());
};
let file = match mac {
Ok(file) => file,
Err(guar) => return DummyResult::any(sp, guar),
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
Err(err) => {
let guar = err.emit();
return DummyResult::any(sp, guar);
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
};
match cx.source_map().load_binary_file(&file) {
ExpandResult::Ready(match cx.source_map().load_binary_file(&file) {
Ok(bytes) => {
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
MacEager::expr(expr)
@ -235,5 +243,5 @@ pub fn expand_include_bytes(
let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp, guar)
}
}
})
}

View file

@ -1,6 +1,6 @@
use crate::errors;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_expand::base::{self, ExtCtxt};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_span::symbol::kw;
use rustc_span::Span;
@ -8,7 +8,7 @@ pub fn expand_trace_macros(
cx: &mut ExtCtxt<'_>,
sp: Span,
tt: TokenStream,
) -> Box<dyn base::MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let mut cursor = tt.trees();
let mut err = false;
let value = match &cursor.next() {
@ -26,5 +26,5 @@ pub fn expand_trace_macros(
cx.set_trace_macros(value);
}
base::DummyResult::any_valid(sp)
ExpandResult::Ready(DummyResult::any_valid(sp))
}

View file

@ -2,25 +2,25 @@ use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{token, Expr, ExprKind, Ty};
use rustc_errors::PResult;
use rustc_expand::base::{self, DummyResult, ExtCtxt, MacEager};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_span::Span;
pub fn expand_type_ascribe(
cx: &mut ExtCtxt<'_>,
span: Span,
tts: TokenStream,
) -> Box<dyn base::MacResult + 'static> {
) -> MacroExpanderResult<'static> {
let (expr, ty) = match parse_ascribe(cx, tts) {
Ok(parsed) => parsed,
Err(err) => {
let guar = err.emit();
return DummyResult::any(span, guar);
return ExpandResult::Ready(DummyResult::any(span, guar));
}
};
let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
return MacEager::expr(asc_expr);
ExpandResult::Ready(MacEager::expr(asc_expr))
}
fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {

View file

@ -63,7 +63,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
global_value
}
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
fn codegen_static(&self, def_id: DefId) {
let attrs = self.tcx.codegen_fn_attrs(def_id);
let value = match codegen_static_initializer(&self, def_id) {
@ -92,7 +92,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
// As an optimization, all shared statics which do not have interior
// mutability are placed into read-only memory.
if !is_mutable && self.type_is_freeze(ty) {
if !self.tcx.static_mutability(def_id).unwrap().is_mut() && self.type_is_freeze(ty) {
#[cfg(feature = "master")]
global.global_set_readonly();
}
@ -349,7 +349,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(
cx.const_struct(&llvals, true)
}
pub fn codegen_static_initializer<'gcc, 'tcx>(
fn codegen_static_initializer<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
def_id: DefId,
) -> Result<(RValue<'gcc>, ConstAllocation<'tcx>), ErrorHandled> {

View file

@ -1,7 +1,9 @@
#[cfg(feature = "master")]
use gccjit::{FnAttribute, VarAttribute};
use rustc_codegen_ssa::traits::PreDefineMethods;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
@ -23,7 +25,14 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
) {
let attrs = self.tcx.codegen_fn_attrs(def_id);
let instance = Instance::mono(self.tcx, def_id);
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
// Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out
// the gcc type from the actual evaluated initializer.
let ty = if nested {
self.tcx.types.unit
} else {
instance.ty(self.tcx, ty::ParamEnv::reveal_all())
};
let gcc_type = self.layout_of(ty).gcc_type(self);
let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);

View file

@ -1132,9 +1132,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
&mut self,
op: rustc_codegen_ssa::common::AtomicRmwBinOp,
dst: &'ll Value,
src: &'ll Value,
mut src: &'ll Value,
order: rustc_codegen_ssa::common::AtomicOrdering,
) -> &'ll Value {
// The only RMW operation that LLVM supports on pointers is compare-exchange.
if self.val_ty(src) == self.type_ptr()
&& op != rustc_codegen_ssa::common::AtomicRmwBinOp::AtomicXchg
{
src = self.ptrtoint(src, self.type_isize());
}
unsafe {
llvm::LLVMBuildAtomicRMW(
self.llbuilder,

View file

@ -95,11 +95,13 @@ impl<'ll> BackendTypes for CodegenCx<'ll, '_> {
impl<'ll> CodegenCx<'ll, '_> {
pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
unsafe { llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint) }
let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow");
unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
}
pub fn const_vector(&self, elts: &[&'ll Value]) -> &'ll Value {
unsafe { llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint) }
let len = c_uint::try_from(elts.len()).expect("LLVMConstVector elements len overflow");
unsafe { llvm::LLVMConstVector(elts.as_ptr(), len) }
}
pub fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
@ -108,8 +110,8 @@ impl<'ll> CodegenCx<'ll, '_> {
pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
assert_eq!(idx as c_uint as u64, idx);
let r = llvm::LLVMGetAggregateElement(v, idx as c_uint).unwrap();
let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
let r = llvm::LLVMGetAggregateElement(v, idx).unwrap();
debug!("const_get_elt(v={:?}, idx={}, r={:?})", v, idx, r);
@ -329,7 +331,7 @@ pub fn val_ty(v: &Value) -> &Type {
pub fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
unsafe {
let ptr = bytes.as_ptr() as *const c_char;
llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True)
llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), True)
}
}
@ -338,9 +340,8 @@ pub fn struct_in_context<'ll>(
elts: &[&'ll Value],
packed: bool,
) -> &'ll Value {
unsafe {
llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), elts.len() as c_uint, packed as Bool)
}
let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
unsafe { llvm::LLVMConstStructInContext(llcx, elts.as_ptr(), len, packed as Bool) }
}
#[inline]

View file

@ -9,6 +9,7 @@ use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
@ -17,7 +18,7 @@ use rustc_middle::mir::interpret::{
};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::ty::{self, Instance};
use rustc_middle::{bug, span_bug};
use rustc_session::config::Lto;
use rustc_target::abi::{
@ -114,7 +115,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
cx.const_struct(&llvals, true)
}
pub fn codegen_static_initializer<'ll, 'tcx>(
fn codegen_static_initializer<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> {
@ -147,11 +148,10 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
fn check_and_apply_linkage<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
attrs: &CodegenFnAttrs,
ty: Ty<'tcx>,
llty: &'ll Type,
sym: &str,
def_id: DefId,
) -> &'ll Value {
let llty = cx.layout_of(ty).llvm_type(cx);
if let Some(linkage) = attrs.import_linkage {
debug!("get_static: sym={} linkage={:?}", sym, linkage);
@ -226,9 +226,28 @@ impl<'ll> CodegenCx<'ll, '_> {
}
}
#[instrument(level = "debug", skip(self))]
pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value {
let instance = Instance::mono(self.tcx, def_id);
if let Some(&g) = self.instances.borrow().get(&instance) {
trace!(?instance);
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
// Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out
// the llvm type from the actual evaluated initializer.
let llty = if nested {
self.type_i8()
} else {
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
trace!(?ty);
self.layout_of(ty).llvm_type(self)
};
self.get_static_inner(def_id, llty)
}
#[instrument(level = "debug", skip(self, llty))]
pub(crate) fn get_static_inner(&self, def_id: DefId, llty: &'ll Type) -> &'ll Value {
if let Some(&g) = self.instances.borrow().get(&Instance::mono(self.tcx, def_id)) {
trace!("used cached value");
return g;
}
@ -240,14 +259,12 @@ impl<'ll> CodegenCx<'ll, '_> {
statics defined in the same CGU, but did not for `{def_id:?}`"
);
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let sym = self.tcx.symbol_name(instance).name;
let sym = self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name;
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs);
debug!(?sym, ?fn_attrs);
let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
let llty = self.layout_of(ty).llvm_type(self);
if let Some(g) = self.get_declared_value(sym) {
if self.val_ty(g) != self.type_ptr() {
span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
@ -264,7 +281,7 @@ impl<'ll> CodegenCx<'ll, '_> {
g
} else {
check_and_apply_linkage(self, fn_attrs, ty, sym, def_id)
check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
};
// Thread-local statics in some other crate need to *always* be linked
@ -332,34 +349,18 @@ impl<'ll> CodegenCx<'ll, '_> {
}
}
self.instances.borrow_mut().insert(instance, g);
self.instances.borrow_mut().insert(Instance::mono(self.tcx, def_id), g);
g
}
}
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
unsafe {
// Upgrade the alignment in cases where the same constant is used with different
// alignment requirements
let llalign = align.bytes() as u32;
if llalign > llvm::LLVMGetAlignment(gv) {
llvm::LLVMSetAlignment(gv, llalign);
}
}
return gv;
}
let gv = self.static_addr_of_mut(cv, align, kind);
unsafe {
llvm::LLVMSetGlobalConstant(gv, True);
}
self.const_globals.borrow_mut().insert(cv, gv);
gv
}
fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
fn codegen_static_item(&self, def_id: DefId) {
unsafe {
assert!(
llvm::LLVMGetInitializer(
self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap()
)
.is_none()
);
let attrs = self.tcx.codegen_fn_attrs(def_id);
let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else {
@ -368,13 +369,11 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
};
let alloc = alloc.inner();
let g = self.get_static(def_id);
let val_llty = self.val_ty(v);
let instance = Instance::mono(self.tcx, def_id);
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let llty = self.layout_of(ty).llvm_type(self);
let g = self.get_static_inner(def_id, val_llty);
let llty = self.val_ty(g);
let g = if val_llty == llty {
g
} else {
@ -409,16 +408,15 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
self.statics_to_rauw.borrow_mut().push((g, new_g));
new_g
};
set_global_alignment(self, g, self.align_of(ty));
set_global_alignment(self, g, alloc.align);
llvm::LLVMSetInitializer(g, v);
if self.should_assume_dso_local(g, true) {
llvm::LLVMRustSetDSOLocal(g, true);
}
// As an optimization, all shared statics which do not have interior
// mutability are placed into read-only memory.
if !is_mutable && self.type_is_freeze(ty) {
// Forward the allocation's mutability (picked by the const interner) to LLVM.
if alloc.mutability.is_not() {
llvm::LLVMSetGlobalConstant(g, llvm::True);
}
@ -541,6 +539,32 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
}
}
}
}
impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value {
if let Some(&gv) = self.const_globals.borrow().get(&cv) {
unsafe {
// Upgrade the alignment in cases where the same constant is used with different
// alignment requirements
let llalign = align.bytes() as u32;
if llalign > llvm::LLVMGetAlignment(gv) {
llvm::LLVMSetAlignment(gv, llalign);
}
}
return gv;
}
let gv = self.static_addr_of_mut(cv, align, kind);
unsafe {
llvm::LLVMSetGlobalConstant(gv, True);
}
self.const_globals.borrow_mut().insert(cv, gv);
gv
}
fn codegen_static(&self, def_id: DefId) {
self.codegen_static_item(def_id)
}
/// Add a global value to a list to be stored in the `llvm.used` variable, an array of ptr.
fn add_used_global(&self, global: &'ll Value) {

View file

@ -355,21 +355,20 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
let tcx = cx.tcx;
let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
let eligible_def_ids = tcx.mir_keys(()).iter().filter_map(|local_def_id| {
let def_id = local_def_id.to_def_id();
let kind = tcx.def_kind(def_id);
// `mir_keys` will give us `DefId`s for all kinds of things, not
// just "functions", like consts, statics, etc. Filter those out.
// If `ignore_unused_generics` was specified, filter out any
// generic functions from consideration as well.
if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) {
return None;
}
if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
return None;
}
// FIXME(79651): Consider trying to filter out dummy instantiations of
// unused generic functions from library crates, because they can produce
// "unused instantiation" in coverage reports even when they are actually
// used by some downstream crate in the same binary.
Some(local_def_id.to_def_id())
});

View file

@ -26,6 +26,7 @@ use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
use rustc_codegen_ssa::traits::*;
use rustc_fs_util::path_to_c_string;
use rustc_hir::def::CtorKind;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@ -1309,6 +1310,11 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo
};
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
let DefKind::Static { nested, .. } = cx.tcx.def_kind(def_id) else { bug!() };
if nested {
return;
}
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
let type_di_node = type_di_node(cx, variable_type);
let var_name = tcx.item_name(def_id);

View file

@ -936,10 +936,16 @@ extern "C" {
pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
// Operations on composite constants
pub fn LLVMConstStringInContext(
pub fn LLVMConstArray2<'a>(
ElementTy: &'a Type,
ConstantVals: *const &'a Value,
Length: u64,
) -> &'a Value;
pub fn LLVMArrayType2(ElementType: &Type, ElementCount: u64) -> &Type;
pub fn LLVMConstStringInContext2(
C: &Context,
Str: *const c_char,
Length: c_uint,
Length: size_t,
DontNullTerminate: Bool,
) -> &Value;
pub fn LLVMConstStructInContext<'a>(
@ -948,14 +954,6 @@ extern "C" {
Count: c_uint,
Packed: Bool,
) -> &'a Value;
// FIXME: replace with LLVMConstArray2 when bumped minimal version to llvm-17
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
pub fn LLVMConstArray<'a>(
ElementTy: &'a Type,
ConstantVals: *const &'a Value,
Length: c_uint,
) -> &'a Value;
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
// Constant expressions
@ -1530,9 +1528,6 @@ extern "C" {
/// See llvm::LLVMTypeKind::getTypeID.
pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
// Operations on array, pointer, and vector types (sequence types)
pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type;
// Operations on all values
pub fn LLVMRustGlobalAddMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
pub fn LLVMRustIsNonGVFunctionPointerTy(Val: &Value) -> bool;

View file

@ -5,7 +5,9 @@ use crate::errors::SymbolAlreadyDefined;
use crate::llvm;
use crate::type_of::LayoutLlvmExt;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
@ -21,7 +23,14 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
symbol_name: &str,
) {
let instance = Instance::mono(self.tcx, def_id);
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() };
// Nested statics do not have a type, so pick a dummy type and let `codegen_static` figure out
// the llvm type from the actual evaluated initializer.
let ty = if nested {
self.tcx.types.unit
} else {
instance.ty(self.tcx, ty::ParamEnv::reveal_all())
};
let llty = self.layout_of(ty).llvm_type(self);
let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {

View file

@ -233,7 +233,7 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
unsafe { llvm::LLVMRustArrayType(ty, len) }
unsafe { llvm::LLVMArrayType2(ty, len) }
}
}

View file

@ -87,7 +87,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
// Only consider nodes that actually have exported symbols.
match tcx.def_kind(def_id) {
DefKind::Fn | DefKind::Static(_) => {}
DefKind::Fn | DefKind::Static { .. } => {}
DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
_ => return None,
};
@ -483,7 +483,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
let target = &tcx.sess.target.llvm_target;
// WebAssembly cannot export data symbols, so reduce their export level
if target.contains("emscripten") {
if let DefKind::Static(_) = tcx.def_kind(sym_def_id) {
if let DefKind::Static { .. } = tcx.def_kind(sym_def_id) {
return SymbolExportLevel::Rust;
}
}

View file

@ -42,7 +42,7 @@ pub enum RealPredicate {
RealPredicateTrue,
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq)]
pub enum AtomicRmwBinOp {
AtomicXchg,
AtomicAdd,

View file

@ -1237,6 +1237,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
pub fn codegen_block_as_unreachable(&mut self, bb: mir::BasicBlock) {
let llbb = match self.try_llbb(bb) {
Some(llbb) => llbb,
None => return,
};
let bx = &mut Bx::build(self.cx, llbb);
debug!("codegen_block_as_unreachable({:?})", bb);
bx.unreachable();
}
fn codegen_terminator(
&mut self,
bx: &mut Bx,

View file

@ -350,14 +350,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
let weak = instruction == "cxchgweak";
let dst = args[0].immediate();
let mut cmp = args[1].immediate();
let mut src = args[2].immediate();
if ty.is_unsafe_ptr() {
// Some platforms do not support atomic operations on pointers,
// so we cast to integer first.
cmp = bx.ptrtoint(cmp, bx.type_isize());
src = bx.ptrtoint(src, bx.type_isize());
}
let cmp = args[1].immediate();
let src = args[2].immediate();
let (val, success) = bx.atomic_cmpxchg(
dst,
cmp,
@ -385,26 +379,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let layout = bx.layout_of(ty);
let size = layout.size;
let source = args[0].immediate();
if ty.is_unsafe_ptr() {
// Some platforms do not support atomic operations on pointers,
// so we cast to integer first...
let llty = bx.type_isize();
let result = bx.atomic_load(
llty,
source,
parse_ordering(bx, ordering),
size,
);
// ... and then cast the result back to a pointer
bx.inttoptr(result, bx.backend_type(layout))
} else {
bx.atomic_load(
bx.backend_type(layout),
source,
parse_ordering(bx, ordering),
size,
)
}
bx.atomic_load(
bx.backend_type(layout),
source,
parse_ordering(bx, ordering),
size,
)
} else {
invalid_monomorphization(ty);
return Ok(());
@ -415,13 +395,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ty = fn_args.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
let size = bx.layout_of(ty).size;
let mut val = args[1].immediate();
let val = args[1].immediate();
let ptr = args[0].immediate();
if ty.is_unsafe_ptr() {
// Some platforms do not support atomic operations on pointers,
// so we cast to integer first.
val = bx.ptrtoint(val, bx.type_isize());
}
bx.atomic_store(val, ptr, parse_ordering(bx, ordering), size);
} else {
invalid_monomorphization(ty);
@ -465,12 +440,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let ty = fn_args.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
let ptr = args[0].immediate();
let mut val = args[1].immediate();
if ty.is_unsafe_ptr() {
// Some platforms do not support atomic operations on pointers,
// so we cast to integer first.
val = bx.ptrtoint(val, bx.type_isize());
}
let val = args[1].immediate();
bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering))
} else {
invalid_monomorphization(ty);

View file

@ -256,13 +256,22 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx);
let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance);
// The builders will be created separately for each basic block at `codegen_block`.
// So drop the builder of `start_llbb` to avoid having two at the same time.
drop(start_bx);
// Codegen the body of each block using reverse postorder
for (bb, _) in traversal::reverse_postorder(mir) {
fx.codegen_block(bb);
if reachable_blocks.contains(bb) {
fx.codegen_block(bb);
} else {
// This may have references to things we didn't monomorphize, so we
// don't actually codegen the body. We still create the block so
// terminators in other blocks can reference it without worry.
fx.codegen_block_as_unreachable(bb);
}
}
}

View file

@ -306,11 +306,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.bitcast(imm, to_backend_ty)
}
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.inttoptr(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
(F16 | F32 | F64 | F128, Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.inttoptr(int_imm, to_backend_ty)
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
}
(Pointer(..), F16 | F32 | F64 | F128) => {
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());

View file

@ -30,7 +30,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
match *self {
MonoItem::Static(def_id) => {
cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id));
cx.codegen_static(def_id);
}
MonoItem::GlobalAsm(item_id) => {
let item = cx.tcx().hir().item(item_id);

View file

@ -4,7 +4,7 @@ use rustc_target::abi::Align;
pub trait StaticMethods: BackendTypes {
fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
fn codegen_static(&self, def_id: DefId, is_mutable: bool);
fn codegen_static(&self, def_id: DefId);
/// Mark the given global value as "used", to prevent the compiler and linker from potentially
/// removing a static variable that may otherwise appear unused.

View file

@ -37,7 +37,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|| matches!(
ecx.tcx.def_kind(cid.instance.def_id()),
DefKind::Const
| DefKind::Static(_)
| DefKind::Static { .. }
| DefKind::ConstParam
| DefKind::AnonConst
| DefKind::InlineConst
@ -59,7 +59,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
};
let ret = if let InternKind::Static(_) = intern_kind {
create_static_alloc(ecx, cid.instance.def_id(), layout)?
create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)?
} else {
ecx.allocate(layout, MemoryKind::Stack)?
};
@ -380,7 +380,11 @@ pub fn eval_in_interpreter<'mir, 'tcx>(
}
Ok(mplace) => {
// Since evaluation had no errors, validate the resulting constant.
// Temporarily allow access to the static_root_ids for the purpose of validation.
let static_root_ids = ecx.machine.static_root_ids.take();
let res = const_validate_mplace(&ecx, &mplace, cid);
ecx.machine.static_root_ids = static_root_ids;
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();

View file

@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::fx::IndexEntry;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::LangItem;
use rustc_middle::mir;
use rustc_middle::mir::AssertMessage;
@ -59,8 +60,10 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
/// Whether to check alignment during evaluation.
pub(super) check_alignment: CheckAlignment,
/// Used to prevent reads from a static's base allocation, as that may allow for self-initialization.
pub(crate) static_root_alloc_id: Option<AllocId>,
/// If `Some`, we are evaluating the initializer of the static with the given `LocalDefId`,
/// storing the result in the given `AllocId`.
/// Used to prevent reads from a static's base allocation, as that may allow for self-initialization loops.
pub(crate) static_root_ids: Option<(AllocId, LocalDefId)>,
}
#[derive(Copy, Clone)]
@ -94,7 +97,7 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
stack: Vec::new(),
can_access_mut_global,
check_alignment,
static_root_alloc_id: None,
static_root_ids: None,
}
}
}
@ -749,7 +752,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
ecx: &InterpCx<'mir, 'tcx, Self>,
alloc_id: AllocId,
) -> InterpResult<'tcx> {
if Some(alloc_id) == ecx.machine.static_root_alloc_id {
if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
Err(ConstEvalErrKind::RecursiveStatic.into())
} else {
Ok(())

View file

@ -25,10 +25,13 @@ pub(crate) struct DanglingPtrInFinal {
pub kind: InternKind,
}
#[derive(Diagnostic)]
#[derive(LintDiagnostic)]
#[diag(const_eval_mutable_ptr_in_final)]
pub(crate) struct MutablePtrInFinal {
#[primary_span]
// rust-lang/rust#122153: This was marked as `#[primary_span]` under
// `derive(Diagnostic)`. Since we expect we may hard-error in future, we are
// keeping the field (and skipping it under `derive(LintDiagnostic)`).
#[skip_arg]
pub span: Span,
pub kind: InternKind,
}

View file

@ -13,12 +13,17 @@
//! but that would require relying on type information, and given how many ways Rust has to lie
//! about type information, we want to avoid doing that.
use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult};
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_session::lint;
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
use crate::const_eval;
@ -33,7 +38,19 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
FrameExtra = (),
AllocExtra = (),
MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
>;
> + HasStaticRootDefId;
pub trait HasStaticRootDefId {
/// Returns the `DefId` of the static item that is currently being evaluated.
/// Used for interning to be able to handle nested allocations.
fn static_def_id(&self) -> Option<LocalDefId>;
}
impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_, '_> {
fn static_def_id(&self) -> Option<LocalDefId> {
Some(self.static_root_ids?.1)
}
}
/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory.
///
@ -67,10 +84,35 @@ fn intern_shallow<'rt, 'mir, 'tcx, T, M: CompileTimeMachine<'mir, 'tcx, T>>(
}
// link the alloc id to the actual allocation
let alloc = ecx.tcx.mk_const_alloc(alloc);
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
if let Some(static_id) = ecx.machine.static_def_id() {
intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc);
} else {
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
}
Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov))
}
/// Creates a new `DefId` and feeds all the right queries to make this `DefId`
/// appear as if it were a user-written `static` (though it has no HIR).
fn intern_as_new_static<'tcx>(
tcx: TyCtxtAt<'tcx>,
static_id: LocalDefId,
alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
) {
let feed = tcx.create_def(
static_id,
sym::nested,
DefKind::Static { mutability: alloc.0.mutability, nested: true },
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
feed.codegen_fn_attrs(tcx.codegen_fn_attrs(static_id).clone());
feed.eval_static_initializer(Ok(alloc));
feed.generics_of(tcx.generics_of(static_id).clone());
feed.def_ident_span(tcx.def_ident_span(static_id));
feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id));
}
/// How a constant value should be interned.
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
pub enum InternKind {
@ -221,10 +263,13 @@ pub fn intern_const_alloc_recursive<
})?);
}
if found_bad_mutable_pointer {
return Err(ecx
.tcx
.dcx()
.emit_err(MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }));
let err_diag = MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
ecx.tcx.emit_node_span_lint(
lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
ecx.best_lint_scope(),
err_diag.span,
err_diag,
)
}
Ok(())

View file

@ -443,7 +443,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
_prov: (AllocId, Self::ProvenanceExtra),
_range: AllocRange,
_size: Size,
_align: Align,
) -> InterpResult<'tcx> {
Ok(())
}

View file

@ -15,6 +15,7 @@ use std::ptr;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir::def::DefKind;
use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size};
@ -352,7 +353,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&mut self.machine,
&mut alloc.extra,
(alloc_id, prov),
alloc_range(Size::ZERO, size),
size,
alloc.align,
)?;
// Don't forget to remember size and align of this now-dead allocation
@ -761,19 +763,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// be held throughout the match.
match self.tcx.try_get_global_alloc(id) {
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
// Thread-local statics do not have a constant address. They *must* be accessed via
// `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
assert!(!self.tcx.is_thread_local_static(def_id));
// Use size and align of the type.
let ty = self
.tcx
.type_of(def_id)
.no_bound_vars()
.expect("statics should not have generic parameters");
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
assert!(layout.is_sized());
(layout.size, layout.align.abi, AllocKind::LiveData)
let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else {
bug!("GlobalAlloc::Static is not a static")
};
let (size, align) = if nested {
// Nested anonymous statics are untyped, so let's get their
// size and alignment from the allocaiton itself. This always
// succeeds, as the query is fed at DefId creation time, so no
// evaluation actually occurs.
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
(alloc.0.size(), alloc.0.align)
} else {
// Use size and align of the type for everything else. We need
// to do that to
// * avoid cycle errors in case of self-referential statics,
// * be able to get information on extern statics.
let ty = self
.tcx
.type_of(def_id)
.no_bound_vars()
.expect("statics should not have generic parameters");
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
assert!(layout.is_sized());
(layout.size, layout.align.abi)
};
(size, align, AllocKind::LiveData)
}
Some(GlobalAlloc::Memory(alloc)) => {
// Need to duplicate the logic here, because the global allocations have

View file

@ -22,7 +22,7 @@ pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in
pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
pub use self::intern::{
intern_const_alloc_for_constprop, intern_const_alloc_recursive, InternKind,
intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
};
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};

View file

@ -1,11 +1,11 @@
use crate::const_eval::CompileTimeEvalContext;
use crate::interpret::{MemPlaceMeta, MemoryKind};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_span::def_id::DefId;
use std::ops::ControlFlow;
use super::MPlaceTy;
@ -89,13 +89,13 @@ pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>(
pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
static_def_id: DefId,
static_def_id: LocalDefId,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?;
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id);
assert_eq!(ecx.machine.static_root_alloc_id, None);
ecx.machine.static_root_alloc_id = Some(alloc_id);
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
assert_eq!(ecx.machine.static_root_ids, None);
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout))
}

View file

@ -457,15 +457,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// Special handling for pointers to statics (irrespective of their type).
assert!(!self.ecx.tcx.is_thread_local_static(did));
assert!(self.ecx.tcx.is_static(did));
let is_mut =
matches!(self.ecx.tcx.def_kind(did), DefKind::Static(Mutability::Mut))
|| !self
.ecx
.tcx
.type_of(did)
.no_bound_vars()
.expect("statics should not have generic parameters")
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all());
// Mode-specific checks
match self.ctfe_mode {
Some(
@ -490,8 +481,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
}
None => {}
}
// Return alloc mutability
if is_mut { Mutability::Mut } else { Mutability::Not }
// Return alloc mutability. For "root" statics we look at the type to account for interior
// mutability; for nested statics we have no type and directly use the annotated mutability.
let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did)
else {
bug!()
};
match (mutability, nested) {
(Mutability::Mut, _) => Mutability::Mut,
(Mutability::Not, true) => Mutability::Not,
(Mutability::Not, false)
if !self
.ecx
.tcx
.type_of(did)
.no_bound_vars()
.expect("statics should not have generic parameters")
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) =>
{
Mutability::Mut
}
(Mutability::Not, false) => Mutability::Not,
}
}
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {

View file

@ -1327,6 +1327,9 @@ pub fn install_ice_hook(
panic::update_hook(Box::new(
move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static),
info: &PanicInfo<'_>| {
// Lock stderr to prevent interleaving of concurrent panics.
let _guard = io::stderr().lock();
// If the error was caused by a broken pipe then this is not a bug.
// Write the error and return immediately. See #98700.
#[cfg(windows)]

View file

@ -336,8 +336,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
ThirTree => {
let tcx = ex.tcx();
let mut out = String::new();
rustc_hir_analysis::check_crate(tcx);
if tcx.dcx().has_errors().is_some() {
if rustc_hir_analysis::check_crate(tcx).is_err() {
FatalError.raise();
}
debug!("pretty printing THIR tree");
@ -349,8 +348,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
ThirFlat => {
let tcx = ex.tcx();
let mut out = String::new();
rustc_hir_analysis::check_crate(tcx);
if tcx.dcx().has_errors().is_some() {
if rustc_hir_analysis::check_crate(tcx).is_err() {
FatalError.raise();
}
debug!("pretty printing THIR flat");

View file

@ -769,13 +769,10 @@ impl DiagCtxt {
format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
);
}
Error => {
// This `unchecked_error_guaranteed` is valid. It is where the
// `ErrorGuaranteed` for stashed errors originates. See
// `DiagCtxtInner::drop`.
#[allow(deprecated)]
Some(ErrorGuaranteed::unchecked_error_guaranteed())
}
// We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs`
// can be used to create a backtrace at the stashing site insted of whenever the
// diagnostic context is dropped and thus delayed bugs are emitted.
Error => Some(self.span_delayed_bug(span, "stashing {key:?}")),
DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag),
ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
| Expect(_) => None,

View file

@ -245,6 +245,15 @@ pub enum ExpandResult<T, U> {
Retry(U),
}
impl<T, U> ExpandResult<T, U> {
pub fn map<E, F: FnOnce(T) -> E>(self, f: F) -> ExpandResult<E, U> {
match self {
ExpandResult::Ready(t) => ExpandResult::Ready(f(t)),
ExpandResult::Retry(u) => ExpandResult::Retry(u),
}
}
}
pub trait MultiItemModifier {
/// `meta_item` is the attribute, and `item` is the item being modified.
fn expand(
@ -330,22 +339,24 @@ pub trait TTMacroExpander {
ecx: &'cx mut ExtCtxt<'_>,
span: Span,
input: TokenStream,
) -> Box<dyn MacResult + 'cx>;
) -> MacroExpanderResult<'cx>;
}
pub type MacroExpanderResult<'cx> = ExpandResult<Box<dyn MacResult + 'cx>, ()>;
pub type MacroExpanderFn =
for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>;
for<'cx> fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>;
impl<F> TTMacroExpander for F
where
F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> Box<dyn MacResult + 'cx>,
F: for<'cx> Fn(&'cx mut ExtCtxt<'_>, Span, TokenStream) -> MacroExpanderResult<'cx>,
{
fn expand<'cx>(
&self,
ecx: &'cx mut ExtCtxt<'_>,
span: Span,
input: TokenStream,
) -> Box<dyn MacResult + 'cx> {
) -> MacroExpanderResult<'cx> {
self(ecx, span, input)
}
}
@ -904,8 +915,11 @@ impl SyntaxExtension {
cx: &'cx mut ExtCtxt<'_>,
span: Span,
_: TokenStream,
) -> Box<dyn MacResult + 'cx> {
DummyResult::any(span, cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"))
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(DummyResult::any(
span,
cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"),
))
}
SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition)
}
@ -1008,6 +1022,11 @@ pub trait ResolverExpand {
expn_id: LocalExpnId,
path: &ast::Path,
) -> Result<bool, Indeterminate>;
fn macro_accessible(
&mut self,
expn_id: LocalExpnId,
path: &ast::Path,
) -> Result<bool, Indeterminate>;
/// Decodes the proc-macro quoted span in the specified crate, with the specified id.
/// No caching is performed.
@ -1253,6 +1272,15 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
}
}
/// `Ok` represents successfully retrieving the string literal at the correct
/// position, e.g., `println("abc")`.
type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
/// but another type of expression is obtained instead.
/// - `Err` is returned when the conversion process fails.
type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>;
/// Extracts a string literal from the macro expanded version of `expr`,
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
/// The returned bool indicates whether an applicable suggestion has already been
@ -1264,17 +1292,23 @@ pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
err_msg: &'static str,
) -> Result<
(Symbol, ast::StrStyle, Span),
Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>,
> {
) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
if !cx.force_mode
&& let ast::ExprKind::MacCall(m) = &expr.kind
&& cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
{
return ExpandResult::Retry(());
}
// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
Err(match expr.kind {
ExpandResult::Ready(Err(match expr.kind {
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Str(s, style)) => return Ok((s, style, expr.span)),
Ok(ast::LitKind::Str(s, style)) => {
return ExpandResult::Ready(Ok((s, style, expr.span)));
}
Ok(ast::LitKind::ByteStr(..)) => {
let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
let span = expr.span.shrink_to_lo();
@ -1295,7 +1329,7 @@ pub fn expr_to_spanned_string<'a>(
cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`")
}
_ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
})
}))
}
/// Extracts a string literal from the macro expanded version of `expr`,
@ -1305,13 +1339,14 @@ pub fn expr_to_string(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
err_msg: &'static str,
) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> {
expr_to_spanned_string(cx, expr, err_msg)
.map_err(|err| match err {
) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
expr_to_spanned_string(cx, expr, err_msg).map(|res| {
res.map_err(|err| match err {
Ok((err, _)) => err.emit(),
Err(guar) => guar,
})
.map(|(symbol, style, _)| (symbol, style))
})
}
/// Non-fatally assert that `tts` is empty. Note that this function
@ -1343,19 +1378,22 @@ pub fn get_single_str_from_tts(
span: Span,
tts: TokenStream,
name: &str,
) -> Result<Symbol, ErrorGuaranteed> {
) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> {
let mut p = cx.new_parser_from_tts(tts);
if p.token == token::Eof {
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
return Err(guar);
return ExpandResult::Ready(Err(guar));
}
let ret = parse_expr(&mut p)?;
let ret = match parse_expr(&mut p) {
Ok(ret) => ret,
Err(guar) => return ExpandResult::Ready(Err(guar)),
};
let _ = p.eat(&token::Comma);
if p.token != token::Eof {
cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
}
expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
expr_to_string(cx, ret, "argument must be a string literal").map(|s| s.map(|(s, _)| s))
}
/// Extracts comma-separated expressions from `tts`.
@ -1363,11 +1401,20 @@ pub fn get_single_str_from_tts(
pub fn get_exprs_from_tts(
cx: &mut ExtCtxt<'_>,
tts: TokenStream,
) -> Result<Vec<P<ast::Expr>>, ErrorGuaranteed> {
) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> {
let mut p = cx.new_parser_from_tts(tts);
let mut es = Vec::new();
while p.token != token::Eof {
let expr = parse_expr(&mut p)?;
let expr = match parse_expr(&mut p) {
Ok(expr) => expr,
Err(guar) => return ExpandResult::Ready(Err(guar)),
};
if !cx.force_mode
&& let ast::ExprKind::MacCall(m) = &expr.kind
&& cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
{
return ExpandResult::Retry(());
}
// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
@ -1379,10 +1426,10 @@ pub fn get_exprs_from_tts(
}
if p.token != token::Eof {
let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
return Err(guar);
return ExpandResult::Ready(Err(guar));
}
}
Ok(es)
ExpandResult::Ready(Ok(es))
}
pub fn parse_macro_name_and_helper_attrs(

View file

@ -218,7 +218,7 @@ impl<'a> ExtCtxt<'a> {
}
pub fn stmt_local(&self, local: P<ast::Local>, span: Span) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span }
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Let(local), span }
}
pub fn stmt_item(&self, sp: Span, item: P<ast::Item>) -> ast::Stmt {

View file

@ -659,7 +659,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
ExpandResult::Ready(match invoc.kind {
InvocationKind::Bang { mac, .. } => match ext {
InvocationKind::Bang { mac, span } => match ext {
SyntaxExtensionKind::Bang(expander) => {
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
Ok(tok_result) => {
@ -669,7 +669,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
SyntaxExtensionKind::LegacyBang(expander) => {
let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
ExpandResult::Ready(tok_result) => tok_result,
ExpandResult::Retry(_) => {
// retry the original
return ExpandResult::Retry(Invocation {
kind: InvocationKind::Bang { mac, span },
..invoc
});
}
};
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
result
} else {
@ -1380,7 +1389,7 @@ impl InvocationCollectorNode for ast::Stmt {
StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
StmtKind::Expr(..) => unreachable!(),
StmtKind::Local(..) | StmtKind::Empty => false,
StmtKind::Let(..) | StmtKind::Empty => false,
}
}
fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {

View file

@ -1,5 +1,5 @@
use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
use crate::base::{SyntaxExtension, SyntaxExtensionKind};
use crate::base::{DummyResult, SyntaxExtension, SyntaxExtensionKind};
use crate::base::{ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, TTMacroExpander};
use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind};
use crate::mbe;
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
@ -111,8 +111,8 @@ impl TTMacroExpander for MacroRulesMacroExpander {
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
input: TokenStream,
) -> Box<dyn MacResult + 'cx> {
expand_macro(
) -> MacroExpanderResult<'cx> {
ExpandResult::Ready(expand_macro(
cx,
sp,
self.span,
@ -122,7 +122,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
input,
&self.lhses,
&self.rhses,
)
))
}
}
@ -134,8 +134,8 @@ impl TTMacroExpander for DummyExpander {
_: &'cx mut ExtCtxt<'_>,
span: Span,
_: TokenStream,
) -> Box<dyn MacResult + 'cx> {
DummyResult::any(span, self.0)
) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> {
ExpandResult::Ready(DummyResult::any(span, self.0))
}
}

View file

@ -75,7 +75,12 @@ pub enum DefKind {
Const,
/// Constant generic parameter: `struct Foo<const N: usize> { ... }`
ConstParam,
Static(ast::Mutability),
Static {
/// Whether it's a `static mut` or just a `static`.
mutability: ast::Mutability,
/// Whether it's an anonymous static generated for nested allocations.
nested: bool,
},
/// Refers to the struct or enum variant's constructor.
///
/// The reason `Ctor` exists in addition to [`DefKind::Struct`] and
@ -136,7 +141,7 @@ impl DefKind {
DefKind::Fn => "function",
DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
DefKind::Mod => "module",
DefKind::Static(..) => "static",
DefKind::Static { .. } => "static",
DefKind::Enum => "enum",
DefKind::Variant => "variant",
DefKind::Ctor(CtorOf::Variant, CtorKind::Fn) => "tuple variant",
@ -209,7 +214,7 @@ impl DefKind {
DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst => Some(Namespace::ValueNS),
@ -245,10 +250,13 @@ impl DefKind {
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::ExternCrate => DefPathData::TypeNs(name),
// It's not exactly an anon const, but wrt DefPathData, there
// is no difference.
DefKind::Static { nested: true, .. } => DefPathData::AnonConst,
DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::Field => DefPathData::ValueNs(name),
@ -278,7 +286,7 @@ impl DefKind {
| DefKind::AssocFn
| DefKind::Ctor(..)
| DefKind::Closure
| DefKind::Static(_) => true,
| DefKind::Static { .. } => true,
DefKind::Mod
| DefKind::Struct
| DefKind::Union

View file

@ -1209,7 +1209,7 @@ pub struct Stmt<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum StmtKind<'hir> {
/// A local (`let`) binding.
Local(&'hir Local<'hir>),
Let(&'hir Local<'hir>),
/// An item binding.
Item(ItemId),
@ -1253,11 +1253,11 @@ pub struct Arm<'hir> {
pub body: &'hir Expr<'hir>,
}
/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a Local), occurring in an `if-let` or
/// `let-else`, evaluating to a boolean. Typically the pattern is refutable.
/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`Local`]), occurring in an `if-let`
/// or `let-else`, evaluating to a boolean. Typically the pattern is refutable.
///
/// In an if-let, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of the
/// desugaring to if-let. Only let-else supports the type annotation at present.
/// In an `if let`, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of
/// the desugaring to if-let. Only let-else supports the type annotation at present.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Let<'hir> {
pub span: Span,
@ -1616,7 +1616,7 @@ impl Expr<'_> {
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
match self.kind {
ExprKind::Path(QPath::Resolved(_, ref path)) => {
matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static(_), _) | Res::Err)
matches!(path.res, Res::Local(..) | Res::Def(DefKind::Static { .. }, _) | Res::Err)
}
// Type ascription inherits its place expression kind from its

View file

@ -627,7 +627,7 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) ->
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result {
try_visit!(visitor.visit_id(statement.hir_id));
match statement.kind {
StmtKind::Local(ref local) => visitor.visit_local(local),
StmtKind::Let(ref local) => visitor.visit_local(local),
StmtKind::Item(item) => visitor.visit_nested_item(item),
StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
visitor.visit_expr(expression)

View file

@ -107,7 +107,7 @@ impl Target {
match item.kind {
ItemKind::ExternCrate(..) => Target::ExternCrate,
ItemKind::Use(..) => Target::Use,
ItemKind::Static(..) => Target::Static,
ItemKind::Static { .. } => Target::Static,
ItemKind::Const(..) => Target::Const,
ItemKind::Fn(..) => Target::Fn,
ItemKind::Macro(..) => Target::MacroDef,
@ -130,7 +130,7 @@ impl Target {
match def_kind {
DefKind::ExternCrate => Target::ExternCrate,
DefKind::Use => Target::Use,
DefKind::Static(..) => Target::Static,
DefKind::Static { .. } => Target::Static,
DefKind::Const => Target::Const,
DefKind::Fn => Target::Fn,
DefKind::Macro(..) => Target::MacroDef,

View file

@ -1934,7 +1934,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
// Case 3. Reference to a top-level value.
DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static(_) => {
DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } => {
path_segs.push(PathSeg(def_id, last));
}

View file

@ -226,7 +226,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
Ok(l) => l,
// Foreign statics that overflow their allowed size should emit an error
Err(LayoutError::SizeOverflow(_))
if matches!(tcx.def_kind(def_id), DefKind::Static(_)
if matches!(tcx.def_kind(def_id), DefKind::Static{ .. }
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
{
tcx.dcx().emit_err(errors::TooLargeStatic { span });
@ -381,11 +381,17 @@ fn check_opaque_meets_bounds<'tcx>(
match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
Ok(()) => {}
Err(ty_err) => {
// Some types may be left "stranded" if they can't be reached
// from an astconv'd bound but they're mentioned in the HIR. This
// will happen, e.g., when a nested opaque is inside of a non-
// existent associated type, like `impl Trait<Missing = impl Trait>`.
// See <tests/ui/impl-trait/stranded-opaque.rs>.
let ty_err = ty_err.to_string(tcx);
tcx.dcx().span_bug(
let guar = tcx.dcx().span_delayed_bug(
span,
format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
);
return Err(guar);
}
}
@ -505,7 +511,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let _indenter = indenter();
match tcx.def_kind(def_id) {
DefKind::Static(..) => {
DefKind::Static { .. } => {
tcx.ensure().typeck(def_id);
maybe_check_static_with_link_section(tcx, def_id);
check_static_inhabited(tcx, def_id);

View file

@ -27,7 +27,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
/// Check for shared or mutable references of `static mut` inside statement
pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
if let hir::StmtKind::Local(loc) = stmt.kind
if let hir::StmtKind::Let(loc) = stmt.kind
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
&& matches!(ba.0, rustc_ast::ByRef::Yes)
&& let Some(init) = loc.init
@ -48,8 +48,7 @@ fn is_path_static_mut(expr: hir::Expr<'_>) -> Option<String> {
if let hir::ExprKind::Path(qpath) = expr.kind
&& let hir::QPath::Resolved(_, path) = qpath
&& let hir::def::Res::Def(def_kind, _) = path.res
&& let hir::def::DefKind::Static(mt) = def_kind
&& matches!(mt, Mutability::Mut)
&& let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
{
return Some(qpath_to_string(&qpath));
}

View file

@ -123,7 +123,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
for (i, statement) in blk.stmts.iter().enumerate() {
match statement.kind {
hir::StmtKind::Local(hir::Local { els: Some(els), .. }) => {
hir::StmtKind::Let(hir::Local { els: Some(els), .. }) => {
// Let-else has a special lexical structure for variables.
// First we take a checkpoint of the current scope context here.
let mut prev_cx = visitor.cx;
@ -146,7 +146,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
// From now on, we continue normally.
visitor.cx = prev_cx;
}
hir::StmtKind::Local(..) => {
hir::StmtKind::Let(..) => {
// Each declaration introduces a subscope for bindings
// introduced by the declaration; this subscope covers a
// suffix of the block. Each subscope in a block has the

View file

@ -5,20 +5,22 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::{sym, DUMMY_SP};
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
let type_of = tcx.type_of(id.owner_id).instantiate_identity();
tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
res = Err(tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of }));
}
}
}
res
}
/// Checks "defining uses" of opaque `impl Trait` in associated types.

View file

@ -98,6 +98,7 @@ mod outlives;
pub mod structured_errors;
mod variance;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::middle;
use rustc_middle::query::Providers;
@ -155,13 +156,11 @@ pub fn provide(providers: &mut Providers) {
hir_wf_check::provide(providers);
}
pub fn check_crate(tcx: TyCtxt<'_>) {
pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let _prof_timer = tcx.sess.timer("type_check_crate");
if tcx.features().rustc_attrs {
tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx));
tcx.sess.time("variance_testing", || variance::test::test_variance(tcx));
collect::test_opaque_hidden_types(tcx);
tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?;
}
tcx.sess.time("coherence_checking", || {
@ -177,12 +176,20 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _ = tcx.ensure().crate_inherent_impls_overlap_check(());
});
if tcx.features().rustc_attrs {
tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?;
}
if tcx.features().rustc_attrs {
collect::test_opaque_hidden_types(tcx)?;
}
// Make sure we evaluate all static and (non-associated) const items, even if unused.
// If any of these fail to evaluate, we do not want this crate to pass compilation.
tcx.hir().par_body_owners(|item_def_id| {
let def_kind = tcx.def_kind(item_def_id);
match def_kind {
DefKind::Static(_) => tcx.ensure().eval_static_initializer(item_def_id),
DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
DefKind::Const => tcx.ensure().const_eval_poly(item_def_id.into()),
_ => (),
}
@ -191,6 +198,21 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
// Freeze definitions as we don't add new ones at this point. This improves performance by
// allowing lock-free access to them.
tcx.untracked().definitions.freeze();
// FIXME: Remove this when we implement creating `DefId`s
// for anon constants during their parents' typeck.
// Typeck all body owners in parallel will produce queries
// cycle errors because it may typeck on anon constants directly.
tcx.hir().par_body_owners(|item_def_id| {
let def_kind = tcx.def_kind(item_def_id);
if !matches!(def_kind, DefKind::AnonConst) {
tcx.ensure().typeck(item_def_id);
}
});
tcx.ensure().check_unused_traits(());
Ok(())
}
/// A quasi-deprecated helper used in rustdoc and clippy to get

View file

@ -1,7 +1,8 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::{symbol::sym, ErrorGuaranteed};
pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
pub fn test_inferred_outlives(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
for id in tcx.hir().items() {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
@ -22,7 +23,8 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
for p in pred {
err.note(p);
}
err.emit();
res = Err(err.emit());
}
}
res
}

View file

@ -2,19 +2,21 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
use rustc_span::ErrorGuaranteed;
use crate::errors;
pub fn test_variance(tcx: TyCtxt<'_>) {
pub fn test_variance(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
let mut res = Ok(());
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
let variances_of = tcx.variances_of(id.owner_id);
tcx.dcx().emit_err(errors::VariancesOf {
res = Err(tcx.dcx().emit_err(errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances_of: format!("{variances_of:?}"),
});
}));
}
}
}
@ -25,10 +27,11 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
if tcx.has_attr(id.owner_id, sym::rustc_variance) {
let variances_of = tcx.variances_of(id.owner_id);
tcx.dcx().emit_err(errors::VariancesOf {
res = Err(tcx.dcx().emit_err(errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances_of: format!("{variances_of:?}"),
});
}));
}
}
res
}

View file

@ -863,7 +863,7 @@ impl<'a> State<'a> {
fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
self.maybe_print_comment(st.span.lo());
match st.kind {
hir::StmtKind::Local(loc) => {
hir::StmtKind::Let(loc) => {
self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc));
}
hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
@ -2306,7 +2306,7 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
/// seen the semicolon, and thus don't need another.
fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
match *stmt {
hir::StmtKind::Local(_) => true,
hir::StmtKind::Let(_) => true,
hir::StmtKind::Item(_) => false,
hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
hir::StmtKind::Semi(..) => false,

View file

@ -699,7 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::Path {
res:
hir::def::Res::Def(
hir::def::DefKind::Static(_) | hir::def::DefKind::Const,
hir::def::DefKind::Static { .. } | hir::def::DefKind::Const,
def_id,
),
..

View file

@ -371,11 +371,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
match stmt.kind {
hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => {
hir::StmtKind::Let(hir::Local { pat, init: Some(expr), els, .. }) => {
self.walk_local(expr, pat, *els, |_| {})
}
hir::StmtKind::Local(_) => {}
hir::StmtKind::Let(_) => {}
hir::StmtKind::Item(_) => {
// We don't visit nested items in this visitor,

View file

@ -1593,7 +1593,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Don't do all the complex logic below for `DeclItem`.
match stmt.kind {
hir::StmtKind::Item(..) => return,
hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
hir::StmtKind::Let(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
}
self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
@ -1602,7 +1602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let old_diverges = self.diverges.replace(Diverges::Maybe);
match stmt.kind {
hir::StmtKind::Local(l) => {
hir::StmtKind::Let(l) => {
self.check_decl_local(l);
}
// Ignore for now.
@ -1765,7 +1765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
[
hir::Stmt {
kind:
hir::StmtKind::Local(hir::Local {
hir::StmtKind::Let(hir::Local {
source:
hir::LocalSource::AssignDesugar(_),
..

View file

@ -1599,7 +1599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_local_statement(&self, id: hir::HirId) -> bool {
let node = self.tcx.hir_node(id);
matches!(node, Node::Stmt(Stmt { kind: StmtKind::Local(..), .. }))
matches!(node, Node::Stmt(Stmt { kind: StmtKind::Let(..), .. }))
}
/// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,

View file

@ -398,7 +398,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
)
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
Res::Def(DefKind::Static(_), _) => {
Res::Def(DefKind::Static { .. }, _) => {
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
}

View file

@ -2221,7 +2221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
impl<'v> Visitor<'v> for LetVisitor {
type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Local(&hir::Local { pat, init, .. }) = ex.kind
if let hir::StmtKind::Let(&hir::Local { pat, init, .. }) = ex.kind
&& let Binding(_, _, ident, ..) = pat.kind
&& ident.name == self.ident_name
{

View file

@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bug!();
};
for stmt in block.stmts {
let hir::StmtKind::Local(hir::Local {
let hir::StmtKind::Let(hir::Local {
init: Some(init),
source: hir::LocalSource::AsyncFn,
pat,

View file

@ -2139,7 +2139,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// the same span as the error and the type is specified.
if let hir::Stmt {
kind:
hir::StmtKind::Local(hir::Local {
hir::StmtKind::Let(hir::Local {
init: Some(hir::Expr { span: init_span, .. }),
ty: Some(array_ty),
..

View file

@ -372,7 +372,7 @@ impl<T> Trait<T> for X {
&& matches!(
tcx.def_kind(body_owner_def_id),
DefKind::Fn
| DefKind::Static(_)
| DefKind::Static { .. }
| DefKind::Const
| DefKind::AssocFn
| DefKind::AssocConst

View file

@ -585,7 +585,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Local(hir::Local {
if let hir::StmtKind::Let(hir::Local {
span,
pat: hir::Pat { .. },
ty: None,
@ -824,7 +824,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let hir = self.tcx.hir();
for stmt in blk.stmts.iter().rev() {
let hir::StmtKind::Local(local) = &stmt.kind else {
let hir::StmtKind::Let(local) = &stmt.kind else {
continue;
};
local.pat.walk(&mut find_compatible_candidates);

View file

@ -734,22 +734,19 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
});
// passes are timed inside typeck
rustc_hir_analysis::check_crate(tcx);
rustc_hir_analysis::check_crate(tcx)?;
sess.time("typeck_and_mir_analyses", || {
sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| {
let def_kind = tcx.def_kind(def_id);
// FIXME: Remove this when we implement creating `DefId`s
// for anon constants during their parents' typeck.
// Typeck all body owners in parallel will produce queries
// cycle errors because it may typeck on anon constants directly.
if !matches!(def_kind, rustc_hir::def::DefKind::AnonConst) {
tcx.ensure().typeck(def_id);
}
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure().check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id);
tcx.ensure().mir_borrowck(def_id)
});
});
sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
}
@ -764,15 +761,15 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id()));
}
if tcx.is_coroutine(def_id.to_def_id()) {
tcx.ensure().mir_coroutine_witnesses(def_id);
tcx.ensure().check_coroutine_obligations(def_id);
}
})
}
});
tcx.ensure().check_unused_traits(());
tcx.hir().par_body_owners(|def_id| {
if tcx.is_coroutine(def_id.to_def_id()) {
tcx.ensure().mir_coroutine_witnesses(def_id);
tcx.ensure().check_coroutine_obligations(def_id);
}
});
sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));

View file

@ -321,6 +321,8 @@ impl Compiler {
}
self.sess.time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph));
gcx.enter(rustc_query_impl::query_key_hash_verify_all);
}
// The timer's lifetime spans the dropping of `queries`, which contains

View file

@ -4,11 +4,12 @@ use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::{
build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg,
CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry,
ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage,
InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig,
OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius,
ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
CollapseMacroDebuginfo, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType,
ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input,
InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli,
NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion,
WasiExecModel,
};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
@ -750,6 +751,7 @@ fn test_unstable_options_tracking_hash() {
);
tracked!(codegen_backend, Some("abc".to_string()));
tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes);
tracked!(coverage_options, CoverageOptions { branch: true });
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);

View file

@ -989,7 +989,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
impl EarlyLintPass for UnusedDocComment {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
let kind = match stmt.kind {
ast::StmtKind::Local(..) => "statements",
ast::StmtKind::Let(..) => "statements",
// Disabled pending discussion in #78306
ast::StmtKind::Item(..) => return,
// expressions will be reported by `check_expr`.

View file

@ -914,7 +914,7 @@ trait UnusedDelimLint {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
match s.kind {
StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
if let Some((init, els)) = local.kind.init_else_opt() {
let ctx = match els {
None => UnusedDelimsCtx::AssignedValue,
@ -1189,7 +1189,7 @@ impl EarlyLintPass for UnusedParens {
}
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
if let StmtKind::Local(ref local) = s.kind {
if let StmtKind::Let(ref local) = s.kind {
self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false));
}

View file

@ -30,6 +30,7 @@ declare_lint_pass! {
CENUM_IMPL_DROP_CAST,
COHERENCE_LEAK_CHECK,
CONFLICTING_REPR_HINTS,
CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
CONST_EVALUATABLE_UNCHECKED,
CONST_ITEM_MUTATION,
DEAD_CODE,
@ -2796,6 +2797,51 @@ declare_lint! {
@feature_gate = sym::strict_provenance;
}
declare_lint! {
/// The `const_eval_mutable_ptr_in_final_value` lint detects if a mutable pointer
/// has leaked into the final value of a const expression.
///
/// ### Example
///
/// ```rust
/// pub enum JsValue {
/// Undefined,
/// Object(std::cell::Cell<bool>),
/// }
///
/// impl ::std::ops::Drop for JsValue {
/// fn drop(&mut self) {}
/// }
///
/// const UNDEFINED: &JsValue = &JsValue::Undefined;
///
/// fn main() {
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In the 1.77 release, the const evaluation machinery adopted some
/// stricter rules to reject expressions with values that could
/// end up holding mutable references to state stored in static memory
/// (which is inherently immutable).
///
/// This is a [future-incompatible] lint to ease the transition to an error.
/// See [issue #122153] for more details.
///
/// [issue #122153]: https://github.com/rust-lang/rust/issues/122153
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
Warn,
"detects a mutable pointer that has leaked into final value of a const expression",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #122153 <https://github.com/rust-lang/rust/issues/122153>",
};
}
declare_lint! {
/// The `const_evaluatable_unchecked` lint detects a generic constant used
/// in a type.

View file

@ -10,6 +10,7 @@
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Value.h"
#include "llvm/Remarks/RemarkStreamer.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Remarks/RemarkFormat.h"
@ -1111,11 +1112,16 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
LLVMBasicBlockRef InsertAtEnd) {
return wrap(Builder->insertDeclare(
auto Result = Builder->insertDeclare(
unwrap(V), unwrap<DILocalVariable>(VarInfo),
Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
DebugLoc(cast<MDNode>(unwrap(DL))),
unwrap(InsertAtEnd)));
unwrap(InsertAtEnd));
#if LLVM_VERSION_GE(19, 0)
return wrap(Result.get<llvm::Instruction *>());
#else
return wrap(Result);
#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(
@ -1223,14 +1229,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V,
}
}
// LLVMArrayType function does not support 64-bit ElementCount
// FIXME: replace with LLVMArrayType2 when bumped minimal version to llvm-17
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
uint64_t ElementCount) {
return wrap(ArrayType::get(unwrap(ElementTy), ElementCount));
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef)
extern "C" void LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef Str) {
@ -2114,3 +2112,36 @@ extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() {
extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() {
return llvm::compression::zstd::isAvailable();
}
// Operations on composite constants.
// These are clones of LLVM api functions that will become available in future releases.
// They can be removed once Rust's minimum supported LLVM version supports them.
// See https://github.com/rust-lang/rust/issues/121868
// See https://llvm.org/doxygen/group__LLVMCCoreValueConstantComposite.html
// FIXME: Remove when Rust's minimum supported LLVM version reaches 19.
// https://github.com/llvm/llvm-project/commit/e1405e4f71c899420ebf8262d5e9745598419df8
#if LLVM_VERSION_LT(19, 0)
extern "C" LLVMValueRef LLVMConstStringInContext2(LLVMContextRef C,
const char *Str,
size_t Length,
bool DontNullTerminate) {
return wrap(ConstantDataArray::getString(*unwrap(C), StringRef(Str, Length), !DontNullTerminate));
}
#endif
// FIXME: Remove when Rust's minimum supported LLVM version reaches 17.
// https://github.com/llvm/llvm-project/commit/35276f16e5a2cae0dfb49c0fbf874d4d2f177acc
#if LLVM_VERSION_LT(17, 0)
extern "C" LLVMValueRef LLVMConstArray2(LLVMTypeRef ElementTy,
LLVMValueRef *ConstantVals,
uint64_t Length) {
ArrayRef<Constant *> V(unwrap<Constant>(ConstantVals, Length), Length);
return wrap(ConstantArray::get(ArrayType::get(unwrap(ElementTy), Length), V));
}
extern "C" LLVMTypeRef LLVMArrayType2(LLVMTypeRef ElementTy,
uint64_t ElementCount) {
return wrap(ArrayType::get(unwrap(ElementTy), ElementCount));
}
#endif

View file

@ -863,7 +863,7 @@ fn should_encode_span(def_kind: DefKind) -> bool {
| DefKind::LifetimeParam
| DefKind::Fn
| DefKind::Const
| DefKind::Static(_)
| DefKind::Static { .. }
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst
@ -894,7 +894,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
| DefKind::AssocTy
| DefKind::Fn
| DefKind::Const
| DefKind::Static(_)
| DefKind::Static { nested: false, .. }
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::Macro(_)
@ -915,6 +915,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
| DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::LifetimeParam
| DefKind::Static { nested: true, .. }
| DefKind::GlobalAsm => false,
}
}
@ -936,7 +937,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool {
| DefKind::Fn
| DefKind::Const
| DefKind::ConstParam
| DefKind::Static(_)
| DefKind::Static { .. }
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst
@ -968,7 +969,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
| DefKind::AssocTy
| DefKind::Fn
| DefKind::Const
| DefKind::Static(..)
| DefKind::Static { nested: false, .. }
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst
@ -981,6 +982,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
| DefKind::LifetimeParam
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Static { nested: true, .. }
| DefKind::OpaqueTy
| DefKind::GlobalAsm
| DefKind::Impl { .. }
@ -1001,7 +1003,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
| DefKind::AssocConst
| DefKind::TyParam
| DefKind::ConstParam
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::Const
| DefKind::Fn
| DefKind::ForeignMod
@ -1099,7 +1101,7 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def
| DefKind::AssocConst
| DefKind::TyParam
| DefKind::ConstParam
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::Const
| DefKind::ForeignMod
| DefKind::Impl { .. }
@ -1131,7 +1133,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
| DefKind::AssocTy
| DefKind::Fn
| DefKind::Const
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst
@ -1163,7 +1165,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
| DefKind::Field
| DefKind::Fn
| DefKind::Const
| DefKind::Static(..)
| DefKind::Static { nested: false, .. }
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::Impl { .. }
@ -1205,6 +1207,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
| DefKind::Mod
| DefKind::ForeignMod
| DefKind::Macro(..)
| DefKind::Static { nested: true, .. }
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::GlobalAsm
@ -1222,7 +1225,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
| DefKind::Variant
| DefKind::Field
| DefKind::Const
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::Ctor(..)
| DefKind::TyAlias
| DefKind::OpaqueTy
@ -1263,7 +1266,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
| DefKind::Const
| DefKind::AssocConst
| DefKind::AnonConst
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::Impl { of_trait: false }
@ -1295,7 +1298,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
| DefKind::Ctor(..)
| DefKind::Field
| DefKind::Fn
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::TyAlias
| DefKind::OpaqueTy
| DefKind::ForeignTy
@ -1469,7 +1472,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
.coroutine_for_closure
.set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into());
}
if let DefKind::Static(_) = def_kind {
if let DefKind::Static { .. } = def_kind {
if !self.tcx.is_foreign_item(def_id) {
let data = self.tcx.eval_static_initializer(def_id).unwrap();
record!(self.tables.eval_static_initializer[def_id] <- data);

View file

@ -155,8 +155,10 @@ fixed_size_enum! {
( Impl { of_trait: false } )
( Impl { of_trait: true } )
( Closure )
( Static(ast::Mutability::Not) )
( Static(ast::Mutability::Mut) )
( Static { mutability: ast::Mutability::Not, nested: false } )
( Static { mutability: ast::Mutability::Mut, nested: false } )
( Static { mutability: ast::Mutability::Not, nested: true } )
( Static { mutability: ast::Mutability::Mut, nested: true } )
( Ctor(CtorOf::Struct, CtorKind::Fn) )
( Ctor(CtorOf::Struct, CtorKind::Const) )
( Ctor(CtorOf::Variant, CtorKind::Fn) )

View file

@ -343,7 +343,7 @@ impl<'hir> Map<'hir> {
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
DefKind::Closure => BodyOwnerKind::Closure,
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability),
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
}
}
@ -359,7 +359,7 @@ impl<'hir> Map<'hir> {
let def_id = def_id.into();
let ccx = match self.body_owner_kind(def_id) {
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
BodyOwnerKind::Static(mutability) => ConstContext::Static(mutability),
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id) => return None,
BodyOwnerKind::Fn | BodyOwnerKind::Closure if self.tcx.is_const_fn_raw(def_id) => {
@ -655,7 +655,7 @@ impl<'hir> Map<'hir> {
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
| Node::Stmt(Stmt { kind: StmtKind::Let(_), .. }) => break,
Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
return Some(expr);
}

View file

@ -130,7 +130,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{HashMapExt, Lock};
use rustc_data_structures::tiny_list::TinyList;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::HashStable;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_serialize::{Decodable, Encodable};
@ -627,6 +627,16 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Freezes an `AllocId` created with `reserve` by pointing it at a static item. Trying to
/// call this function twice, even with the same `DefId` will ICE the compiler.
pub fn set_nested_alloc_id_static(self, id: AllocId, def_id: LocalDefId) {
if let Some(old) =
self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Static(def_id.to_def_id()))
{
bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
}
}
/// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
/// twice for the same `(AllocId, Allocation)` pair.
fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {

View file

@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::visit::TypeVisitableExt;
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
use crate::ty::{AdtDef, Instance, InstanceDef, UserTypeAnnotationIndex};
use crate::ty::{GenericArg, GenericArgsRef};
use rustc_data_structures::captures::Captures;
@ -27,6 +27,8 @@ pub use rustc_ast::Mutability;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_index::bit_set::BitSet;
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_serialize::{Decodable, Encodable};
use rustc_span::symbol::Symbol;
@ -640,6 +642,129 @@ impl<'tcx> Body<'tcx> {
self.injection_phase.is_some()
}
/// Finds which basic blocks are actually reachable for a specific
/// monomorphization of this body.
///
/// This is allowed to have false positives; just because this says a block
/// is reachable doesn't mean that's necessarily true. It's thus always
/// legal for this to return a filled set.
///
/// Regardless, the [`BitSet::domain_size`] of the returned set will always
/// exactly match the number of blocks in the body so that `contains`
/// checks can be done without worrying about panicking.
///
/// This is mostly useful because it lets us skip lowering the `false` side
/// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`.
pub fn reachable_blocks_in_mono(
&self,
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> BitSet<BasicBlock> {
let mut set = BitSet::new_empty(self.basic_blocks.len());
self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK);
set
}
fn reachable_blocks_in_mono_from(
&self,
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
set: &mut BitSet<BasicBlock>,
bb: BasicBlock,
) {
if !set.insert(bb) {
return;
}
let data = &self.basic_blocks[bb];
if let Some((bits, targets)) = Self::try_const_mono_switchint(tcx, instance, data) {
let target = targets.target_for_value(bits);
ensure_sufficient_stack(|| {
self.reachable_blocks_in_mono_from(tcx, instance, set, target)
});
return;
}
for target in data.terminator().successors() {
ensure_sufficient_stack(|| {
self.reachable_blocks_in_mono_from(tcx, instance, set, target)
});
}
}
/// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the
/// dimscriminant in monomorphization, we return the discriminant bits and the
/// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator.
fn try_const_mono_switchint<'a>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
block: &'a BasicBlockData<'tcx>,
) -> Option<(u128, &'a SwitchTargets)> {
// There are two places here we need to evaluate a constant.
let eval_mono_const = |constant: &ConstOperand<'tcx>| {
let env = ty::ParamEnv::reveal_all();
let mono_literal = instance.instantiate_mir_and_normalize_erasing_regions(
tcx,
env,
crate::ty::EarlyBinder::bind(constant.const_),
);
let Some(bits) = mono_literal.try_eval_bits(tcx, env) else {
bug!("Couldn't evaluate constant {:?} in mono {:?}", constant, instance);
};
bits
};
let TerminatorKind::SwitchInt { discr, targets } = &block.terminator().kind else {
return None;
};
// If this is a SwitchInt(const _), then we can just evaluate the constant and return.
let discr = match discr {
Operand::Constant(constant) => {
let bits = eval_mono_const(constant);
return Some((bits, targets));
}
Operand::Move(place) | Operand::Copy(place) => place,
};
// MIR for `if false` actually looks like this:
// _1 = const _
// SwitchInt(_1)
//
// And MIR for if intrinsics::debug_assertions() looks like this:
// _1 = cfg!(debug_assertions)
// SwitchInt(_1)
//
// So we're going to try to recognize this pattern.
//
// If we have a SwitchInt on a non-const place, we find the most recent statement that
// isn't a storage marker. If that statement is an assignment of a const to our
// discriminant place, we evaluate and return the const, as if we've const-propagated it
// into the SwitchInt.
let last_stmt = block.statements.iter().rev().find(|stmt| {
!matches!(stmt.kind, StatementKind::StorageDead(_) | StatementKind::StorageLive(_))
})?;
let (place, rvalue) = last_stmt.kind.as_assign()?;
if discr != place {
return None;
}
match rvalue {
Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {
Some((tcx.sess.opts.debug_assertions as u128, targets))
}
Rvalue::Use(Operand::Constant(constant)) => {
let bits = eval_mono_const(constant);
Some((bits, targets))
}
_ => None,
}
}
/// For a `Location` in this scope, determine what the "caller location" at that point is. This
/// is interesting because of inlining: the `#[track_caller]` attribute of inlined functions
/// must be honored. Falls back to the `tracked_caller` value for `#[track_caller]` functions,

View file

@ -498,8 +498,12 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
match (kind, body.source.promoted) {
(_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts
(DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
(DefKind::Static(hir::Mutability::Not), _) => write!(w, "static ")?,
(DefKind::Static(hir::Mutability::Mut), _) => write!(w, "static mut ")?,
(DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => {
write!(w, "static ")?
}
(DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => {
write!(w, "static mut ")?
}
(_, _) if is_function => write!(w, "fn ")?,
(DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
_ => bug!("Unexpected def kind {:?}", kind),

View file

@ -1,5 +1,3 @@
use rustc_index::bit_set::BitSet;
use super::*;
/// Preorder traversal of a graph.

View file

@ -1062,6 +1062,7 @@ rustc_queries! {
}
cache_on_disk_if { key.is_local() }
separate_provide_extern
feedable
}
/// Evaluates const items or anonymous constants
@ -1220,6 +1221,7 @@ rustc_queries! {
arena_cache
cache_on_disk_if { def_id.is_local() }
separate_provide_extern
feedable
}
query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> {

View file

@ -1708,7 +1708,7 @@ impl<'tcx> TyCtxt<'tcx> {
debug!("returned from def_kind: {:?}", def_kind);
match def_kind {
DefKind::Const
| DefKind::Static(..)
| DefKind::Static { .. }
| DefKind::AssocConst
| DefKind::Ctor(..)
| DefKind::AnonConst

View file

@ -359,7 +359,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
| DefKind::TyAlias
| DefKind::Fn
| DefKind::Const
| DefKind::Static(_) = kind
| DefKind::Static { .. } = kind
{
} else {
// If not covered above, like for example items out of `impl` blocks, fallback.

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