mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 08:36:03 +00:00
Merge from rustc
This commit is contained in:
commit
debf88ae1a
@ -661,11 +661,11 @@ impl TokenStream {
|
|||||||
if attr_style == AttrStyle::Inner {
|
if attr_style == AttrStyle::Inner {
|
||||||
vec![
|
vec![
|
||||||
TokenTree::token_joint(token::Pound, span),
|
TokenTree::token_joint(token::Pound, span),
|
||||||
TokenTree::token_alone(token::Not, span),
|
TokenTree::token_joint_hidden(token::Not, span),
|
||||||
body,
|
body,
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![TokenTree::token_alone(token::Pound, span), body]
|
vec![TokenTree::token_joint_hidden(token::Pound, span), body]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,22 +681,40 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The easiest way to implement token stream pretty printing would be to
|
||||||
|
// print each token followed by a single space. But that would produce ugly
|
||||||
|
// output, so we go to some effort to do better.
|
||||||
|
//
|
||||||
|
// First, we track whether each token that appears in source code is
|
||||||
|
// followed by a space, with `Spacing`, and reproduce that in the output.
|
||||||
|
// This works well in a lot of cases. E.g. `stringify!(x + y)` produces
|
||||||
|
// "x + y" and `stringify!(x+y)` produces "x+y".
|
||||||
|
//
|
||||||
|
// But this doesn't work for code produced by proc macros (which have no
|
||||||
|
// original source text representation) nor for code produced by decl
|
||||||
|
// macros (which are tricky because the whitespace after tokens appearing
|
||||||
|
// in macro rules isn't always what you want in the produced output). For
|
||||||
|
// these we mostly use `Spacing::Alone`, which is the conservative choice.
|
||||||
|
//
|
||||||
|
// So we have a backup mechanism for when `Spacing::Alone` occurs between a
|
||||||
|
// pair of tokens: we check if that pair of tokens can obviously go
|
||||||
|
// together without a space between them. E.g. token `x` followed by token
|
||||||
|
// `,` is better printed as `x,` than `x ,`. (Even if the original source
|
||||||
|
// code was `x ,`.)
|
||||||
|
//
|
||||||
|
// Finally, we must be careful about changing the output. Token pretty
|
||||||
|
// printing is used by `stringify!` and `impl Display for
|
||||||
|
// proc_macro::TokenStream`, and some programs rely on the output having a
|
||||||
|
// particular form, even though they shouldn't. In particular, some proc
|
||||||
|
// macros do `format!({stream})` on a token stream and then "parse" the
|
||||||
|
// output with simple string matching that can't handle whitespace changes.
|
||||||
|
// E.g. we have seen cases where a proc macro can handle `a :: b` but not
|
||||||
|
// `a::b`. See #117433 for some examples.
|
||||||
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||||
let mut iter = tts.trees().peekable();
|
let mut iter = tts.trees().peekable();
|
||||||
while let Some(tt) = iter.next() {
|
while let Some(tt) = iter.next() {
|
||||||
let spacing = self.print_tt(tt, convert_dollar_crate);
|
let spacing = self.print_tt(tt, convert_dollar_crate);
|
||||||
if let Some(next) = iter.peek() {
|
if let Some(next) = iter.peek() {
|
||||||
// Should we print a space after `tt`? There are two guiding
|
|
||||||
// factors.
|
|
||||||
// - `spacing` is the more important and accurate one. Most
|
|
||||||
// tokens have good spacing information, and
|
|
||||||
// `Joint`/`JointHidden` get used a lot.
|
|
||||||
// - `space_between` is the backup. Code produced by proc
|
|
||||||
// macros has worse spacing information, with no
|
|
||||||
// `JointHidden` usage and too much `Alone` usage, which
|
|
||||||
// would result in over-spaced output such as
|
|
||||||
// `( x () , y . z )`. `space_between` avoids some of the
|
|
||||||
// excess whitespace.
|
|
||||||
if spacing == Spacing::Alone && space_between(tt, next) {
|
if spacing == Spacing::Alone && space_between(tt, next) {
|
||||||
self.space();
|
self.space();
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||||||
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
|
||||||
let escaped_expr_str = escape_to_fmt(expr_str);
|
let escaped_expr_str = escape_to_fmt(expr_str);
|
||||||
let initial = [
|
let initial = [
|
||||||
TokenTree::token_joint_hidden(
|
TokenTree::token_joint(
|
||||||
token::Literal(token::Lit {
|
token::Literal(token::Lit {
|
||||||
kind: token::LitKind::Str,
|
kind: token::LitKind::Str,
|
||||||
symbol: Symbol::intern(&if self.fmt_string.is_empty() {
|
symbol: Symbol::intern(&if self.fmt_string.is_empty() {
|
||||||
@ -172,7 +172,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||||||
];
|
];
|
||||||
let captures = self.capture_decls.iter().flat_map(|cap| {
|
let captures = self.capture_decls.iter().flat_map(|cap| {
|
||||||
[
|
[
|
||||||
TokenTree::token_joint_hidden(
|
TokenTree::token_joint(
|
||||||
token::Ident(cap.ident.name, IdentIsRaw::No),
|
token::Ident(cap.ident.name, IdentIsRaw::No),
|
||||||
cap.ident.span,
|
cap.ident.span,
|
||||||
),
|
),
|
||||||
|
@ -3,7 +3,7 @@ use crate::deriving::generic::*;
|
|||||||
use crate::errors;
|
use crate::errors;
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::visit_opt;
|
||||||
use rustc_ast::{attr, EnumDef, VariantData};
|
use rustc_ast::{attr, EnumDef, VariantData};
|
||||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
@ -224,7 +224,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
|
|||||||
self.visit_ident(v.ident);
|
self.visit_ident(v.ident);
|
||||||
self.visit_vis(&v.vis);
|
self.visit_vis(&v.vis);
|
||||||
self.visit_variant_data(&v.data);
|
self.visit_variant_data(&v.data);
|
||||||
walk_list!(self, visit_anon_const, &v.disr_expr);
|
visit_opt!(self, visit_anon_const, &v.disr_expr);
|
||||||
for attr in &v.attrs {
|
for attr in &v.attrs {
|
||||||
rustc_ast::visit::walk_attribute(self, attr);
|
rustc_ast::visit::walk_attribute(self, attr);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ fn produce_final_output_artifacts(
|
|||||||
// to get rid of it.
|
// to get rid of it.
|
||||||
for output_type in crate_output.outputs.keys() {
|
for output_type in crate_output.outputs.keys() {
|
||||||
match *output_type {
|
match *output_type {
|
||||||
OutputType::Bitcode => {
|
OutputType::Bitcode | OutputType::ThinLinkBitcode => {
|
||||||
// Cranelift doesn't have bitcode
|
// Cranelift doesn't have bitcode
|
||||||
// user_wants_bitcode = true;
|
// user_wants_bitcode = true;
|
||||||
// // Copy to .bc, but always keep the .0.bc. There is a later
|
// // Copy to .bc, but always keep the .0.bc. There is a later
|
||||||
|
@ -335,6 +335,10 @@ impl ThinBufferMethods for ThinBuffer {
|
|||||||
fn data(&self) -> &[u8] {
|
fn data(&self) -> &[u8] {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn thin_link_data(&self) -> &[u8] {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GccContext {
|
pub struct GccContext {
|
||||||
@ -414,7 +418,7 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||||||
back::write::codegen(cgcx, dcx, module, config)
|
back::write::codegen(cgcx, dcx, module, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
|
fn prepare_thin(_module: ModuleCodegen<Self::Module>, _emit_summary: bool) -> (String, Self::ThinBuffer) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use rustc_middle::{bug, span_bug, ty::Instance};
|
|||||||
use rustc_span::{Pos, Span};
|
use rustc_span::{Pos, Span};
|
||||||
use rustc_target::abi::*;
|
use rustc_target::abi::*;
|
||||||
use rustc_target::asm::*;
|
use rustc_target::asm::*;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use libc::{c_char, c_uint};
|
use libc::{c_char, c_uint};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -18,6 +18,7 @@ use rustc_codegen_ssa::back::archive::{
|
|||||||
get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
|
get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
|
||||||
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
|
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
|
||||||
};
|
};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use rustc_session::cstore::DllImport;
|
use rustc_session::cstore::DllImport;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
@ -20,6 +20,7 @@ use rustc_middle::bug;
|
|||||||
use rustc_middle::dep_graph::WorkProduct;
|
use rustc_middle::dep_graph::WorkProduct;
|
||||||
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
|
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
|
||||||
use rustc_session::config::{self, CrateType, Lto};
|
use rustc_session::config::{self, CrateType, Lto};
|
||||||
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
@ -229,9 +230,12 @@ pub(crate) fn run_thin(
|
|||||||
thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
|
thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
|
pub(crate) fn prepare_thin(
|
||||||
|
module: ModuleCodegen<ModuleLlvm>,
|
||||||
|
emit_summary: bool,
|
||||||
|
) -> (String, ThinBuffer) {
|
||||||
let name = module.name;
|
let name = module.name;
|
||||||
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true);
|
let buffer = ThinBuffer::new(module.module_llvm.llmod(), true, emit_summary);
|
||||||
(name, buffer)
|
(name, buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -671,9 +675,9 @@ unsafe impl Send for ThinBuffer {}
|
|||||||
unsafe impl Sync for ThinBuffer {}
|
unsafe impl Sync for ThinBuffer {}
|
||||||
|
|
||||||
impl ThinBuffer {
|
impl ThinBuffer {
|
||||||
pub fn new(m: &llvm::Module, is_thin: bool) -> ThinBuffer {
|
pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin);
|
let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary);
|
||||||
ThinBuffer(buffer)
|
ThinBuffer(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -687,6 +691,14 @@ impl ThinBufferMethods for ThinBuffer {
|
|||||||
slice::from_raw_parts(ptr, len)
|
slice::from_raw_parts(ptr, len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn thin_link_data(&self) -> &[u8] {
|
||||||
|
unsafe {
|
||||||
|
let ptr = llvm::LLVMRustThinLTOBufferThinLinkDataPtr(self.0) as *const _;
|
||||||
|
let len = llvm::LLVMRustThinLTOBufferThinLinkDataLen(self.0);
|
||||||
|
slice::from_raw_parts(ptr, len)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ThinBuffer {
|
impl Drop for ThinBuffer {
|
||||||
|
@ -35,6 +35,7 @@ use rustc_session::Session;
|
|||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::InnerSpan;
|
use rustc_span::InnerSpan;
|
||||||
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::llvm::diagnostic::OptimizationDiagnosticKind;
|
use crate::llvm::diagnostic::OptimizationDiagnosticKind;
|
||||||
use libc::{c_char, c_int, c_void, size_t};
|
use libc::{c_char, c_int, c_void, size_t};
|
||||||
@ -708,13 +709,15 @@ pub(crate) unsafe fn codegen(
|
|||||||
// asm from LLVM and use `gcc` to create the object file.
|
// asm from LLVM and use `gcc` to create the object file.
|
||||||
|
|
||||||
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
||||||
|
let bc_summary_out =
|
||||||
|
cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name);
|
||||||
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
||||||
|
|
||||||
if config.bitcode_needed() {
|
if config.bitcode_needed() {
|
||||||
let _timer = cgcx
|
let _timer = cgcx
|
||||||
.prof
|
.prof
|
||||||
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
|
.generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name);
|
||||||
let thin = ThinBuffer::new(llmod, config.emit_thin_lto);
|
let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_summary);
|
||||||
let data = thin.data();
|
let data = thin.data();
|
||||||
|
|
||||||
if let Some(bitcode_filename) = bc_out.file_name() {
|
if let Some(bitcode_filename) = bc_out.file_name() {
|
||||||
@ -725,6 +728,25 @@ pub(crate) unsafe fn codegen(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.emit_thin_lto_summary
|
||||||
|
&& let Some(thin_link_bitcode_filename) = bc_summary_out.file_name()
|
||||||
|
{
|
||||||
|
let summary_data = thin.thin_link_data();
|
||||||
|
cgcx.prof.artifact_size(
|
||||||
|
"llvm_bitcode_summary",
|
||||||
|
thin_link_bitcode_filename.to_string_lossy(),
|
||||||
|
summary_data.len() as u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
let _timer = cgcx.prof.generic_activity_with_arg(
|
||||||
|
"LLVM_module_codegen_emit_bitcode_summary",
|
||||||
|
&*module.name,
|
||||||
|
);
|
||||||
|
if let Err(err) = fs::write(&bc_summary_out, summary_data) {
|
||||||
|
dcx.emit_err(WriteBytecode { path: &bc_summary_out, err });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
|
||||||
let _timer = cgcx
|
let _timer = cgcx
|
||||||
.prof
|
.prof
|
||||||
|
@ -30,6 +30,7 @@ use std::borrow::Cow;
|
|||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
// All Builders must have an llfn associated with them
|
// All Builders must have an llfn associated with them
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -12,6 +12,7 @@ use crate::value::Value;
|
|||||||
|
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
|
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
|
||||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Codegens a reference to a fn/method item, monomorphizing and
|
/// Codegens a reference to a fn/method item, monomorphizing and
|
||||||
/// inlining as it goes.
|
/// inlining as it goes.
|
||||||
|
@ -19,6 +19,7 @@ use rustc_target::spec::Target;
|
|||||||
|
|
||||||
use libc::{c_char, c_uint};
|
use libc::{c_char, c_uint};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
|
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
|
||||||
|
@ -25,6 +25,7 @@ use rustc_target::abi::{
|
|||||||
Align, AlignFromBytesError, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
|
Align, AlignFromBytesError, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
|
||||||
};
|
};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
pub fn const_alloc_to_llvm<'ll>(
|
pub fn const_alloc_to_llvm<'ll>(
|
||||||
cx: &CodegenCx<'ll, '_>,
|
cx: &CodegenCx<'ll, '_>,
|
||||||
|
@ -9,6 +9,7 @@ use rustc_middle::mir::coverage::{
|
|||||||
};
|
};
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
/// Holds all of the coverage mapping data associated with a function instance,
|
/// Holds all of the coverage mapping data associated with a function instance,
|
||||||
/// collected during traversal of `Coverage` statements in the function's MIR.
|
/// collected during traversal of `Coverage` statements in the function's MIR.
|
||||||
|
@ -14,6 +14,7 @@ use rustc_middle::mir;
|
|||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_span::def_id::DefIdSet;
|
use rustc_span::def_id::DefIdSet;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Generates and exports the Coverage Map.
|
/// Generates and exports the Coverage Map.
|
||||||
///
|
///
|
||||||
|
@ -17,6 +17,7 @@ use rustc_middle::mir::coverage::CoverageKind;
|
|||||||
use rustc_middle::ty::layout::HasTyCtxt;
|
use rustc_middle::ty::layout::HasTyCtxt;
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ use rustc_symbol_mangling::typeid_for_trait_ref;
|
|||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use rustc_target::spec::DebuginfoKind;
|
use rustc_target::spec::DebuginfoKind;
|
||||||
use smallvec::smallvec;
|
use smallvec::smallvec;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use libc::{c_char, c_longlong, c_uint};
|
use libc::{c_char, c_longlong, c_uint};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -42,6 +42,7 @@ use std::cell::OnceCell;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
mod create_scope_map;
|
mod create_scope_map;
|
||||||
pub mod gdb;
|
pub mod gdb;
|
||||||
|
@ -6,7 +6,7 @@ use super::CodegenUnitDebugContext;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
|
use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::common::CodegenCx;
|
use crate::common::CodegenCx;
|
||||||
use crate::llvm;
|
use crate::llvm;
|
||||||
|
@ -24,6 +24,7 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||||||
use rustc_middle::ty::{Instance, Ty};
|
use rustc_middle::ty::{Instance, Ty};
|
||||||
use rustc_sanitizers::{cfi, kcfi};
|
use rustc_sanitizers::{cfi, kcfi};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Declare a function.
|
/// Declare a function.
|
||||||
///
|
///
|
||||||
|
@ -21,6 +21,7 @@ use rustc_middle::{bug, span_bug};
|
|||||||
use rustc_span::{sym, Span, Symbol};
|
use rustc_span::{sym, Span, Symbol};
|
||||||
use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size};
|
use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size};
|
||||||
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
|
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(impl_trait_in_assoc_type)]
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
use back::owned_target_machine::OwnedTargetMachine;
|
use back::owned_target_machine::OwnedTargetMachine;
|
||||||
use back::write::{create_informational_target_machine, create_target_machine};
|
use back::write::{create_informational_target_machine, create_target_machine};
|
||||||
|
|
||||||
@ -240,8 +237,11 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||||||
) -> Result<CompiledModule, FatalError> {
|
) -> Result<CompiledModule, FatalError> {
|
||||||
back::write::codegen(cgcx, dcx, module, config)
|
back::write::codegen(cgcx, dcx, module, config)
|
||||||
}
|
}
|
||||||
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
|
fn prepare_thin(
|
||||||
back::lto::prepare_thin(module)
|
module: ModuleCodegen<Self::Module>,
|
||||||
|
emit_summary: bool,
|
||||||
|
) -> (String, Self::ThinBuffer) {
|
||||||
|
back::lto::prepare_thin(module, emit_summary)
|
||||||
}
|
}
|
||||||
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
|
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
|
||||||
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
|
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
|
||||||
|
@ -2350,10 +2350,16 @@ extern "C" {
|
|||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
|
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
|
||||||
|
|
||||||
pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer;
|
pub fn LLVMRustThinLTOBufferCreate(
|
||||||
|
M: &Module,
|
||||||
|
is_thin: bool,
|
||||||
|
emit_summary: bool,
|
||||||
|
) -> &'static mut ThinLTOBuffer;
|
||||||
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
|
pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
|
||||||
pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
|
pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
|
||||||
pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
|
pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
|
||||||
|
pub fn LLVMRustThinLTOBufferThinLinkDataPtr(M: &ThinLTOBuffer) -> *const c_char;
|
||||||
|
pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
|
||||||
pub fn LLVMRustCreateThinLTOData(
|
pub fn LLVMRustCreateThinLTOData(
|
||||||
Modules: *const ThinLTOModule,
|
Modules: *const ThinLTOModule,
|
||||||
NumModules: c_uint,
|
NumModules: c_uint,
|
||||||
|
@ -13,6 +13,7 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
|
|||||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||||
use rustc_session::config::CrateType;
|
use rustc_session::config::CrateType;
|
||||||
use rustc_target::spec::RelocModel;
|
use rustc_target::spec::RelocModel;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
|
||||||
fn predefine_static(
|
fn predefine_static(
|
||||||
|
@ -8,6 +8,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
|||||||
use rustc_target::abi::{Abi, Align, FieldsShape};
|
use rustc_target::abi::{Abi, Align, FieldsShape};
|
||||||
use rustc_target::abi::{Float, Int, Pointer};
|
use rustc_target::abi::{Float, Int, Pointer};
|
||||||
use rustc_target::abi::{Scalar, Size, Variants};
|
use rustc_target::abi::{Scalar, Size, Variants};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
@ -212,6 +212,8 @@ codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, fo
|
|||||||
|
|
||||||
codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
|
codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
|
||||||
|
|
||||||
|
codegen_ssa_self_contained_linker_missing = the self-contained linker was requested, but it wasn't found in the target's sysroot, or in rustc's sysroot
|
||||||
|
|
||||||
codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
|
codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
|
||||||
|
|
||||||
codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
|
codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
|
||||||
|
@ -37,6 +37,7 @@ use rustc_span::{Span, Symbol};
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) {
|
pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) {
|
||||||
|
@ -52,6 +52,7 @@ use std::ops::Deref;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{ExitStatus, Output, Stdio};
|
use std::process::{ExitStatus, Output, Stdio};
|
||||||
use std::{env, fmt, fs, io, mem, str};
|
use std::{env, fmt, fs, io, mem, str};
|
||||||
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
|
pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
|
||||||
if let Err(e) = fs::remove_file(path) {
|
if let Err(e) = fs::remove_file(path) {
|
||||||
@ -786,12 +787,33 @@ fn link_natively(
|
|||||||
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
||||||
&& unknown_arg_regex.is_match(&out)
|
&& unknown_arg_regex.is_match(&out)
|
||||||
&& out.contains("-no-pie")
|
&& out.contains("-no-pie")
|
||||||
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
|
&& cmd.get_args().iter().any(|e| e == "-no-pie")
|
||||||
{
|
{
|
||||||
info!("linker output: {:?}", out);
|
info!("linker output: {:?}", out);
|
||||||
warn!("Linker does not support -no-pie command line option. Retrying without.");
|
warn!("Linker does not support -no-pie command line option. Retrying without.");
|
||||||
for arg in cmd.take_args() {
|
for arg in cmd.take_args() {
|
||||||
if arg.to_string_lossy() != "-no-pie" {
|
if arg != "-no-pie" {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("{:?}", &cmd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if linking failed with an error message that indicates the driver didn't recognize
|
||||||
|
// the `-fuse-ld=lld` option. If so, re-perform the link step without it. This avoids having
|
||||||
|
// to spawn multiple instances on the happy path to do version checking, and ensures things
|
||||||
|
// keep working on the tier 1 baseline of GLIBC 2.17+. That is generally understood as GCCs
|
||||||
|
// circa RHEL/CentOS 7, 4.5 or so, whereas lld support was added in GCC 9.
|
||||||
|
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, Lld::Yes))
|
||||||
|
&& unknown_arg_regex.is_match(&out)
|
||||||
|
&& out.contains("-fuse-ld=lld")
|
||||||
|
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-fuse-ld=lld")
|
||||||
|
{
|
||||||
|
info!("linker output: {:?}", out);
|
||||||
|
warn!("The linker driver does not support `-fuse-ld=lld`. Retrying without it.");
|
||||||
|
for arg in cmd.take_args() {
|
||||||
|
if arg.to_string_lossy() != "-fuse-ld=lld" {
|
||||||
cmd.arg(arg);
|
cmd.arg(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -804,7 +826,7 @@ fn link_natively(
|
|||||||
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
if matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
||||||
&& unknown_arg_regex.is_match(&out)
|
&& unknown_arg_regex.is_match(&out)
|
||||||
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
|
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
|
||||||
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
|
&& cmd.get_args().iter().any(|e| e == "-static-pie")
|
||||||
{
|
{
|
||||||
info!("linker output: {:?}", out);
|
info!("linker output: {:?}", out);
|
||||||
warn!(
|
warn!(
|
||||||
@ -843,7 +865,7 @@ fn link_natively(
|
|||||||
assert!(pre_objects_static.is_empty() || !pre_objects_static_pie.is_empty());
|
assert!(pre_objects_static.is_empty() || !pre_objects_static_pie.is_empty());
|
||||||
assert!(post_objects_static.is_empty() || !post_objects_static_pie.is_empty());
|
assert!(post_objects_static.is_empty() || !post_objects_static_pie.is_empty());
|
||||||
for arg in cmd.take_args() {
|
for arg in cmd.take_args() {
|
||||||
if arg.to_string_lossy() == "-static-pie" {
|
if arg == "-static-pie" {
|
||||||
// Replace the output kind.
|
// Replace the output kind.
|
||||||
cmd.arg("-static");
|
cmd.arg("-static");
|
||||||
} else if pre_objects_static_pie.contains(&arg) {
|
} else if pre_objects_static_pie.contains(&arg) {
|
||||||
@ -3119,13 +3141,21 @@ fn add_lld_args(
|
|||||||
|
|
||||||
let self_contained_linker = self_contained_cli || self_contained_target;
|
let self_contained_linker = self_contained_cli || self_contained_target;
|
||||||
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
|
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
|
||||||
|
let mut linker_path_exists = false;
|
||||||
for path in sess.get_tools_search_paths(false) {
|
for path in sess.get_tools_search_paths(false) {
|
||||||
|
let linker_path = path.join("gcc-ld");
|
||||||
|
linker_path_exists |= linker_path.exists();
|
||||||
cmd.arg({
|
cmd.arg({
|
||||||
let mut arg = OsString::from("-B");
|
let mut arg = OsString::from("-B");
|
||||||
arg.push(path.join("gcc-ld"));
|
arg.push(linker_path);
|
||||||
arg
|
arg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if !linker_path_exists {
|
||||||
|
// As a sanity check, we emit an error if none of these paths exist: we want
|
||||||
|
// self-contained linking and have no linker.
|
||||||
|
sess.dcx().emit_fatal(errors::SelfContainedLinkerMissing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
|
// 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
|
||||||
|
@ -22,6 +22,7 @@ use rustc_session::Session;
|
|||||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
|
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
|
||||||
|
|
||||||
use cc::windows_registry;
|
use cc::windows_registry;
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
/// Disables non-English messages from localized linkers.
|
/// Disables non-English messages from localized linkers.
|
||||||
/// Such messages may cause issues with text encoding on Windows (#35785)
|
/// Such messages may cause issues with text encoding on Windows (#35785)
|
||||||
|
@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||||||
use rustc_fs_util::try_canonicalize;
|
use rustc_fs_util::try_canonicalize;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub struct RPathConfig<'a> {
|
pub struct RPathConfig<'a> {
|
||||||
pub libs: &'a [&'a Path],
|
pub libs: &'a [&'a Path],
|
||||||
|
@ -18,6 +18,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
|||||||
use rustc_middle::util::Providers;
|
use rustc_middle::util::Providers;
|
||||||
use rustc_session::config::{CrateType, OomStrategy};
|
use rustc_session::config::{CrateType, OomStrategy};
|
||||||
use rustc_target::spec::{SanitizerSet, TlsModel};
|
use rustc_target::spec::{SanitizerSet, TlsModel};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
|
||||||
crates_export_threshold(tcx.crate_types())
|
crates_export_threshold(tcx.crate_types())
|
||||||
@ -399,7 +400,7 @@ fn upstream_monomorphizations_provider(
|
|||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
(): (),
|
(): (),
|
||||||
) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> {
|
) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> {
|
||||||
let cnums = tcx.crates(());
|
let cnums = tcx.used_crates(());
|
||||||
|
|
||||||
let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
|
let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ use std::str;
|
|||||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
|
const PRE_LTO_BC_EXT: &str = "pre-lto.bc";
|
||||||
|
|
||||||
@ -107,6 +108,7 @@ pub struct ModuleConfig {
|
|||||||
pub emit_asm: bool,
|
pub emit_asm: bool,
|
||||||
pub emit_obj: EmitObj,
|
pub emit_obj: EmitObj,
|
||||||
pub emit_thin_lto: bool,
|
pub emit_thin_lto: bool,
|
||||||
|
pub emit_thin_lto_summary: bool,
|
||||||
pub bc_cmdline: String,
|
pub bc_cmdline: String,
|
||||||
|
|
||||||
// Miscellaneous flags. These are mostly copied from command-line
|
// Miscellaneous flags. These are mostly copied from command-line
|
||||||
@ -231,6 +233,10 @@ impl ModuleConfig {
|
|||||||
),
|
),
|
||||||
emit_obj,
|
emit_obj,
|
||||||
emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
|
emit_thin_lto: sess.opts.unstable_opts.emit_thin_lto,
|
||||||
|
emit_thin_lto_summary: if_regular!(
|
||||||
|
sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode),
|
||||||
|
false
|
||||||
|
),
|
||||||
bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
|
bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(),
|
||||||
|
|
||||||
verify_llvm_ir: sess.verify_llvm_ir(),
|
verify_llvm_ir: sess.verify_llvm_ir(),
|
||||||
@ -282,6 +288,7 @@ impl ModuleConfig {
|
|||||||
|
|
||||||
pub fn bitcode_needed(&self) -> bool {
|
pub fn bitcode_needed(&self) -> bool {
|
||||||
self.emit_bc
|
self.emit_bc
|
||||||
|
|| self.emit_thin_lto_summary
|
||||||
|| self.emit_obj == EmitObj::Bitcode
|
|| self.emit_obj == EmitObj::Bitcode
|
||||||
|| self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
|
|| self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)
|
||||||
}
|
}
|
||||||
@ -629,6 +636,9 @@ fn produce_final_output_artifacts(
|
|||||||
// them for making an rlib.
|
// them for making an rlib.
|
||||||
copy_if_one_unit(OutputType::Bitcode, true);
|
copy_if_one_unit(OutputType::Bitcode, true);
|
||||||
}
|
}
|
||||||
|
OutputType::ThinLinkBitcode => {
|
||||||
|
copy_if_one_unit(OutputType::ThinLinkBitcode, false);
|
||||||
|
}
|
||||||
OutputType::LlvmAssembly => {
|
OutputType::LlvmAssembly => {
|
||||||
copy_if_one_unit(OutputType::LlvmAssembly, false);
|
copy_if_one_unit(OutputType::LlvmAssembly, false);
|
||||||
}
|
}
|
||||||
@ -882,7 +892,7 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
|
|||||||
match lto_type {
|
match lto_type {
|
||||||
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
|
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
|
||||||
ComputedLtoType::Thin => {
|
ComputedLtoType::Thin => {
|
||||||
let (name, thin_buffer) = B::prepare_thin(module);
|
let (name, thin_buffer) = B::prepare_thin(module, false);
|
||||||
if let Some(path) = bitcode {
|
if let Some(path) = bitcode {
|
||||||
fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
|
fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
|
||||||
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
|
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
|
||||||
|
@ -45,6 +45,7 @@ use std::collections::BTreeSet;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use tracing::{debug, info};
|
||||||
|
|
||||||
pub fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
pub fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||||
match op {
|
match op {
|
||||||
@ -539,7 +540,7 @@ pub fn collect_debugger_visualizers_transitive(
|
|||||||
tcx.debugger_visualizers(LOCAL_CRATE)
|
tcx.debugger_visualizers(LOCAL_CRATE)
|
||||||
.iter()
|
.iter()
|
||||||
.chain(
|
.chain(
|
||||||
tcx.crates(())
|
tcx.used_crates(())
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&cnum| {
|
.filter(|&cnum| {
|
||||||
let used_crate_source = tcx.used_crate_source(*cnum);
|
let used_crate_source = tcx.used_crate_source(*cnum);
|
||||||
@ -849,7 +850,7 @@ impl CrateInfo {
|
|||||||
// `compiler_builtins` are always placed last to ensure that they're linked correctly.
|
// `compiler_builtins` are always placed last to ensure that they're linked correctly.
|
||||||
used_crates.extend(compiler_builtins);
|
used_crates.extend(compiler_builtins);
|
||||||
|
|
||||||
let crates = tcx.crates(());
|
let crates = tcx.used_crates(());
|
||||||
let n_crates = crates.len();
|
let n_crates = crates.len();
|
||||||
let mut info = CrateInfo {
|
let mut info = CrateInfo {
|
||||||
target_cpu,
|
target_cpu,
|
||||||
|
@ -413,6 +413,10 @@ pub struct UnableToExeLinker {
|
|||||||
#[diag(codegen_ssa_msvc_missing_linker)]
|
#[diag(codegen_ssa_msvc_missing_linker)]
|
||||||
pub struct MsvcMissingLinker;
|
pub struct MsvcMissingLinker;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(codegen_ssa_self_contained_linker_missing)]
|
||||||
|
pub struct SelfContainedLinkerMissing;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_ssa_check_installed_visual_studio)]
|
#[diag(codegen_ssa_check_installed_visual_studio)]
|
||||||
pub struct CheckInstalledVisualStudio;
|
pub struct CheckInstalledVisualStudio;
|
||||||
|
@ -15,9 +15,6 @@
|
|||||||
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
//! The backend-agnostic functions of this crate use functions defined in various traits that
|
||||||
//! have to be implemented by each backend.
|
//! have to be implemented by each backend.
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
|
@ -5,6 +5,7 @@ use rustc_middle::ty::{self, GenericArgKind, Ty};
|
|||||||
use rustc_session::config::Lto;
|
use rustc_session::config::Lto;
|
||||||
use rustc_symbol_mangling::typeid_for_trait_ref;
|
use rustc_symbol_mangling::typeid_for_trait_ref;
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::abi::call::FnAbi;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct VirtualIndex(u64);
|
pub struct VirtualIndex(u64);
|
||||||
|
@ -11,6 +11,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
|
|||||||
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind};
|
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind};
|
||||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
fx: &FunctionCx<'a, 'tcx, Bx>,
|
fx: &FunctionCx<'a, 'tcx, Bx>,
|
||||||
|
@ -24,6 +24,7 @@ use rustc_span::{source_map::Spanned, sym, Span};
|
|||||||
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
|
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
|
||||||
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
|
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ use rustc_index::IndexVec;
|
|||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
pub(super) struct Locals<'tcx, V> {
|
pub(super) struct Locals<'tcx, V> {
|
||||||
values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
|
values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
|||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_target::abi::call::{FnAbi, PassMode};
|
use rustc_target::abi::call::{FnAbi, PassMode};
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ use std::fmt;
|
|||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// The representation of a Rust value. The enum variant is in fact
|
/// The representation of a Rust value. The enum variant is in fact
|
||||||
/// uniquely determined by the value's type, but is kept as a
|
/// uniquely determined by the value's type, but is kept as a
|
||||||
|
@ -12,6 +12,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
|||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
|
use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
|
||||||
use rustc_target::abi::{VariantIdx, Variants};
|
use rustc_target::abi::{VariantIdx, Variants};
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
/// The location and extra runtime properties of the place.
|
/// The location and extra runtime properties of the place.
|
||||||
///
|
///
|
||||||
|
@ -17,6 +17,7 @@ use rustc_span::{Span, DUMMY_SP};
|
|||||||
use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT};
|
use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
#[instrument(level = "trace", skip(self, bx))]
|
#[instrument(level = "trace", skip(self, bx))]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use rustc_middle::mir::{self, NonDivergingIntrinsic};
|
use rustc_middle::mir::{self, NonDivergingIntrinsic};
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::FunctionCx;
|
use super::FunctionCx;
|
||||||
use super::LocalRef;
|
use super::LocalRef;
|
||||||
|
@ -9,6 +9,7 @@ use rustc_middle::span_bug;
|
|||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub trait MonoItemExt<'a, 'tcx> {
|
pub trait MonoItemExt<'a, 'tcx> {
|
||||||
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
|
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
|
||||||
|
@ -9,6 +9,7 @@ use rustc_middle::bug;
|
|||||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_target::abi::WrappingRange;
|
use rustc_target::abi::WrappingRange;
|
||||||
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
|
@ -56,12 +56,16 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
|
|||||||
module: ModuleCodegen<Self::Module>,
|
module: ModuleCodegen<Self::Module>,
|
||||||
config: &ModuleConfig,
|
config: &ModuleConfig,
|
||||||
) -> Result<CompiledModule, FatalError>;
|
) -> Result<CompiledModule, FatalError>;
|
||||||
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
|
fn prepare_thin(
|
||||||
|
module: ModuleCodegen<Self::Module>,
|
||||||
|
want_summary: bool,
|
||||||
|
) -> (String, Self::ThinBuffer);
|
||||||
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
|
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ThinBufferMethods: Send + Sync {
|
pub trait ThinBufferMethods: Send + Sync {
|
||||||
fn data(&self) -> &[u8];
|
fn data(&self) -> &[u8];
|
||||||
|
fn thin_link_data(&self) -> &[u8];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ModuleBufferMethods: Send + Sync {
|
pub trait ModuleBufferMethods: Send + Sync {
|
||||||
|
@ -246,11 +246,10 @@ const_eval_offset_from_unsigned_overflow =
|
|||||||
|
|
||||||
const_eval_operator_non_const =
|
const_eval_operator_non_const =
|
||||||
cannot call non-const operator in {const_eval_const_context}s
|
cannot call non-const operator in {const_eval_const_context}s
|
||||||
const_eval_overflow =
|
const_eval_overflow_arith =
|
||||||
overflow executing `{$name}`
|
arithmetic overflow in `{$intrinsic}`
|
||||||
|
|
||||||
const_eval_overflow_shift =
|
const_eval_overflow_shift =
|
||||||
overflowing shift by {$val} in `{$name}`
|
overflowing shift by {$shift_amount} in `{$intrinsic}`
|
||||||
|
|
||||||
const_eval_panic =
|
const_eval_panic =
|
||||||
the evaluated program panicked at '{$msg}', {$file}:{$line}:{$col}
|
the evaluated program panicked at '{$msg}', {$file}:{$line}:{$col}
|
||||||
|
@ -125,7 +125,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
|
|||||||
bin_op: BinOp,
|
bin_op: BinOp,
|
||||||
left: &interpret::ImmTy<'tcx, Self::Provenance>,
|
left: &interpret::ImmTy<'tcx, Self::Provenance>,
|
||||||
right: &interpret::ImmTy<'tcx, Self::Provenance>,
|
right: &interpret::ImmTy<'tcx, Self::Provenance>,
|
||||||
) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
|
) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> {
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
Ok(match bin_op {
|
Ok(match bin_op {
|
||||||
Eq | Ne | Lt | Le | Gt | Ge => {
|
Eq | Ne | Lt | Le | Gt | Ge => {
|
||||||
@ -154,7 +154,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
|
|||||||
Ge => left >= right,
|
Ge => left >= right,
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
(ImmTy::from_bool(res, *ecx.tcx), false)
|
ImmTy::from_bool(res, *ecx.tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some more operations are possible with atomics.
|
// Some more operations are possible with atomics.
|
||||||
|
@ -2,7 +2,7 @@ use std::mem;
|
|||||||
|
|
||||||
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
|
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg};
|
||||||
use rustc_hir::CRATE_HIR_ID;
|
use rustc_hir::CRATE_HIR_ID;
|
||||||
use rustc_middle::mir::interpret::Provenance;
|
use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo};
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
use rustc_middle::query::TyCtxtAt;
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
@ -139,9 +139,10 @@ where
|
|||||||
ErrorHandled::TooGeneric(span)
|
ErrorHandled::TooGeneric(span)
|
||||||
}
|
}
|
||||||
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span),
|
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span),
|
||||||
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
|
err_inval!(Layout(LayoutError::ReferencesError(guar))) => ErrorHandled::Reported(
|
||||||
ErrorHandled::Reported(guar.into(), span)
|
ReportedErrorInfo::tainted_by_errors(guar),
|
||||||
}
|
span,
|
||||||
|
),
|
||||||
// Report remaining errors.
|
// Report remaining errors.
|
||||||
_ => {
|
_ => {
|
||||||
let (our_span, frames) = get_span_and_frames();
|
let (our_span, frames) = get_span_and_frames();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::sync::atomic::Ordering::Relaxed;
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
|
@ -21,6 +21,7 @@ use rustc_span::symbol::{sym, Symbol};
|
|||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
use rustc_target::spec::abi::Abi as CallAbi;
|
use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::errors::{LongRunning, LongRunningWarn};
|
use crate::errors::{LongRunning, LongRunningWarn};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
@ -589,7 +590,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||||||
_bin_op: mir::BinOp,
|
_bin_op: mir::BinOp,
|
||||||
_left: &ImmTy<'tcx>,
|
_left: &ImmTy<'tcx>,
|
||||||
_right: &ImmTy<'tcx>,
|
_right: &ImmTy<'tcx>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
|
) -> InterpResult<'tcx, ImmTy<'tcx>> {
|
||||||
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
|
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use rustc_middle::mir::interpret::InterpErrorInfo;
|
|||||||
use rustc_middle::query::{Key, TyCtxtAt};
|
use rustc_middle::query::{Key, TyCtxtAt};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
use crate::interpret::{format_interp_error, InterpCx};
|
use crate::interpret::{format_interp_error, InterpCx};
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
|||||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
use rustc_target::abi::{Abi, VariantIdx};
|
use rustc_target::abi::{Abi, VariantIdx};
|
||||||
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const};
|
use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const};
|
||||||
use super::machine::CompileTimeEvalContext;
|
use super::machine::CompileTimeEvalContext;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
codes::*, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, Level,
|
codes::*, Diag, DiagArgValue, DiagCtxt, DiagMessage, Diagnostic, EmissionGuarantee, Level,
|
||||||
};
|
};
|
||||||
@ -481,6 +482,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
|||||||
DivisionOverflow => const_eval_division_overflow,
|
DivisionOverflow => const_eval_division_overflow,
|
||||||
RemainderOverflow => const_eval_remainder_overflow,
|
RemainderOverflow => const_eval_remainder_overflow,
|
||||||
PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
|
PointerArithOverflow => const_eval_pointer_arithmetic_overflow,
|
||||||
|
ArithOverflow { .. } => const_eval_overflow_arith,
|
||||||
|
ShiftOverflow { .. } => const_eval_overflow_shift,
|
||||||
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
|
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
|
||||||
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
|
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
|
||||||
UnterminatedCString(_) => const_eval_unterminated_c_string,
|
UnterminatedCString(_) => const_eval_unterminated_c_string,
|
||||||
@ -539,6 +542,19 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
|||||||
| UninhabitedEnumVariantWritten(_)
|
| UninhabitedEnumVariantWritten(_)
|
||||||
| UninhabitedEnumVariantRead(_) => {}
|
| UninhabitedEnumVariantRead(_) => {}
|
||||||
|
|
||||||
|
ArithOverflow { intrinsic } => {
|
||||||
|
diag.arg("intrinsic", intrinsic);
|
||||||
|
}
|
||||||
|
ShiftOverflow { intrinsic, shift_amount } => {
|
||||||
|
diag.arg("intrinsic", intrinsic);
|
||||||
|
diag.arg(
|
||||||
|
"shift_amount",
|
||||||
|
match shift_amount {
|
||||||
|
Either::Left(v) => v.to_string(),
|
||||||
|
Either::Right(v) => v.to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
BoundsCheckFailed { len, index } => {
|
BoundsCheckFailed { len, index } => {
|
||||||
diag.arg("len", len);
|
diag.arg("len", len);
|
||||||
diag.arg("index", index);
|
diag.arg("index", index);
|
||||||
|
@ -10,6 +10,7 @@ use rustc_middle::ty::{self, FloatTy, Ty};
|
|||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_target::abi::Integer;
|
use rustc_target::abi::Integer;
|
||||||
use rustc_type_ir::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
err_inval, throw_ub, throw_ub_custom, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate,
|
err_inval, throw_ub, throw_ub_custom, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate,
|
||||||
|
@ -6,6 +6,7 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
|
|||||||
use rustc_middle::ty::{self, ScalarInt, Ty};
|
use rustc_middle::ty::{self, ScalarInt, Ty};
|
||||||
use rustc_target::abi::{self, TagEncoding};
|
use rustc_target::abi::{self, TagEncoding};
|
||||||
use rustc_target::abi::{VariantIdx, Variants};
|
use rustc_target::abi::{VariantIdx, Variants};
|
||||||
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
err_ub, throw_ub, ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable,
|
err_ub, throw_ub, ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable,
|
||||||
@ -172,7 +173,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
|
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
|
||||||
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
||||||
let variant_index_relative_val =
|
let variant_index_relative_val =
|
||||||
self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
|
self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
|
||||||
let variant_index_relative =
|
let variant_index_relative =
|
||||||
variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
|
variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
|
||||||
// Check if this is in the range that indicates an actual discriminant.
|
// Check if this is in the range that indicates an actual discriminant.
|
||||||
@ -292,11 +293,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let variant_index_relative_val =
|
let variant_index_relative_val =
|
||||||
ImmTy::from_uint(variant_index_relative, tag_layout);
|
ImmTy::from_uint(variant_index_relative, tag_layout);
|
||||||
let tag = self
|
let tag = self
|
||||||
.wrapping_binary_op(
|
.binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)?
|
||||||
mir::BinOp::Add,
|
|
||||||
&variant_index_relative_val,
|
|
||||||
&niche_start_val,
|
|
||||||
)?
|
|
||||||
.to_scalar()
|
.to_scalar()
|
||||||
.assert_int();
|
.assert_int();
|
||||||
Ok(Some((tag, tag_field)))
|
Ok(Some((tag, tag_field)))
|
||||||
|
@ -2,6 +2,7 @@ use std::cell::Cell;
|
|||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use either::{Either, Left, Right};
|
use either::{Either, Left, Right};
|
||||||
|
use tracing::{debug, info, info_span, instrument, trace};
|
||||||
|
|
||||||
use hir::CRATE_HIR_ID;
|
use hir::CRATE_HIR_ID;
|
||||||
use rustc_errors::DiagCtxt;
|
use rustc_errors::DiagCtxt;
|
||||||
@ -1181,9 +1182,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||||
M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
|
M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
|
||||||
let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
|
let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
|
||||||
if M::ALL_CONSTS_ARE_PRECHECKED && !matches!(err, ErrorHandled::TooGeneric(..)) {
|
if M::ALL_CONSTS_ARE_PRECHECKED {
|
||||||
|
match err {
|
||||||
|
ErrorHandled::TooGeneric(..) => {},
|
||||||
|
ErrorHandled::Reported(reported, span) => {
|
||||||
|
if reported.is_tainted_by_errors() {
|
||||||
|
// const-eval will return "tainted" errors if e.g. the layout cannot
|
||||||
|
// be computed as the type references non-existing names.
|
||||||
|
// See <https://github.com/rust-lang/rust/issues/124348>.
|
||||||
|
} else {
|
||||||
// Looks like the const is not captued by `required_consts`, that's bad.
|
// Looks like the const is not captued by `required_consts`, that's bad.
|
||||||
bug!("interpret const eval failure of {val:?} which is not in required_consts");
|
span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err.emit_note(*ecx.tcx);
|
err.emit_note(*ecx.tcx);
|
||||||
err
|
err
|
||||||
|
@ -23,6 +23,7 @@ use rustc_middle::query::TyCtxtAt;
|
|||||||
use rustc_middle::ty::layout::TyAndLayout;
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use super::{err_ub, AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
|
use super::{err_ub, AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
|
||||||
use crate::const_eval;
|
use crate::const_eval;
|
||||||
|
@ -14,6 +14,7 @@ use rustc_middle::{
|
|||||||
};
|
};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom,
|
err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom,
|
||||||
@ -286,9 +287,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let (val, overflowed) = {
|
let (val, overflowed) = {
|
||||||
let a_offset = ImmTy::from_uint(a_offset, usize_layout);
|
let a_offset = ImmTy::from_uint(a_offset, usize_layout);
|
||||||
let b_offset = ImmTy::from_uint(b_offset, usize_layout);
|
let b_offset = ImmTy::from_uint(b_offset, usize_layout);
|
||||||
self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
|
self.binary_op(BinOp::SubWithOverflow, &a_offset, &b_offset)?
|
||||||
|
.to_scalar_pair()
|
||||||
};
|
};
|
||||||
if overflowed {
|
if overflowed.to_bool()? {
|
||||||
// a < b
|
// a < b
|
||||||
if intrinsic_name == sym::ptr_offset_from_unsigned {
|
if intrinsic_name == sym::ptr_offset_from_unsigned {
|
||||||
throw_ub_custom!(
|
throw_ub_custom!(
|
||||||
@ -300,7 +302,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// The signed form of the intrinsic allows this. If we interpret the
|
// The signed form of the intrinsic allows this. If we interpret the
|
||||||
// difference as isize, we'll get the proper signed difference. If that
|
// difference as isize, we'll get the proper signed difference. If that
|
||||||
// seems *positive*, they were more than isize::MAX apart.
|
// seems *positive*, they were more than isize::MAX apart.
|
||||||
let dist = val.to_scalar().to_target_isize(self)?;
|
let dist = val.to_target_isize(self)?;
|
||||||
if dist >= 0 {
|
if dist >= 0 {
|
||||||
throw_ub_custom!(
|
throw_ub_custom!(
|
||||||
fluent::const_eval_offset_from_underflow,
|
fluent::const_eval_offset_from_underflow,
|
||||||
@ -310,7 +312,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
dist
|
dist
|
||||||
} else {
|
} else {
|
||||||
// b >= a
|
// b >= a
|
||||||
let dist = val.to_scalar().to_target_isize(self)?;
|
let dist = val.to_target_isize(self)?;
|
||||||
// If converting to isize produced a *negative* result, we had an overflow
|
// If converting to isize produced a *negative* result, we had an overflow
|
||||||
// because they were more than isize::MAX apart.
|
// because they were more than isize::MAX apart.
|
||||||
if dist < 0 {
|
if dist < 0 {
|
||||||
@ -516,9 +518,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// Performs an exact division, resulting in undefined behavior where
|
// Performs an exact division, resulting in undefined behavior where
|
||||||
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
|
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
|
||||||
// First, check x % y != 0 (or if that computation overflows).
|
// First, check x % y != 0 (or if that computation overflows).
|
||||||
let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, a, b)?;
|
let rem = self.binary_op(BinOp::Rem, a, b)?;
|
||||||
assert!(!overflow); // All overflow is UB, so this should never return on overflow.
|
if rem.to_scalar().assert_bits(a.layout.size) != 0 {
|
||||||
if res.to_scalar().assert_bits(a.layout.size) != 0 {
|
|
||||||
throw_ub_custom!(
|
throw_ub_custom!(
|
||||||
fluent::const_eval_exact_div_has_remainder,
|
fluent::const_eval_exact_div_has_remainder,
|
||||||
a = format!("{a}"),
|
a = format!("{a}"),
|
||||||
@ -526,7 +527,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// `Rem` says this is all right, so we can let `Div` do its job.
|
// `Rem` says this is all right, so we can let `Div` do its job.
|
||||||
self.binop_ignore_overflow(BinOp::Div, a, b, &dest.clone().into())
|
let res = self.binary_op(BinOp::Div, a, b)?;
|
||||||
|
self.write_immediate(*res, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn saturating_arith(
|
pub fn saturating_arith(
|
||||||
@ -539,8 +541,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
assert!(matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..)));
|
assert!(matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..)));
|
||||||
assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
|
assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
|
||||||
|
|
||||||
let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?;
|
let (val, overflowed) =
|
||||||
Ok(if overflowed {
|
self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair();
|
||||||
|
Ok(if overflowed.to_bool()? {
|
||||||
let size = l.layout.size;
|
let size = l.layout.size;
|
||||||
let num_bits = size.bits();
|
let num_bits = size.bits();
|
||||||
if l.layout.abi.is_signed() {
|
if l.layout.abi.is_signed() {
|
||||||
@ -571,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val.to_scalar()
|
val
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: &ImmTy<'tcx, Self::Provenance>,
|
left: &ImmTy<'tcx, Self::Provenance>,
|
||||||
right: &ImmTy<'tcx, Self::Provenance>,
|
right: &ImmTy<'tcx, Self::Provenance>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>;
|
) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>>;
|
||||||
|
|
||||||
/// Generate the NaN returned by a float operation, given the list of inputs.
|
/// Generate the NaN returned by a float operation, given the list of inputs.
|
||||||
/// (This is all inputs, not just NaN inputs!)
|
/// (This is all inputs, not just NaN inputs!)
|
||||||
|
@ -21,6 +21,8 @@ use rustc_middle::mir::display_allocation;
|
|||||||
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_target::abi::{Align, HasDataLayout, Size};
|
use rustc_target::abi::{Align, HasDataLayout, Size};
|
||||||
|
|
||||||
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
|
||||||
use either::{Either, Left, Right};
|
use either::{Either, Left, Right};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_middle::mir::interpret::ScalarSizeMismatch;
|
use rustc_middle::mir::interpret::ScalarSizeMismatch;
|
||||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
||||||
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
|
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
@ -249,6 +250,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||||||
Self::from_scalar(Scalar::from_i8(c as i8), layout)
|
Self::from_scalar(Scalar::from_i8(c as i8), layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
let layout = tcx
|
||||||
|
.layout_of(
|
||||||
|
ty::ParamEnv::reveal_all().and(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the immediate as a `ScalarInt`. Ensures that it has the size that the layout of the
|
/// Return the immediate as a `ScalarInt`. Ensures that it has the size that the layout of the
|
||||||
/// immediate indicates.
|
/// immediate indicates.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -270,6 +280,17 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||||||
ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral())
|
ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
|
||||||
|
pub fn to_pair(self, cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>)) -> (Self, Self) {
|
||||||
|
let layout = self.layout;
|
||||||
|
let (val0, val1) = self.to_scalar_pair();
|
||||||
|
(
|
||||||
|
ImmTy::from_scalar(val0, layout.field(cx, 0)),
|
||||||
|
ImmTy::from_scalar(val1, layout.field(cx, 1)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the "sub-immediate" that is located within the `base` at the given offset with the
|
/// Compute the "sub-immediate" that is located within the `base` at the given offset with the
|
||||||
/// given layout.
|
/// given layout.
|
||||||
// Not called `offset` to avoid confusion with the trait method.
|
// Not called `offset` to avoid confusion with the trait method.
|
||||||
|
@ -1,78 +1,23 @@
|
|||||||
|
use either::Either;
|
||||||
|
|
||||||
use rustc_apfloat::{Float, FloatConvert};
|
use rustc_apfloat::{Float, FloatConvert};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
|
use rustc_middle::ty::{self, FloatTy, ScalarInt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_target::abi::Abi;
|
use tracing::trace;
|
||||||
|
|
||||||
use super::{err_ub, throw_ub, throw_ub_custom, ImmTy, Immediate, InterpCx, Machine, PlaceTy};
|
use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
|
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
|
||||||
/// and a boolean signifying the potential overflow to the destination.
|
|
||||||
pub fn binop_with_overflow(
|
|
||||||
&mut self,
|
|
||||||
op: mir::BinOp,
|
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
let (val, overflowed) = self.overflowing_binary_op(op, left, right)?;
|
|
||||||
debug_assert_eq!(
|
|
||||||
Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]),
|
|
||||||
dest.layout.ty,
|
|
||||||
"type mismatch for result of {op:?}",
|
|
||||||
);
|
|
||||||
// Write the result to `dest`.
|
|
||||||
if let Abi::ScalarPair(..) = dest.layout.abi {
|
|
||||||
// We can use the optimized path and avoid `place_field` (which might do
|
|
||||||
// `force_allocation`).
|
|
||||||
let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed));
|
|
||||||
self.write_immediate(pair, dest)?;
|
|
||||||
} else {
|
|
||||||
assert!(self.tcx.sess.opts.unstable_opts.randomize_layout);
|
|
||||||
// With randomized layout, `(int, bool)` might cease to be a `ScalarPair`, so we have to
|
|
||||||
// do a component-wise write here. This code path is slower than the above because
|
|
||||||
// `place_field` will have to `force_allocate` locals here.
|
|
||||||
let val_field = self.project_field(dest, 0)?;
|
|
||||||
self.write_scalar(val.to_scalar(), &val_field)?;
|
|
||||||
let overflowed_field = self.project_field(dest, 1)?;
|
|
||||||
self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies the binary operation `op` to the arguments and writes the result to the
|
|
||||||
/// destination.
|
|
||||||
pub fn binop_ignore_overflow(
|
|
||||||
&mut self,
|
|
||||||
op: mir::BinOp,
|
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
|
||||||
) -> InterpResult<'tcx> {
|
|
||||||
let val = self.wrapping_binary_op(op, left, right)?;
|
|
||||||
assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}");
|
|
||||||
self.write_immediate(*val, dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|
||||||
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
|
||||||
let res = Ord::cmp(&lhs, &rhs);
|
let res = Ord::cmp(&lhs, &rhs);
|
||||||
return (ImmTy::from_ordering(res, *self.tcx), false);
|
return ImmTy::from_ordering(res, *self.tcx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_char_op(
|
fn binary_char_op(&self, bin_op: mir::BinOp, l: char, r: char) -> ImmTy<'tcx, M::Provenance> {
|
||||||
&self,
|
|
||||||
bin_op: mir::BinOp,
|
|
||||||
l: char,
|
|
||||||
r: char,
|
|
||||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
|
|
||||||
if bin_op == Cmp {
|
if bin_op == Cmp {
|
||||||
@ -88,15 +33,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Ge => l >= r,
|
Ge => l >= r,
|
||||||
_ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
|
_ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
|
||||||
};
|
};
|
||||||
(ImmTy::from_bool(res, *self.tcx), false)
|
ImmTy::from_bool(res, *self.tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_bool_op(
|
fn binary_bool_op(&self, bin_op: mir::BinOp, l: bool, r: bool) -> ImmTy<'tcx, M::Provenance> {
|
||||||
&self,
|
|
||||||
bin_op: mir::BinOp,
|
|
||||||
l: bool,
|
|
||||||
r: bool,
|
|
||||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
|
|
||||||
let res = match bin_op {
|
let res = match bin_op {
|
||||||
@ -111,7 +51,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
BitXor => l ^ r,
|
BitXor => l ^ r,
|
||||||
_ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
|
_ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
|
||||||
};
|
};
|
||||||
(ImmTy::from_bool(res, *self.tcx), false)
|
ImmTy::from_bool(res, *self.tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>(
|
fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>(
|
||||||
@ -120,14 +60,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
layout: TyAndLayout<'tcx>,
|
layout: TyAndLayout<'tcx>,
|
||||||
l: F,
|
l: F,
|
||||||
r: F,
|
r: F,
|
||||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
) -> ImmTy<'tcx, M::Provenance> {
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
|
|
||||||
// Performs appropriate non-deterministic adjustments of NaN results.
|
// Performs appropriate non-deterministic adjustments of NaN results.
|
||||||
let adjust_nan =
|
let adjust_nan =
|
||||||
|f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } };
|
|f: F| -> F { if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } };
|
||||||
|
|
||||||
let val = match bin_op {
|
match bin_op {
|
||||||
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
||||||
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
||||||
Lt => ImmTy::from_bool(l < r, *self.tcx),
|
Lt => ImmTy::from_bool(l < r, *self.tcx),
|
||||||
@ -140,8 +80,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout),
|
Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout),
|
||||||
Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout),
|
Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout),
|
||||||
_ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
|
_ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
|
||||||
};
|
}
|
||||||
(val, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_int_op(
|
fn binary_int_op(
|
||||||
@ -149,7 +88,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
left: &ImmTy<'tcx, M::Provenance>,
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
right: &ImmTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
|
|
||||||
// This checks the size, so that we can just assert it below.
|
// This checks the size, so that we can just assert it below.
|
||||||
@ -169,25 +108,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
ShrUnchecked => Some(sym::unchecked_shr),
|
ShrUnchecked => Some(sym::unchecked_shr),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
let with_overflow = bin_op.is_overflowing();
|
||||||
|
|
||||||
// Shift ops can have an RHS with a different numeric type.
|
// Shift ops can have an RHS with a different numeric type.
|
||||||
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
||||||
let size = left.layout.size.bits();
|
let size = left.layout.size.bits();
|
||||||
// The shift offset is implicitly masked to the type size. (This is the one MIR operator
|
// Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is
|
||||||
// that does *not* directly map to a single LLVM operation.) Compute how much we
|
// the one MIR operator that does *not* directly map to a single LLVM operation.)
|
||||||
// actually shift and whether there was an overflow due to shifting too much.
|
|
||||||
let (shift_amount, overflow) = if right.layout.abi.is_signed() {
|
let (shift_amount, overflow) = if right.layout.abi.is_signed() {
|
||||||
let shift_amount = r_signed();
|
let shift_amount = r_signed();
|
||||||
let overflow = shift_amount < 0 || shift_amount >= i128::from(size);
|
let overflow = shift_amount < 0 || shift_amount >= i128::from(size);
|
||||||
// Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result
|
// Deliberately wrapping `as` casts: shift_amount *can* be negative, but the result
|
||||||
// of the `as` will be equal modulo `size` (since it is a power of two).
|
// of the `as` will be equal modulo `size` (since it is a power of two).
|
||||||
let masked_amount = (shift_amount as u128) % u128::from(size);
|
let masked_amount = (shift_amount as u128) % u128::from(size);
|
||||||
assert_eq!(overflow, shift_amount != (masked_amount as i128));
|
assert_eq!(overflow, shift_amount != i128::try_from(masked_amount).unwrap());
|
||||||
(masked_amount, overflow)
|
(masked_amount, overflow)
|
||||||
} else {
|
} else {
|
||||||
let shift_amount = r_unsigned();
|
let shift_amount = r_unsigned();
|
||||||
|
let overflow = shift_amount >= u128::from(size);
|
||||||
let masked_amount = shift_amount % u128::from(size);
|
let masked_amount = shift_amount % u128::from(size);
|
||||||
(masked_amount, shift_amount != masked_amount)
|
assert_eq!(overflow, shift_amount != masked_amount);
|
||||||
|
(masked_amount, overflow)
|
||||||
};
|
};
|
||||||
let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit
|
let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit
|
||||||
// Compute the shifted result.
|
// Compute the shifted result.
|
||||||
@ -209,19 +150,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
ScalarInt::truncate_from_uint(result, left.layout.size).0
|
ScalarInt::truncate_from_uint(result, left.layout.size).0
|
||||||
};
|
};
|
||||||
|
|
||||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
if overflow && let Some(intrinsic) = throw_ub_on_overflow {
|
||||||
throw_ub_custom!(
|
throw_ub!(ShiftOverflow {
|
||||||
fluent::const_eval_overflow_shift,
|
intrinsic,
|
||||||
val = if right.layout.abi.is_signed() {
|
shift_amount: if right.layout.abi.is_signed() {
|
||||||
r_signed().to_string()
|
Either::Right(r_signed())
|
||||||
} else {
|
} else {
|
||||||
r_unsigned().to_string()
|
Either::Left(r_unsigned())
|
||||||
},
|
}
|
||||||
name = intrinsic_name
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok((ImmTy::from_scalar_int(result, left.layout), overflow));
|
return Ok(ImmTy::from_scalar_int(result, left.layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the remaining ops, the types must be the same on both sides
|
// For the remaining ops, the types must be the same on both sides
|
||||||
@ -246,7 +186,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(op) = op {
|
if let Some(op) = op {
|
||||||
return Ok((ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx), false));
|
return Ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx));
|
||||||
}
|
}
|
||||||
if bin_op == Cmp {
|
if bin_op == Cmp {
|
||||||
return Ok(self.three_way_compare(l_signed(), r_signed()));
|
return Ok(self.three_way_compare(l_signed(), r_signed()));
|
||||||
@ -256,9 +196,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Rem if r.is_null() => throw_ub!(RemainderByZero),
|
Rem if r.is_null() => throw_ub!(RemainderByZero),
|
||||||
Div => Some(i128::overflowing_div),
|
Div => Some(i128::overflowing_div),
|
||||||
Rem => Some(i128::overflowing_rem),
|
Rem => Some(i128::overflowing_rem),
|
||||||
Add | AddUnchecked => Some(i128::overflowing_add),
|
Add | AddUnchecked | AddWithOverflow => Some(i128::overflowing_add),
|
||||||
Sub | SubUnchecked => Some(i128::overflowing_sub),
|
Sub | SubUnchecked | SubWithOverflow => Some(i128::overflowing_sub),
|
||||||
Mul | MulUnchecked => Some(i128::overflowing_mul),
|
Mul | MulUnchecked | MulWithOverflow => Some(i128::overflowing_mul),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(op) = op {
|
if let Some(op) = op {
|
||||||
@ -282,10 +222,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// If that truncation loses any information, we have an overflow.
|
// If that truncation loses any information, we have an overflow.
|
||||||
let (result, lossy) = ScalarInt::truncate_from_int(result, left.layout.size);
|
let (result, lossy) = ScalarInt::truncate_from_int(result, left.layout.size);
|
||||||
let overflow = oflo || lossy;
|
let overflow = oflo || lossy;
|
||||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
if overflow && let Some(intrinsic) = throw_ub_on_overflow {
|
||||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
throw_ub!(ArithOverflow { intrinsic });
|
||||||
}
|
}
|
||||||
return Ok((ImmTy::from_scalar_int(result, left.layout), overflow));
|
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||||
|
return Ok(if with_overflow {
|
||||||
|
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||||
|
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// From here on it's okay to treat everything as unsigned.
|
// From here on it's okay to treat everything as unsigned.
|
||||||
@ -296,7 +242,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
return Ok(self.three_way_compare(l, r));
|
return Ok(self.three_way_compare(l, r));
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = match bin_op {
|
Ok(match bin_op {
|
||||||
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
||||||
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
||||||
|
|
||||||
@ -309,29 +255,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
BitAnd => ImmTy::from_uint(l & r, left.layout),
|
BitAnd => ImmTy::from_uint(l & r, left.layout),
|
||||||
BitXor => ImmTy::from_uint(l ^ r, left.layout),
|
BitXor => ImmTy::from_uint(l ^ r, left.layout),
|
||||||
|
|
||||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => {
|
_ => {
|
||||||
assert!(!left.layout.abi.is_signed());
|
assert!(!left.layout.abi.is_signed());
|
||||||
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
|
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
|
||||||
Add | AddUnchecked => u128::overflowing_add,
|
Add | AddUnchecked | AddWithOverflow => u128::overflowing_add,
|
||||||
Sub | SubUnchecked => u128::overflowing_sub,
|
Sub | SubUnchecked | SubWithOverflow => u128::overflowing_sub,
|
||||||
Mul | MulUnchecked => u128::overflowing_mul,
|
Mul | MulUnchecked | MulWithOverflow => u128::overflowing_mul,
|
||||||
Div if r == 0 => throw_ub!(DivisionByZero),
|
Div if r == 0 => throw_ub!(DivisionByZero),
|
||||||
Rem if r == 0 => throw_ub!(RemainderByZero),
|
Rem if r == 0 => throw_ub!(RemainderByZero),
|
||||||
Div => u128::overflowing_div,
|
Div => u128::overflowing_div,
|
||||||
Rem => u128::overflowing_rem,
|
Rem => u128::overflowing_rem,
|
||||||
_ => bug!(),
|
|
||||||
};
|
|
||||||
let (result, oflo) = op(l, r);
|
|
||||||
// Truncate to target type.
|
|
||||||
// If that truncation loses any information, we have an overflow.
|
|
||||||
let (result, lossy) = ScalarInt::truncate_from_uint(result, left.layout.size);
|
|
||||||
let overflow = oflo || lossy;
|
|
||||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
|
||||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
|
||||||
}
|
|
||||||
return Ok((ImmTy::from_scalar_int(result, left.layout), overflow));
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => span_bug!(
|
_ => span_bug!(
|
||||||
self.cur_span(),
|
self.cur_span(),
|
||||||
"invalid binary op {:?}: {:?}, {:?} (both {})",
|
"invalid binary op {:?}: {:?}, {:?} (both {})",
|
||||||
@ -341,8 +274,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
right.layout.ty,
|
right.layout.ty,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
let (result, oflo) = op(l, r);
|
||||||
Ok((val, false))
|
// Truncate to target type.
|
||||||
|
// If that truncation loses any information, we have an overflow.
|
||||||
|
let (result, lossy) = ScalarInt::truncate_from_uint(result, left.layout.size);
|
||||||
|
let overflow = oflo || lossy;
|
||||||
|
if overflow && let Some(intrinsic) = throw_ub_on_overflow {
|
||||||
|
throw_ub!(ArithOverflow { intrinsic });
|
||||||
|
}
|
||||||
|
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||||
|
if with_overflow {
|
||||||
|
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||||
|
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||||
|
} else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_ptr_op(
|
fn binary_ptr_op(
|
||||||
@ -350,7 +298,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
left: &ImmTy<'tcx, M::Provenance>,
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
right: &ImmTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||||
use rustc_middle::mir::BinOp::*;
|
use rustc_middle::mir::BinOp::*;
|
||||||
|
|
||||||
match bin_op {
|
match bin_op {
|
||||||
@ -369,10 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
|
offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?;
|
||||||
|
|
||||||
let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
|
let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
|
||||||
Ok((
|
Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout))
|
||||||
ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout),
|
|
||||||
false,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall back to machine hook so Miri can support more pointer ops.
|
// Fall back to machine hook so Miri can support more pointer ops.
|
||||||
@ -380,13 +325,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the result of the specified operation, and whether it overflowed.
|
/// Returns the result of the specified operation.
|
||||||
pub fn overflowing_binary_op(
|
///
|
||||||
|
/// Whether this produces a scalar or a pair depends on the specific `bin_op`.
|
||||||
|
pub fn binary_op(
|
||||||
&self,
|
&self,
|
||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
left: &ImmTy<'tcx, M::Provenance>,
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
right: &ImmTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||||
trace!(
|
trace!(
|
||||||
"Running binary op {:?}: {:?} ({}), {:?} ({})",
|
"Running binary op {:?}: {:?} ({}), {:?} ({})",
|
||||||
bin_op,
|
bin_op,
|
||||||
@ -458,24 +405,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn wrapping_binary_op(
|
|
||||||
&self,
|
|
||||||
bin_op: mir::BinOp,
|
|
||||||
left: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
right: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
|
||||||
let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the result of the specified operation, whether it overflowed, and
|
/// Returns the result of the specified operation, whether it overflowed, and
|
||||||
/// the result type.
|
/// the result type.
|
||||||
pub fn overflowing_unary_op(
|
pub fn unary_op(
|
||||||
&self,
|
&self,
|
||||||
un_op: mir::UnOp,
|
un_op: mir::UnOp,
|
||||||
val: &ImmTy<'tcx, M::Provenance>,
|
val: &ImmTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||||
use rustc_middle::mir::UnOp::*;
|
use rustc_middle::mir::UnOp::*;
|
||||||
|
|
||||||
let layout = val.layout;
|
let layout = val.layout;
|
||||||
@ -489,7 +425,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
Not => !val,
|
Not => !val,
|
||||||
_ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
|
_ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
|
||||||
};
|
};
|
||||||
Ok((ImmTy::from_bool(res, *self.tcx), false))
|
Ok(ImmTy::from_bool(res, *self.tcx))
|
||||||
}
|
}
|
||||||
ty::Float(fty) => {
|
ty::Float(fty) => {
|
||||||
// No NaN adjustment here, `-` is a bitwise operation!
|
// No NaN adjustment here, `-` is a bitwise operation!
|
||||||
@ -498,37 +434,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||||
_ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
|
_ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
|
||||||
};
|
};
|
||||||
Ok((ImmTy::from_scalar(res, layout), false))
|
Ok(ImmTy::from_scalar(res, layout))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
assert!(layout.ty.is_integral());
|
assert!(layout.ty.is_integral());
|
||||||
let val = val.to_bits(layout.size)?;
|
let val = val.to_bits(layout.size)?;
|
||||||
let (res, overflow) = match un_op {
|
let res = match un_op {
|
||||||
Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate
|
Not => self.truncate(!val, layout), // bitwise negation, then truncate
|
||||||
Neg => {
|
Neg => {
|
||||||
// arithmetic negation
|
// arithmetic negation
|
||||||
assert!(layout.abi.is_signed());
|
assert!(layout.abi.is_signed());
|
||||||
let val = self.sign_extend(val, layout) as i128;
|
let val = self.sign_extend(val, layout) as i128;
|
||||||
let (res, overflow) = val.overflowing_neg();
|
let res = val.wrapping_neg();
|
||||||
let res = res as u128;
|
let res = res as u128;
|
||||||
// Truncate to target type.
|
// Truncate to target type.
|
||||||
// If that truncation loses any information, we have an overflow.
|
self.truncate(res, layout)
|
||||||
let truncated = self.truncate(res, layout);
|
|
||||||
(truncated, overflow || self.sign_extend(truncated, layout) != res)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok((ImmTy::from_uint(res, layout), overflow))
|
Ok(ImmTy::from_uint(res, layout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn wrapping_unary_op(
|
|
||||||
&self,
|
|
||||||
un_op: mir::UnOp,
|
|
||||||
val: &ImmTy<'tcx, M::Provenance>,
|
|
||||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
|
||||||
let (val, _overflow) = self.overflowing_unary_op(un_op, val)?;
|
|
||||||
Ok(val)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
|
||||||
use either::{Either, Left, Right};
|
use either::{Either, Left, Right};
|
||||||
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
|
@ -18,6 +18,8 @@ use rustc_middle::{bug, span_bug};
|
|||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
use rustc_target::abi::{self, VariantIdx};
|
use rustc_target::abi::{self, VariantIdx};
|
||||||
|
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
||||||
Provenance, Scalar,
|
Provenance, Scalar,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
//! The main entry point is the `step` method.
|
//! The main entry point is the `step` method.
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use tracing::{info, instrument, trace};
|
||||||
|
|
||||||
use rustc_index::IndexSlice;
|
use rustc_index::IndexSlice;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
@ -167,19 +168,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
|
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
|
||||||
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||||
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
||||||
if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
|
let result = self.binary_op(bin_op, &left, &right)?;
|
||||||
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
|
assert_eq!(result.layout, dest.layout, "layout mismatch for result of {bin_op:?}");
|
||||||
} else {
|
self.write_immediate(*result, &dest)?;
|
||||||
self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UnaryOp(un_op, ref operand) => {
|
UnaryOp(un_op, ref operand) => {
|
||||||
// The operand always has the same type as the result.
|
// The operand always has the same type as the result.
|
||||||
let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
|
let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
|
||||||
let val = self.wrapping_unary_op(un_op, &val)?;
|
let result = self.unary_op(un_op, &val)?;
|
||||||
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}");
|
assert_eq!(result.layout, dest.layout, "layout mismatch for result of {un_op:?}");
|
||||||
self.write_immediate(*val, &dest)?;
|
self.write_immediate(*result, &dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Aggregate(box ref kind, ref operands) => {
|
Aggregate(box ref kind, ref operands) => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use rustc_middle::span_bug;
|
use rustc_middle::span_bug;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
@ -97,7 +98,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
for (const_int, target) in targets.iter() {
|
for (const_int, target) in targets.iter() {
|
||||||
// Compare using MIR BinOp::Eq, to also support pointer values.
|
// Compare using MIR BinOp::Eq, to also support pointer values.
|
||||||
// (Avoiding `self.binary_op` as that does some redundant layout computation.)
|
// (Avoiding `self.binary_op` as that does some redundant layout computation.)
|
||||||
let res = self.wrapping_binary_op(
|
let res = self.binary_op(
|
||||||
mir::BinOp::Eq,
|
mir::BinOp::Eq,
|
||||||
&discr,
|
&discr,
|
||||||
&ImmTy::from_uint(const_int, discr.layout),
|
&ImmTy::from_uint(const_int, discr.layout),
|
||||||
|
@ -2,6 +2,7 @@ use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
|||||||
use rustc_middle::ty::layout::LayoutOf;
|
use rustc_middle::ty::layout::LayoutOf;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_target::abi::{Align, Size};
|
use rustc_target::abi::{Align, Size};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use super::util::ensure_monomorphic_enough;
|
use super::util::ensure_monomorphic_enough;
|
||||||
use super::{InterpCx, Machine};
|
use super::{InterpCx, Machine};
|
||||||
|
@ -7,6 +7,7 @@ use rustc_middle::ty::{
|
|||||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||||
};
|
};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
|
use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use std::fmt::Write;
|
|||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use hir::def::DefKind;
|
use hir::def::DefKind;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
|
@ -6,6 +6,7 @@ use rustc_middle::mir::interpret::InterpResult;
|
|||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
|
use rustc_target::abi::{FieldsShape, VariantIdx, Variants};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
|
||||||
|
@ -14,9 +14,6 @@
|
|||||||
#![feature(yeet_expr)]
|
#![feature(yeet_expr)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
pub mod const_eval;
|
pub mod const_eval;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod interpret;
|
pub mod interpret;
|
||||||
|
@ -20,6 +20,8 @@ use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use tracing::{debug, instrument, trace};
|
||||||
|
|
||||||
use super::ops::{self, NonConstOp, Status};
|
use super::ops::{self, NonConstOp, Status};
|
||||||
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
|
||||||
use super::resolver::FlowSensitiveAnalysis;
|
use super::resolver::FlowSensitiveAnalysis;
|
||||||
|
@ -19,6 +19,7 @@ use rustc_session::parse::feature_err;
|
|||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{BytePos, Pos, Span, Symbol};
|
use rustc_span::{BytePos, Pos, Span, Symbol};
|
||||||
use rustc_trait_selection::traits::SelectionContext;
|
use rustc_trait_selection::traits::SelectionContext;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use super::ConstCx;
|
use super::ConstCx;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
|
@ -2,6 +2,7 @@ use rustc_middle::mir::visit::Visitor;
|
|||||||
use rustc_middle::mir::{self, BasicBlock, Location};
|
use rustc_middle::mir::{self, BasicBlock, Location};
|
||||||
use rustc_middle::ty::{Ty, TyCtxt};
|
use rustc_middle::ty::{Ty, TyCtxt};
|
||||||
use rustc_span::{symbol::sym, Span};
|
use rustc_span::{symbol::sym, Span};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use super::check::Qualifs;
|
use super::check::Qualifs;
|
||||||
use super::ops::{self, NonConstOp};
|
use super::ops::{self, NonConstOp};
|
||||||
|
@ -13,6 +13,7 @@ use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
|
|||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
|
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
|
||||||
};
|
};
|
||||||
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
use super::ConstCx;
|
use super::ConstCx;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_target::abi::Align;
|
use rustc_target::abi::Align;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Returns `true` if this place is allowed to be less aligned
|
/// Returns `true` if this place is allowed to be less aligned
|
||||||
/// than its containing struct (because it is within a packed
|
/// than its containing struct (because it is within a packed
|
||||||
|
@ -5,6 +5,7 @@ use rustc_middle::query::TyCtxtAt;
|
|||||||
use rustc_middle::ty::layout::LayoutOf;
|
use rustc_middle::ty::layout::LayoutOf;
|
||||||
use rustc_middle::ty::{self, Mutability};
|
use rustc_middle::ty::{self, Mutability};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext};
|
use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext};
|
||||||
use crate::interpret::*;
|
use crate::interpret::*;
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
use fluent_bundle::FluentResource;
|
use fluent_bundle::FluentResource;
|
||||||
use fluent_syntax::parser::ParserError;
|
use fluent_syntax::parser::ParserError;
|
||||||
use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
|
use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
|
||||||
@ -20,6 +17,7 @@ use std::fmt;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use tracing::{instrument, trace};
|
||||||
|
|
||||||
#[cfg(not(parallel_compiler))]
|
#[cfg(not(parallel_compiler))]
|
||||||
use std::cell::LazyCell as Lazy;
|
use std::cell::LazyCell as Lazy;
|
||||||
|
@ -68,12 +68,15 @@ pub(crate) enum KleeneOp {
|
|||||||
/// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros.
|
/// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros.
|
||||||
#[derive(Debug, PartialEq, Encodable, Decodable)]
|
#[derive(Debug, PartialEq, Encodable, Decodable)]
|
||||||
enum TokenTree {
|
enum TokenTree {
|
||||||
|
/// A token. Unlike `tokenstream::TokenTree::Token` this lacks a `Spacing`.
|
||||||
|
/// See the comments about `Spacing` in the `transcribe` function.
|
||||||
Token(Token),
|
Token(Token),
|
||||||
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
|
/// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS).
|
||||||
Delimited(DelimSpan, DelimSpacing, Delimited),
|
Delimited(DelimSpan, DelimSpacing, Delimited),
|
||||||
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
|
/// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS).
|
||||||
Sequence(DelimSpan, SequenceRepetition),
|
Sequence(DelimSpan, SequenceRepetition),
|
||||||
/// e.g., `$var`.
|
/// e.g., `$var`. The span covers the leading dollar and the ident. (The span within the ident
|
||||||
|
/// only covers the ident, e.g. `var`.)
|
||||||
MetaVar(Span, Ident),
|
MetaVar(Span, Ident),
|
||||||
/// e.g., `$var:expr`. Only appears on the LHS.
|
/// e.g., `$var:expr`. Only appears on the LHS.
|
||||||
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
|
||||||
|
@ -62,7 +62,10 @@ pub(super) fn parse(
|
|||||||
match tree {
|
match tree {
|
||||||
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
|
||||||
let span = match trees.next() {
|
let span = match trees.next() {
|
||||||
Some(&tokenstream::TokenTree::Token(Token { kind: token::Colon, span }, _)) => {
|
Some(&tokenstream::TokenTree::Token(
|
||||||
|
Token { kind: token::Colon, span: colon_span },
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
match trees.next() {
|
match trees.next() {
|
||||||
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
|
||||||
Some((fragment, _)) => {
|
Some((fragment, _)) => {
|
||||||
@ -126,10 +129,12 @@ pub(super) fn parse(
|
|||||||
}
|
}
|
||||||
_ => token.span,
|
_ => token.span,
|
||||||
},
|
},
|
||||||
tree => tree.map_or(span, tokenstream::TokenTree::span),
|
Some(tree) => tree.span(),
|
||||||
|
None => colon_span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tree => tree.map_or(start_sp, tokenstream::TokenTree::span),
|
Some(tree) => tree.span(),
|
||||||
|
None => start_sp,
|
||||||
};
|
};
|
||||||
|
|
||||||
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
result.push(TokenTree::MetaVarDecl(span, ident, None));
|
||||||
@ -176,7 +181,7 @@ fn parse_tree<'a>(
|
|||||||
// Depending on what `tree` is, we could be parsing different parts of a macro
|
// Depending on what `tree` is, we could be parsing different parts of a macro
|
||||||
match tree {
|
match tree {
|
||||||
// `tree` is a `$` token. Look at the next token in `trees`
|
// `tree` is a `$` token. Look at the next token in `trees`
|
||||||
&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _) => {
|
&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span: dollar_span }, _) => {
|
||||||
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
|
// FIXME: Handle `Invisible`-delimited groups in a more systematic way
|
||||||
// during parsing.
|
// during parsing.
|
||||||
let mut next = outer_trees.next();
|
let mut next = outer_trees.next();
|
||||||
@ -209,7 +214,7 @@ fn parse_tree<'a>(
|
|||||||
err.emit();
|
err.emit();
|
||||||
// Returns early the same read `$` to avoid spanning
|
// Returns early the same read `$` to avoid spanning
|
||||||
// unrelated diagnostics that could be performed afterwards
|
// unrelated diagnostics that could be performed afterwards
|
||||||
return TokenTree::token(token::Dollar, span);
|
return TokenTree::token(token::Dollar, dollar_span);
|
||||||
}
|
}
|
||||||
Ok(elem) => {
|
Ok(elem) => {
|
||||||
maybe_emit_macro_metavar_expr_feature(
|
maybe_emit_macro_metavar_expr_feature(
|
||||||
@ -251,7 +256,7 @@ fn parse_tree<'a>(
|
|||||||
// special metavariable that names the crate of the invocation.
|
// special metavariable that names the crate of the invocation.
|
||||||
Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
|
Some(tokenstream::TokenTree::Token(token, _)) if token.is_ident() => {
|
||||||
let (ident, is_raw) = token.ident().unwrap();
|
let (ident, is_raw) = token.ident().unwrap();
|
||||||
let span = ident.span.with_lo(span.lo());
|
let span = ident.span.with_lo(dollar_span.lo());
|
||||||
if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) {
|
if ident.name == kw::Crate && matches!(is_raw, IdentIsRaw::No) {
|
||||||
TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
|
TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span)
|
||||||
} else {
|
} else {
|
||||||
@ -260,16 +265,19 @@ fn parse_tree<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `tree` is followed by another `$`. This is an escaped `$`.
|
// `tree` is followed by another `$`. This is an escaped `$`.
|
||||||
Some(&tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }, _)) => {
|
Some(&tokenstream::TokenTree::Token(
|
||||||
|
Token { kind: token::Dollar, span: dollar_span2 },
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
if parsing_patterns {
|
if parsing_patterns {
|
||||||
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
span_dollar_dollar_or_metavar_in_the_lhs_err(
|
||||||
sess,
|
sess,
|
||||||
&Token { kind: token::Dollar, span },
|
&Token { kind: token::Dollar, span: dollar_span2 },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
maybe_emit_macro_metavar_expr_feature(features, sess, span);
|
maybe_emit_macro_metavar_expr_feature(features, sess, dollar_span2);
|
||||||
}
|
}
|
||||||
TokenTree::token(token::Dollar, span)
|
TokenTree::token(token::Dollar, dollar_span2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// `tree` is followed by some other token. This is an error.
|
// `tree` is followed by some other token. This is an error.
|
||||||
@ -281,7 +289,7 @@ fn parse_tree<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There are no more tokens. Just return the `$` we already have.
|
// There are no more tokens. Just return the `$` we already have.
|
||||||
None => TokenTree::token(token::Dollar, span),
|
None => TokenTree::token(token::Dollar, dollar_span),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,8 +253,23 @@ pub(super) fn transcribe<'a>(
|
|||||||
mbe::TokenTree::MetaVar(mut sp, mut original_ident) => {
|
mbe::TokenTree::MetaVar(mut sp, mut original_ident) => {
|
||||||
// Find the matched nonterminal from the macro invocation, and use it to replace
|
// Find the matched nonterminal from the macro invocation, and use it to replace
|
||||||
// the meta-var.
|
// the meta-var.
|
||||||
|
//
|
||||||
|
// We use `Spacing::Alone` everywhere here, because that's the conservative choice
|
||||||
|
// and spacing of declarative macros is tricky. E.g. in this macro:
|
||||||
|
// ```
|
||||||
|
// macro_rules! idents {
|
||||||
|
// ($($a:ident,)*) => { stringify!($($a)*) }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// `$a` has no whitespace after it and will be marked `JointHidden`. If you then
|
||||||
|
// call `idents!(x,y,z,)`, each of `x`, `y`, and `z` will be marked as `Joint`. So
|
||||||
|
// if you choose to use `$x`'s spacing or the identifier's spacing, you'll end up
|
||||||
|
// producing "xyz", which is bad because it effectively merges tokens.
|
||||||
|
// `Spacing::Alone` is the safer option. Fortunately, `space_between` will avoid
|
||||||
|
// some of the unnecessary whitespace.
|
||||||
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
||||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||||
|
// njn: explain the use of alone here
|
||||||
let tt = match cur_matched {
|
let tt = match cur_matched {
|
||||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||||
|
@ -309,10 +309,10 @@ impl ToInternal<SmallVec<[tokenstream::TokenTree; 2]>>
|
|||||||
use rustc_ast::token::*;
|
use rustc_ast::token::*;
|
||||||
|
|
||||||
// The code below is conservative, using `token_alone`/`Spacing::Alone`
|
// The code below is conservative, using `token_alone`/`Spacing::Alone`
|
||||||
// in most places. When the resulting code is pretty-printed by
|
// in most places. It's hard in general to do better when working at
|
||||||
// `print_tts` it ends up with spaces between most tokens, which is
|
// the token level. When the resulting code is pretty-printed by
|
||||||
// safe but ugly. It's hard in general to do better when working at the
|
// `print_tts` the `space_between` function helps avoid a lot of
|
||||||
// token level.
|
// unnecessary whitespace, so the results aren't too bad.
|
||||||
let (tree, rustc) = self;
|
let (tree, rustc) = self;
|
||||||
match tree {
|
match tree {
|
||||||
TokenTree::Punct(Punct { ch, joint, span }) => {
|
TokenTree::Punct(Punct { ch, joint, span }) => {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
|
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
|
||||||
|
|
||||||
use rustc_ast::visit::walk_list;
|
use rustc_ast::visit::visit_opt;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
@ -168,7 +168,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
|
|||||||
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
|
hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
walk_list!(visitor, visit_expr, &blk.expr);
|
visit_opt!(visitor, visit_expr, &blk.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitor.cx = prev_cx;
|
visitor.cx = prev_cx;
|
||||||
|
@ -1159,7 +1159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let sig = self
|
let sig = self
|
||||||
.at(cause, self.param_env)
|
.at(cause, self.param_env)
|
||||||
.trace(prev_ty, new_ty)
|
.trace(prev_ty, new_ty)
|
||||||
.lub(DefineOpaqueTypes::No, a_sig, b_sig)
|
.lub(DefineOpaqueTypes::Yes, a_sig, b_sig)
|
||||||
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
.map(|ok| self.register_infer_ok_obligations(ok))?;
|
||||||
|
|
||||||
// Reify both sides and return the reified fn pointer type.
|
// Reify both sides and return the reified fn pointer type.
|
||||||
|
@ -49,10 +49,10 @@ use rustc_middle::ty::TyCtxt;
|
|||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
|
pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
#![feature(rustdoc_internals)]
|
#![feature(rustdoc_internals)]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
mod assert_dep_graph;
|
mod assert_dep_graph;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod persist;
|
mod persist;
|
||||||
|
@ -33,6 +33,7 @@ use rustc_middle::ty::TyCtxt;
|
|||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use thin_vec::ThinVec;
|
use thin_vec::ThinVec;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
|
const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
|
||||||
const EXCEPT: Symbol = sym::except;
|
const EXCEPT: Symbol = sym::except;
|
||||||
|
@ -19,6 +19,7 @@ use std::env;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// The first few bytes of files generated by incremental compilation.
|
/// The first few bytes of files generated by incremental compilation.
|
||||||
const FILE_MAGIC: &[u8] = b"RSIC";
|
const FILE_MAGIC: &[u8] = b"RSIC";
|
||||||
|
@ -125,6 +125,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use rand::{thread_rng, RngCore};
|
use rand::{thread_rng, RngCore};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -12,6 +12,7 @@ use rustc_session::Session;
|
|||||||
use rustc_span::ErrorGuaranteed;
|
use rustc_span::ErrorGuaranteed;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
use super::data::*;
|
use super::data::*;
|
||||||
use super::file_format;
|
use super::file_format;
|
||||||
|
@ -11,6 +11,7 @@ use rustc_serialize::Encodable as RustcEncodable;
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use super::data::*;
|
use super::data::*;
|
||||||
use super::dirty_clean;
|
use super::dirty_clean;
|
||||||
|
@ -10,6 +10,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
|||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use std::fs as std_fs;
|
use std::fs as std_fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
/// Copies a CGU work product to the incremental compilation directory, so next compilation can
|
/// Copies a CGU work product to the incremental compilation directory, so next compilation can
|
||||||
/// find and reuse it.
|
/// find and reuse it.
|
||||||
|
@ -104,10 +104,10 @@ infer_compare_impl_item_obligation = ...so that the definition in impl matches t
|
|||||||
infer_consider_specifying_length = consider specifying the actual array length
|
infer_consider_specifying_length = consider specifying the actual array length
|
||||||
infer_data_flows = ...but data{$label_var1_exists ->
|
infer_data_flows = ...but data{$label_var1_exists ->
|
||||||
[true] {" "}from `{$label_var1}`
|
[true] {" "}from `{$label_var1}`
|
||||||
*[false] -> {""}
|
*[false] {""}
|
||||||
} flows{$label_var2_exists ->
|
} flows{$label_var2_exists ->
|
||||||
[true] {" "}into `{$label_var2}`
|
[true] {" "}into `{$label_var2}`
|
||||||
*[false] -> {""}
|
*[false] {""}
|
||||||
} here
|
} here
|
||||||
|
|
||||||
infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
|
infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
|
||||||
|
@ -173,7 +173,10 @@ pub(super) fn note_and_explain_region<'tcx>(
|
|||||||
|
|
||||||
ty::ReError(_) => return,
|
ty::ReError(_) => return,
|
||||||
|
|
||||||
ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
|
// FIXME(#125431): `ReVar` shouldn't reach here.
|
||||||
|
ty::ReVar(_) => (format!("lifetime `{region}`"), alt_span),
|
||||||
|
|
||||||
|
ty::ReBound(..) | ty::ReErased => {
|
||||||
bug!("unexpected region for note_and_explain_region: {:?}", region);
|
bug!("unexpected region for note_and_explain_region: {:?}", region);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@ use rustc_data_structures::sync::Lrc;
|
|||||||
use rustc_errors::registry::Registry;
|
use rustc_errors::registry::Registry;
|
||||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
|
use rustc_errors::{DiagCtxt, ErrorGuaranteed};
|
||||||
use rustc_lint::LintStore;
|
use rustc_lint::LintStore;
|
||||||
|
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_middle::ty::CurrentGcx;
|
use rustc_middle::ty::CurrentGcx;
|
||||||
use rustc_middle::util::Providers;
|
use rustc_middle::util::Providers;
|
||||||
@ -28,6 +27,7 @@ use rustc_span::FileName;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
pub type Result<T> = result::Result<T, ErrorGuaranteed>;
|
pub type Result<T> = result::Result<T, ErrorGuaranteed>;
|
||||||
|
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
#![feature(thread_spawn_unchecked)]
|
#![feature(thread_spawn_unchecked)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
mod callbacks;
|
mod callbacks;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod interface;
|
pub mod interface;
|
||||||
|
@ -39,6 +39,7 @@ use std::io::{self, BufWriter, Write};
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use std::{env, fs, iter};
|
use std::{env, fs, iter};
|
||||||
|
use tracing::{info, instrument};
|
||||||
|
|
||||||
pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
|
pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
|
||||||
let krate = sess.time("parse_crate", || match &sess.io.input {
|
let krate = sess.time("parse_crate", || match &sess.io.input {
|
||||||
@ -458,7 +459,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for &cnum in tcx.crates(()) {
|
for &cnum in tcx.crates_including_speculative(()) {
|
||||||
let source = tcx.used_crate_source(cnum);
|
let source = tcx.used_crate_source(cnum);
|
||||||
if let Some((path, _)) = &source.dylib {
|
if let Some((path, _)) = &source.dylib {
|
||||||
files.push(escape_dep_filename(&path.display().to_string()));
|
files.push(escape_dep_filename(&path.display().to_string()));
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user