Auto merge of #69105 - Dylan-DPC:rollup-n73lh5h, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #67954 (Support new LLVM pass manager) - #68981 ( Account for type params on method without parentheses) - #69002 (miri: improve and simplify overflow detection) - #69038 (Add initial debug fmt for Backtrace) - #69040 (Cleanup SGX entry code) - #69086 (Update compiler-builtins to 0.1.25) - #69095 (Minified theme check) Failed merges: r? @ghost
This commit is contained in:
commit
92d8e82f6b
34 changed files with 892 additions and 179 deletions
|
@ -576,9 +576,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.24"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9975aefa63997ef75ca9cf013ff1bb81487aaa0b622c21053afd3b92979a7af"
|
||||
checksum = "438ac08ddc5efe81452f984a9e33ba425b00b31d1f48e6acd9e2210aa28cc52e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
|
@ -584,6 +584,20 @@ pub(crate) fn run_pass_manager(
|
|||
// tools/lto/LTOCodeGenerator.cpp
|
||||
debug!("running the pass manager");
|
||||
unsafe {
|
||||
if write::should_use_new_llvm_pass_manager(config) {
|
||||
let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
|
||||
let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
|
||||
// See comment below for why this is necessary.
|
||||
let opt_level = if let config::OptLevel::No = opt_level {
|
||||
config::OptLevel::Less
|
||||
} else {
|
||||
opt_level
|
||||
};
|
||||
write::optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
|
||||
debug!("lto done");
|
||||
return;
|
||||
}
|
||||
|
||||
let pm = llvm::LLVMCreatePassManager();
|
||||
llvm::LLVMAddAnalysisPasses(module.module_llvm.tm, pm);
|
||||
|
||||
|
|
|
@ -111,6 +111,18 @@ pub fn to_llvm_opt_settings(
|
|||
}
|
||||
}
|
||||
|
||||
fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel {
|
||||
use config::OptLevel::*;
|
||||
match cfg {
|
||||
No => llvm::PassBuilderOptLevel::O0,
|
||||
Less => llvm::PassBuilderOptLevel::O1,
|
||||
Default => llvm::PassBuilderOptLevel::O2,
|
||||
Aggressive => llvm::PassBuilderOptLevel::O3,
|
||||
Size => llvm::PassBuilderOptLevel::Os,
|
||||
SizeMin => llvm::PassBuilderOptLevel::Oz,
|
||||
}
|
||||
}
|
||||
|
||||
// If find_features is true this won't access `sess.crate_types` by assuming
|
||||
// that `is_pie_binary` is false. When we discover LLVM target features
|
||||
// `sess.crate_types` is uninitialized so we cannot access it.
|
||||
|
@ -303,6 +315,88 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
|||
}
|
||||
}
|
||||
|
||||
fn get_pgo_gen_path(config: &ModuleConfig) -> Option<CString> {
|
||||
match config.pgo_gen {
|
||||
SwitchWithOptPath::Enabled(ref opt_dir_path) => {
|
||||
let path = if let Some(dir_path) = opt_dir_path {
|
||||
dir_path.join("default_%m.profraw")
|
||||
} else {
|
||||
PathBuf::from("default_%m.profraw")
|
||||
};
|
||||
|
||||
Some(CString::new(format!("{}", path.display())).unwrap())
|
||||
}
|
||||
SwitchWithOptPath::Disabled => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pgo_use_path(config: &ModuleConfig) -> Option<CString> {
|
||||
config
|
||||
.pgo_use
|
||||
.as_ref()
|
||||
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
|
||||
// We only support the new pass manager starting with LLVM 9.
|
||||
if llvm_util::get_major_version() < 9 {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The new pass manager is disabled by default.
|
||||
config.new_llvm_pass_manager.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
|
||||
module: &ModuleCodegen<ModuleLlvm>,
|
||||
config: &ModuleConfig,
|
||||
opt_level: config::OptLevel,
|
||||
opt_stage: llvm::OptStage,
|
||||
) {
|
||||
let unroll_loops =
|
||||
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
|
||||
let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
|
||||
let pgo_gen_path = get_pgo_gen_path(config);
|
||||
let pgo_use_path = get_pgo_use_path(config);
|
||||
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
|
||||
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
|
||||
let sanitizer_options = if !is_lto {
|
||||
config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions {
|
||||
sanitize_memory: *s == Sanitizer::Memory,
|
||||
sanitize_thread: *s == Sanitizer::Thread,
|
||||
sanitize_address: *s == Sanitizer::Address,
|
||||
sanitize_recover: config.sanitizer_recover.contains(s),
|
||||
sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
|
||||
// We would have to add upstream support for this first, before we can support
|
||||
// config.inline_threshold and our more aggressive default thresholds.
|
||||
// FIXME: NewPM uses an different and more explicit way to textually represent
|
||||
// pass pipelines. It would probably make sense to expose this, but it would
|
||||
// require a different format than the current -C passes.
|
||||
llvm::LLVMRustOptimizeWithNewPassManager(
|
||||
module.module_llvm.llmod(),
|
||||
&*module.module_llvm.tm,
|
||||
to_pass_builder_opt_level(opt_level),
|
||||
opt_stage,
|
||||
config.no_prepopulate_passes,
|
||||
config.verify_llvm_ir,
|
||||
using_thin_buffers,
|
||||
config.merge_functions,
|
||||
unroll_loops,
|
||||
config.vectorize_slp,
|
||||
config.vectorize_loop,
|
||||
config.no_builtins,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
);
|
||||
}
|
||||
|
||||
// Unsafe due to LLVM calls.
|
||||
pub(crate) unsafe fn optimize(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
|
@ -327,6 +421,17 @@ pub(crate) unsafe fn optimize(
|
|||
}
|
||||
|
||||
if let Some(opt_level) = config.opt_level {
|
||||
if should_use_new_llvm_pass_manager(config) {
|
||||
let opt_stage = match cgcx.lto {
|
||||
Lto::Fat => llvm::OptStage::PreLinkFatLTO,
|
||||
Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
|
||||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Create the two optimizing pass managers. These mirror what clang
|
||||
// does, and are by populated by LLVM's default PassManagerBuilder.
|
||||
// Each manager has a different set of passes, but they also share
|
||||
|
@ -757,24 +862,8 @@ pub unsafe fn with_llvm_pmb(
|
|||
let opt_size =
|
||||
config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone);
|
||||
let inline_threshold = config.inline_threshold;
|
||||
|
||||
let pgo_gen_path = match config.pgo_gen {
|
||||
SwitchWithOptPath::Enabled(ref opt_dir_path) => {
|
||||
let path = if let Some(dir_path) = opt_dir_path {
|
||||
dir_path.join("default_%m.profraw")
|
||||
} else {
|
||||
PathBuf::from("default_%m.profraw")
|
||||
};
|
||||
|
||||
Some(CString::new(format!("{}", path.display())).unwrap())
|
||||
}
|
||||
SwitchWithOptPath::Disabled => None,
|
||||
};
|
||||
|
||||
let pgo_use_path = config
|
||||
.pgo_use
|
||||
.as_ref()
|
||||
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap());
|
||||
let pgo_gen_path = get_pgo_gen_path(config);
|
||||
let pgo_use_path = get_pgo_use_path(config);
|
||||
|
||||
llvm::LLVMRustConfigurePassManagerBuilder(
|
||||
builder,
|
||||
|
|
|
@ -781,13 +781,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
align: Align,
|
||||
flags: MemFlags,
|
||||
) {
|
||||
let ptr_width = &self.sess().target.target.target_pointer_width;
|
||||
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
|
||||
let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
|
||||
let is_volatile = flags.contains(MemFlags::VOLATILE);
|
||||
let ptr = self.pointercast(ptr, self.type_i8p());
|
||||
let align = self.const_u32(align.bytes() as u32);
|
||||
let volatile = self.const_bool(flags.contains(MemFlags::VOLATILE));
|
||||
self.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None);
|
||||
unsafe {
|
||||
llvm::LLVMRustBuildMemSet(
|
||||
self.llbuilder,
|
||||
ptr,
|
||||
align.bytes() as c_uint,
|
||||
fill_byte,
|
||||
size,
|
||||
is_volatile,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn select(
|
||||
|
@ -985,11 +990,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
|
||||
}
|
||||
|
||||
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
|
||||
}
|
||||
|
||||
fn call(
|
||||
|
|
|
@ -562,10 +562,6 @@ impl CodegenCx<'b, 'tcx> {
|
|||
t_v8f64: t_f64, 8;
|
||||
}
|
||||
|
||||
ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
|
||||
ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
|
||||
ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
|
||||
|
||||
ifn!("llvm.trap", fn() -> void);
|
||||
ifn!("llvm.debugtrap", fn() -> void);
|
||||
ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
|
||||
|
@ -830,8 +826,8 @@ impl CodegenCx<'b, 'tcx> {
|
|||
ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.lifetime.start", fn(t_i64, i8p) -> void);
|
||||
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
|
||||
ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
|
||||
ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
|
||||
|
||||
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
|
||||
ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
|
||||
|
|
|
@ -402,6 +402,38 @@ pub enum CodeGenOptLevel {
|
|||
Aggressive,
|
||||
}
|
||||
|
||||
/// LLVMRustPassBuilderOptLevel
|
||||
#[repr(C)]
|
||||
pub enum PassBuilderOptLevel {
|
||||
O0,
|
||||
O1,
|
||||
O2,
|
||||
O3,
|
||||
Os,
|
||||
Oz,
|
||||
}
|
||||
|
||||
/// LLVMRustOptStage
|
||||
#[derive(PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum OptStage {
|
||||
PreLinkNoLTO,
|
||||
PreLinkThinLTO,
|
||||
PreLinkFatLTO,
|
||||
ThinLTO,
|
||||
FatLTO,
|
||||
}
|
||||
|
||||
/// LLVMRustSanitizerOptions
|
||||
#[repr(C)]
|
||||
pub struct SanitizerOptions {
|
||||
pub sanitize_memory: bool,
|
||||
pub sanitize_thread: bool,
|
||||
pub sanitize_address: bool,
|
||||
pub sanitize_recover: bool,
|
||||
pub sanitize_memory_track_origins: c_int,
|
||||
}
|
||||
|
||||
/// LLVMRelocMode
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
|
@ -1316,6 +1348,14 @@ extern "C" {
|
|||
Size: &'a Value,
|
||||
IsVolatile: bool,
|
||||
) -> &'a Value;
|
||||
pub fn LLVMRustBuildMemSet(
|
||||
B: &Builder<'a>,
|
||||
Dst: &'a Value,
|
||||
DstAlign: c_uint,
|
||||
Val: &'a Value,
|
||||
Size: &'a Value,
|
||||
IsVolatile: bool,
|
||||
) -> &'a Value;
|
||||
pub fn LLVMBuildSelect(
|
||||
B: &Builder<'a>,
|
||||
If: &'a Value,
|
||||
|
@ -1889,6 +1929,23 @@ extern "C" {
|
|||
Output: *const c_char,
|
||||
FileType: FileType,
|
||||
) -> LLVMRustResult;
|
||||
pub fn LLVMRustOptimizeWithNewPassManager(
|
||||
M: &'a Module,
|
||||
TM: &'a TargetMachine,
|
||||
OptLevel: PassBuilderOptLevel,
|
||||
OptStage: OptStage,
|
||||
NoPrepopulatePasses: bool,
|
||||
VerifyIR: bool,
|
||||
UseThinLTOBuffers: bool,
|
||||
MergeFunctions: bool,
|
||||
UnrollLoops: bool,
|
||||
SLPVectorize: bool,
|
||||
LoopVectorize: bool,
|
||||
DisableSimplifyLibCalls: bool,
|
||||
SanitizerOptions: Option<&SanitizerOptions>,
|
||||
PGOGenPath: *const c_char,
|
||||
PGOUsePath: *const c_char,
|
||||
);
|
||||
pub fn LLVMRustPrintModule(
|
||||
M: &'a Module,
|
||||
Output: *const c_char,
|
||||
|
|
|
@ -88,6 +88,7 @@ pub struct ModuleConfig {
|
|||
pub vectorize_slp: bool,
|
||||
pub merge_functions: bool,
|
||||
pub inline_threshold: Option<usize>,
|
||||
pub new_llvm_pass_manager: Option<bool>,
|
||||
// Instead of creating an object file by doing LLVM codegen, just
|
||||
// make the object file bitcode. Provides easy compatibility with
|
||||
// emscripten's ecc compiler, when used as the linker.
|
||||
|
@ -132,6 +133,7 @@ impl ModuleConfig {
|
|||
vectorize_slp: false,
|
||||
merge_functions: false,
|
||||
inline_threshold: None,
|
||||
new_llvm_pass_manager: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +142,7 @@ impl ModuleConfig {
|
|||
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
|
||||
self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
|
||||
self.inline_threshold = sess.opts.cg.inline_threshold;
|
||||
self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
|
||||
self.obj_is_bitcode =
|
||||
sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
|
||||
let embed_bitcode =
|
||||
|
|
|
@ -134,9 +134,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let mut r = r as u32;
|
||||
let size = left_layout.size;
|
||||
oflo |= r >= size.bits() as u32;
|
||||
if oflo {
|
||||
r %= size.bits() as u32;
|
||||
}
|
||||
r %= size.bits() as u32;
|
||||
let result = if signed {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let result = match bin_op {
|
||||
|
@ -168,6 +166,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
)
|
||||
}
|
||||
|
||||
let size = left_layout.size;
|
||||
|
||||
// Operations that need special treatment for signed integers
|
||||
if left_layout.abi.is_signed() {
|
||||
let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
|
||||
|
@ -195,32 +195,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
if let Some(op) = op {
|
||||
let l128 = self.sign_extend(l, left_layout) as i128;
|
||||
let r = self.sign_extend(r, right_layout) as i128;
|
||||
let size = left_layout.size;
|
||||
// We need a special check for overflowing remainder:
|
||||
// "int_min % -1" overflows and returns 0, but after casting things to a larger int
|
||||
// type it does *not* overflow nor give an unrepresentable result!
|
||||
match bin_op {
|
||||
Rem | Div => {
|
||||
// int_min / -1
|
||||
Rem => {
|
||||
if r == -1 && l == (1 << (size.bits() - 1)) {
|
||||
return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
|
||||
return Ok((Scalar::from_int(0, size), true, left_layout.ty));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
trace!("{}, {}, {}", l, l128, r);
|
||||
let (result, mut oflo) = op(l128, r);
|
||||
trace!("{}, {}", result, oflo);
|
||||
if !oflo && size.bits() != 128 {
|
||||
let max = 1 << (size.bits() - 1);
|
||||
oflo = result >= max || result < -max;
|
||||
}
|
||||
// this may be out-of-bounds for the result type, so we have to truncate ourselves
|
||||
|
||||
let (result, oflo) = op(l128, r);
|
||||
// This may be out-of-bounds for the result type, so we have to truncate ourselves.
|
||||
// If that truncation loses any information, we have an overflow.
|
||||
let result = result as u128;
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||
return Ok((
|
||||
Scalar::from_uint(truncated, size),
|
||||
oflo || self.sign_extend(truncated, left_layout) != result,
|
||||
left_layout.ty,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let size = left_layout.size;
|
||||
|
||||
let (val, ty) = match bin_op {
|
||||
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||
|
@ -247,6 +246,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
_ => bug!(),
|
||||
};
|
||||
let (result, oflo) = op(l, r);
|
||||
// Truncate to target type.
|
||||
// If that truncation loses any information, we have an overflow.
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((
|
||||
Scalar::from_uint(truncated, size),
|
||||
|
@ -341,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
|
||||
/// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows.
|
||||
#[inline]
|
||||
pub fn binary_op(
|
||||
&self,
|
||||
|
@ -353,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||
}
|
||||
|
||||
pub fn unary_op(
|
||||
/// Returns the result of the specified operation, whether it overflowed, and
|
||||
/// the result type.
|
||||
pub fn overflowing_unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
|
||||
use rustc::mir::UnOp::*;
|
||||
|
||||
let layout = val.layout;
|
||||
|
@ -371,7 +374,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Not => !val,
|
||||
_ => bug!("Invalid bool op {:?}", un_op),
|
||||
};
|
||||
Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
|
||||
Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
let res = match (un_op, fty) {
|
||||
|
@ -379,21 +382,36 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||
_ => bug!("Invalid float op {:?}", un_op),
|
||||
};
|
||||
Ok(ImmTy::from_scalar(res, layout))
|
||||
Ok((res, false, layout.ty))
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
let val = self.force_bits(val, layout.size)?;
|
||||
let res = match un_op {
|
||||
Not => !val,
|
||||
let (res, overflow) = match un_op {
|
||||
Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate
|
||||
Neg => {
|
||||
// arithmetic negation
|
||||
assert!(layout.abi.is_signed());
|
||||
(-(val as i128)) as u128
|
||||
let val = self.sign_extend(val, layout) as i128;
|
||||
let (res, overflow) = val.overflowing_neg();
|
||||
let res = res as u128;
|
||||
// Truncate to target type.
|
||||
// If that truncation loses any information, we have an overflow.
|
||||
let truncated = self.truncate(res, layout);
|
||||
(truncated, overflow || self.sign_extend(truncated, layout) != res)
|
||||
}
|
||||
};
|
||||
// res needs tuncating
|
||||
Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
|
||||
Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
|
||||
let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
|
||||
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -518,18 +518,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_unary_op(&mut self, arg: &Operand<'tcx>, source_info: SourceInfo) -> Option<()> {
|
||||
fn check_unary_op(
|
||||
&mut self,
|
||||
op: UnOp,
|
||||
arg: &Operand<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
) -> Option<()> {
|
||||
self.use_ecx(source_info, |this| {
|
||||
let ty = arg.ty(&this.local_decls, this.tcx);
|
||||
let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
|
||||
let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
|
||||
|
||||
if ty.is_integral() {
|
||||
let arg = this.ecx.eval_operand(arg, None)?;
|
||||
let prim = this.ecx.read_immediate(arg)?;
|
||||
// Need to do overflow check here: For actual CTFE, MIR
|
||||
// generation emits code that does this before calling the op.
|
||||
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
|
||||
throw_panic!(OverflowNeg)
|
||||
}
|
||||
if overflow {
|
||||
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
|
||||
throw_panic!(OverflowNeg);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -576,11 +577,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
if !overflow_check {
|
||||
self.use_ecx(source_info, |this| {
|
||||
let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
|
||||
let (_, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
|
||||
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
|
||||
|
||||
if overflow {
|
||||
let err = err_panic!(Overflow(op)).into();
|
||||
return Err(err);
|
||||
throw_panic!(Overflow(op));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -620,9 +620,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
// Additional checking: if overflow checks are disabled (which is usually the case in
|
||||
// release mode), then we need to do additional checking here to give lints to the user
|
||||
// if an overflow would occur.
|
||||
Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => {
|
||||
trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
|
||||
self.check_unary_op(arg, source_info)?;
|
||||
Rvalue::UnaryOp(op, arg) if !overflow_check => {
|
||||
trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
|
||||
self.check_unary_op(*op, arg, source_info)?;
|
||||
}
|
||||
|
||||
// Additional checking: check for overflows on integer binary operations and report
|
||||
|
|
|
@ -823,7 +823,7 @@ impl<'a> Parser<'a> {
|
|||
if let Some(args) = segment.args {
|
||||
self.struct_span_err(
|
||||
args.span(),
|
||||
"field expressions may not have generic arguments",
|
||||
"field expressions cannot have generic arguments",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
|
@ -968,4 +968,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"compile without linking"),
|
||||
link_only: bool = (false, parse_bool, [TRACKED],
|
||||
"link the `.rlink` file generated by `-Z no-link`"),
|
||||
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"use new LLVM pass manager"),
|
||||
}
|
||||
|
|
|
@ -1586,7 +1586,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&format!("a method `{}` also exists, call it with parentheses", field),
|
||||
field,
|
||||
expr_t,
|
||||
expr.hir_id,
|
||||
expr,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
|
@ -1609,7 +1609,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
"use parentheses to call the method",
|
||||
field,
|
||||
expr_t,
|
||||
expr.hir_id,
|
||||
expr,
|
||||
);
|
||||
} else {
|
||||
err.help("methods are immutable and cannot be assigned to");
|
||||
|
|
|
@ -135,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
msg: &str,
|
||||
method_name: ast::Ident,
|
||||
self_ty: Ty<'tcx>,
|
||||
call_expr_id: hir::HirId,
|
||||
call_expr: &hir::Expr<'_>,
|
||||
) {
|
||||
let has_params = self
|
||||
.probe_for_name(
|
||||
|
@ -144,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
method_name,
|
||||
IsSuggestion(false),
|
||||
self_ty,
|
||||
call_expr_id,
|
||||
call_expr.hir_id,
|
||||
ProbeScope::TraitsInScope,
|
||||
)
|
||||
.and_then(|pick| {
|
||||
|
@ -152,13 +152,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Ok(sig.inputs().skip_binder().len() > 1)
|
||||
});
|
||||
|
||||
// Account for `foo.bar<T>`;
|
||||
let sugg_span = method_name.span.with_hi(call_expr.span.hi());
|
||||
let snippet = self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(sugg_span)
|
||||
.unwrap_or_else(|_| method_name.to_string());
|
||||
let (suggestion, applicability) = if has_params.unwrap_or_default() {
|
||||
(format!("{}(...)", method_name), Applicability::HasPlaceholders)
|
||||
(format!("{}(...)", snippet), Applicability::HasPlaceholders)
|
||||
} else {
|
||||
(format!("{}()", method_name), Applicability::MaybeIncorrect)
|
||||
(format!("{}()", snippet), Applicability::MaybeIncorrect)
|
||||
};
|
||||
|
||||
err.span_suggestion(method_name.span, msg, suggestion, applicability);
|
||||
err.span_suggestion(sugg_span, msg, suggestion, applicability);
|
||||
}
|
||||
|
||||
/// Performs method lookup. If lookup is successful, it will return the callee
|
||||
|
|
|
@ -179,20 +179,23 @@ fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
|
|||
}
|
||||
|
||||
fn build_rule(v: &[u8], positions: &[usize]) -> String {
|
||||
positions
|
||||
.chunks(2)
|
||||
.map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
|
||||
.collect::<String>()
|
||||
.trim()
|
||||
.replace("\n", " ")
|
||||
.replace("/", "")
|
||||
.replace("\t", " ")
|
||||
.replace("{", "")
|
||||
.replace("}", "")
|
||||
.split(' ')
|
||||
.filter(|s| s.len() > 0)
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" ")
|
||||
minifier::css::minify(
|
||||
&positions
|
||||
.chunks(2)
|
||||
.map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
|
||||
.collect::<String>()
|
||||
.trim()
|
||||
.replace("\n", " ")
|
||||
.replace("/", "")
|
||||
.replace("\t", " ")
|
||||
.replace("{", "")
|
||||
.replace("}", "")
|
||||
.split(' ')
|
||||
.filter(|s| s.len() > 0)
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" "),
|
||||
)
|
||||
.unwrap_or_else(|_| String::new())
|
||||
}
|
||||
|
||||
fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {
|
||||
|
|
|
@ -102,3 +102,16 @@ fn check_invalid_css() {
|
|||
let events = load_css_events(b"*");
|
||||
assert_eq!(events.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_minification() {
|
||||
let text = include_str!("../html/static/themes/dark.css");
|
||||
let minified = minifier::css::minify(&text).expect("CSS minification failed");
|
||||
|
||||
let against = load_css_paths(text.as_bytes());
|
||||
let other = load_css_paths(minified.as_bytes());
|
||||
|
||||
let mut ret = Vec::new();
|
||||
get_differences(&against, &other, &mut ret);
|
||||
assert!(ret.is_empty());
|
||||
}
|
||||
|
|
|
@ -159,6 +159,69 @@ enum BytesOrWide {
|
|||
Wide(Vec<u16>),
|
||||
}
|
||||
|
||||
impl fmt::Debug for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut capture = match &self.inner {
|
||||
Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
|
||||
Inner::Disabled => return fmt.write_str("disabled backtrace"),
|
||||
Inner::Captured(c) => c.lock().unwrap(),
|
||||
};
|
||||
capture.resolve();
|
||||
|
||||
let frames = &capture.frames[capture.actual_start..];
|
||||
|
||||
write!(fmt, "Backtrace ")?;
|
||||
|
||||
let mut dbg = fmt.debug_list();
|
||||
|
||||
for frame in frames {
|
||||
if frame.frame.ip().is_null() {
|
||||
continue;
|
||||
}
|
||||
|
||||
dbg.entries(&frame.symbols);
|
||||
}
|
||||
|
||||
dbg.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BacktraceSymbol {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "{{ ")?;
|
||||
|
||||
if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
|
||||
write!(fmt, "fn: \"{:#}\"", fn_name)?;
|
||||
} else {
|
||||
write!(fmt, "fn: \"<unknown>\"")?;
|
||||
}
|
||||
|
||||
if let Some(fname) = self.filename.as_ref() {
|
||||
write!(fmt, ", file: {:?}", fname)?;
|
||||
}
|
||||
|
||||
if let Some(line) = self.lineno.as_ref() {
|
||||
write!(fmt, ", line: {:?}", line)?;
|
||||
}
|
||||
|
||||
write!(fmt, " }}")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BytesOrWide {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
output_filename(
|
||||
fmt,
|
||||
match self {
|
||||
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
|
||||
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
|
||||
},
|
||||
backtrace::PrintFmt::Short,
|
||||
crate::env::current_dir().as_ref().ok(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Backtrace {
|
||||
/// Returns whether backtrace captures are enabled through environment
|
||||
/// variables.
|
||||
|
@ -267,12 +330,6 @@ impl Backtrace {
|
|||
}
|
||||
|
||||
impl fmt::Display for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Backtrace {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut capture = match &self.inner {
|
||||
Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
|
||||
|
|
|
@ -30,6 +30,14 @@ IMAGE_BASE:
|
|||
|
||||
/* We can store a bunch of data in the gap between MXCSR and the XSAVE header */
|
||||
|
||||
/* MXCSR initialization value for ABI */
|
||||
.Lmxcsr_init:
|
||||
.int 0x1f80
|
||||
|
||||
/* x87 FPU control word initialization value for ABI */
|
||||
.Lfpucw_init:
|
||||
.int 0x037f
|
||||
|
||||
/* The following symbols point at read-only data that will be filled in by the */
|
||||
/* post-linker. */
|
||||
|
||||
|
@ -134,6 +142,19 @@ elf_entry:
|
|||
ud2 /* should not be reached */
|
||||
/* end elf_entry */
|
||||
|
||||
/* This code needs to be called *after* the enclave stack has been setup. */
|
||||
/* There are 3 places where this needs to happen, so this is put in a macro. */
|
||||
.macro entry_sanitize_final
|
||||
/* Sanitize rflags received from user */
|
||||
/* - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
|
||||
/* - AC flag: AEX on misaligned memory accesses leaks side channel info */
|
||||
pushfq
|
||||
andq $~0x40400, (%rsp)
|
||||
popfq
|
||||
bt $0,.Laborted(%rip)
|
||||
jc .Lreentry_panic
|
||||
.endm
|
||||
|
||||
.text
|
||||
.global sgx_entry
|
||||
.type sgx_entry,function
|
||||
|
@ -150,25 +171,18 @@ sgx_entry:
|
|||
stmxcsr %gs:tcsls_user_mxcsr
|
||||
fnstcw %gs:tcsls_user_fcw
|
||||
|
||||
/* reset user state */
|
||||
/* - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
|
||||
/* - AC flag: AEX on misaligned memory accesses leaks side channel info */
|
||||
pushfq
|
||||
andq $~0x40400, (%rsp)
|
||||
popfq
|
||||
|
||||
/* check for debug buffer pointer */
|
||||
testb $0xff,DEBUG(%rip)
|
||||
jz .Lskip_debug_init
|
||||
mov %r10,%gs:tcsls_debug_panic_buf_ptr
|
||||
.Lskip_debug_init:
|
||||
/* check for abort */
|
||||
bt $0,.Laborted(%rip)
|
||||
jc .Lreentry_panic
|
||||
/* check if returning from usercall */
|
||||
mov %gs:tcsls_last_rsp,%r11
|
||||
test %r11,%r11
|
||||
jnz .Lusercall_ret
|
||||
/* reset user state */
|
||||
ldmxcsr .Lmxcsr_init(%rip)
|
||||
fldcw .Lfpucw_init(%rip)
|
||||
/* setup stack */
|
||||
mov %gs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */
|
||||
/* here. This is fixed below under "adjust stack". */
|
||||
|
@ -179,6 +193,7 @@ sgx_entry:
|
|||
lea IMAGE_BASE(%rip),%rax
|
||||
add %rax,%rsp
|
||||
mov %rsp,%gs:tcsls_tos
|
||||
entry_sanitize_final
|
||||
/* call tcs_init */
|
||||
/* store caller-saved registers in callee-saved registers */
|
||||
mov %rdi,%rbx
|
||||
|
@ -194,7 +209,10 @@ sgx_entry:
|
|||
mov %r13,%rdx
|
||||
mov %r14,%r8
|
||||
mov %r15,%r9
|
||||
jmp .Lafter_init
|
||||
.Lskip_init:
|
||||
entry_sanitize_final
|
||||
.Lafter_init:
|
||||
/* call into main entry point */
|
||||
load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
|
||||
call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
|
||||
|
@ -295,6 +313,7 @@ usercall:
|
|||
ldmxcsr (%rsp)
|
||||
fldcw 4(%rsp)
|
||||
add $8, %rsp
|
||||
entry_sanitize_final
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
pop %r12
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/AssemblyAnnotationWriter.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#if LLVM_VERSION_GE(9, 0)
|
||||
#include "llvm/Passes/StandardInstrumentations.h"
|
||||
#endif
|
||||
#include "llvm/Support/CBindingWrapping.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
|
@ -32,9 +37,12 @@
|
|||
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
|
||||
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
|
||||
#endif
|
||||
#if LLVM_VERSION_GE(9, 0)
|
||||
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
|
||||
#endif
|
||||
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::legacy;
|
||||
|
||||
typedef struct LLVMOpaquePass *LLVMPassRef;
|
||||
typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
|
||||
|
@ -314,6 +322,34 @@ static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
|
|||
}
|
||||
}
|
||||
|
||||
enum class LLVMRustPassBuilderOptLevel {
|
||||
O0,
|
||||
O1,
|
||||
O2,
|
||||
O3,
|
||||
Os,
|
||||
Oz,
|
||||
};
|
||||
|
||||
static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
|
||||
switch (Level) {
|
||||
case LLVMRustPassBuilderOptLevel::O0:
|
||||
return PassBuilder::O0;
|
||||
case LLVMRustPassBuilderOptLevel::O1:
|
||||
return PassBuilder::O1;
|
||||
case LLVMRustPassBuilderOptLevel::O2:
|
||||
return PassBuilder::O2;
|
||||
case LLVMRustPassBuilderOptLevel::O3:
|
||||
return PassBuilder::O3;
|
||||
case LLVMRustPassBuilderOptLevel::Os:
|
||||
return PassBuilder::Os;
|
||||
case LLVMRustPassBuilderOptLevel::Oz:
|
||||
return PassBuilder::Oz;
|
||||
default:
|
||||
report_fatal_error("Bad PassBuilderOptLevel.");
|
||||
}
|
||||
}
|
||||
|
||||
enum class LLVMRustRelocMode {
|
||||
Default,
|
||||
Static,
|
||||
|
@ -604,6 +640,212 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
|
|||
return LLVMRustResult::Success;
|
||||
}
|
||||
|
||||
enum class LLVMRustOptStage {
|
||||
PreLinkNoLTO,
|
||||
PreLinkThinLTO,
|
||||
PreLinkFatLTO,
|
||||
ThinLTO,
|
||||
FatLTO,
|
||||
};
|
||||
|
||||
struct LLVMRustSanitizerOptions {
|
||||
bool SanitizeMemory;
|
||||
bool SanitizeThread;
|
||||
bool SanitizeAddress;
|
||||
bool SanitizeRecover;
|
||||
int SanitizeMemoryTrackOrigins;
|
||||
};
|
||||
|
||||
extern "C" void
|
||||
LLVMRustOptimizeWithNewPassManager(
|
||||
LLVMModuleRef ModuleRef,
|
||||
LLVMTargetMachineRef TMRef,
|
||||
LLVMRustPassBuilderOptLevel OptLevelRust,
|
||||
LLVMRustOptStage OptStage,
|
||||
bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
|
||||
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
|
||||
bool DisableSimplifyLibCalls,
|
||||
LLVMRustSanitizerOptions *SanitizerOptions,
|
||||
const char *PGOGenPath, const char *PGOUsePath) {
|
||||
#if LLVM_VERSION_GE(9, 0)
|
||||
Module *TheModule = unwrap(ModuleRef);
|
||||
TargetMachine *TM = unwrap(TMRef);
|
||||
PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust);
|
||||
|
||||
// FIXME: MergeFunctions is not supported by NewPM yet.
|
||||
(void) MergeFunctions;
|
||||
|
||||
PipelineTuningOptions PTO;
|
||||
PTO.LoopUnrolling = UnrollLoops;
|
||||
PTO.LoopInterleaving = UnrollLoops;
|
||||
PTO.LoopVectorization = LoopVectorize;
|
||||
PTO.SLPVectorization = SLPVectorize;
|
||||
|
||||
PassInstrumentationCallbacks PIC;
|
||||
StandardInstrumentations SI;
|
||||
SI.registerCallbacks(PIC);
|
||||
|
||||
Optional<PGOOptions> PGOOpt;
|
||||
if (PGOGenPath) {
|
||||
assert(!PGOUsePath);
|
||||
PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr);
|
||||
} else if (PGOUsePath) {
|
||||
assert(!PGOGenPath);
|
||||
PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse);
|
||||
}
|
||||
|
||||
PassBuilder PB(TM, PTO, PGOOpt, &PIC);
|
||||
|
||||
// FIXME: We may want to expose this as an option.
|
||||
bool DebugPassManager = false;
|
||||
LoopAnalysisManager LAM(DebugPassManager);
|
||||
FunctionAnalysisManager FAM(DebugPassManager);
|
||||
CGSCCAnalysisManager CGAM(DebugPassManager);
|
||||
ModuleAnalysisManager MAM(DebugPassManager);
|
||||
|
||||
FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
|
||||
|
||||
Triple TargetTriple(TheModule->getTargetTriple());
|
||||
std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
|
||||
if (DisableSimplifyLibCalls)
|
||||
TLII->disableAllFunctions();
|
||||
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
|
||||
|
||||
PB.registerModuleAnalyses(MAM);
|
||||
PB.registerCGSCCAnalyses(CGAM);
|
||||
PB.registerFunctionAnalyses(FAM);
|
||||
PB.registerLoopAnalyses(LAM);
|
||||
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
|
||||
|
||||
// We manually collect pipeline callbacks so we can apply them at O0, where the
|
||||
// PassBuilder does not create a pipeline.
|
||||
std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks;
|
||||
std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
|
||||
OptimizerLastEPCallbacks;
|
||||
|
||||
if (VerifyIR) {
|
||||
PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) {
|
||||
MPM.addPass(VerifierPass());
|
||||
});
|
||||
}
|
||||
|
||||
if (SanitizerOptions) {
|
||||
if (SanitizerOptions->SanitizeMemory) {
|
||||
MemorySanitizerOptions Options(
|
||||
SanitizerOptions->SanitizeMemoryTrackOrigins,
|
||||
SanitizerOptions->SanitizeRecover,
|
||||
/*CompileKernel=*/false);
|
||||
#if LLVM_VERSION_GE(10, 0)
|
||||
PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
|
||||
MPM.addPass(MemorySanitizerPass(Options));
|
||||
});
|
||||
#endif
|
||||
OptimizerLastEPCallbacks.push_back(
|
||||
[Options](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
|
||||
FPM.addPass(MemorySanitizerPass(Options));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (SanitizerOptions->SanitizeThread) {
|
||||
#if LLVM_VERSION_GE(10, 0)
|
||||
PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) {
|
||||
MPM.addPass(ThreadSanitizerPass());
|
||||
});
|
||||
#endif
|
||||
OptimizerLastEPCallbacks.push_back(
|
||||
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
|
||||
FPM.addPass(ThreadSanitizerPass());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (SanitizerOptions->SanitizeAddress) {
|
||||
// FIXME: Rust does not expose the UseAfterScope option.
|
||||
PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
|
||||
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
|
||||
});
|
||||
OptimizerLastEPCallbacks.push_back(
|
||||
[SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
|
||||
FPM.addPass(AddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
|
||||
}
|
||||
);
|
||||
PipelineStartEPCallbacks.push_back(
|
||||
[SanitizerOptions](ModulePassManager &MPM) {
|
||||
MPM.addPass(ModuleAddressSanitizerPass(
|
||||
/*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ModulePassManager MPM(DebugPassManager);
|
||||
if (!NoPrepopulatePasses) {
|
||||
if (OptLevel == PassBuilder::O0) {
|
||||
for (const auto &C : PipelineStartEPCallbacks)
|
||||
C(MPM);
|
||||
|
||||
if (!OptimizerLastEPCallbacks.empty()) {
|
||||
FunctionPassManager FPM(DebugPassManager);
|
||||
for (const auto &C : OptimizerLastEPCallbacks)
|
||||
C(FPM, OptLevel);
|
||||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
|
||||
}
|
||||
|
||||
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
|
||||
|
||||
#if LLVM_VERSION_GE(10, 0)
|
||||
if (PGOOpt) {
|
||||
PB.addPGOInstrPassesForO0(
|
||||
MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
|
||||
/*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
for (const auto &C : PipelineStartEPCallbacks)
|
||||
PB.registerPipelineStartEPCallback(C);
|
||||
for (const auto &C : OptimizerLastEPCallbacks)
|
||||
PB.registerOptimizerLastEPCallback(C);
|
||||
|
||||
switch (OptStage) {
|
||||
case LLVMRustOptStage::PreLinkNoLTO:
|
||||
MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
|
||||
break;
|
||||
case LLVMRustOptStage::PreLinkThinLTO:
|
||||
MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
|
||||
break;
|
||||
case LLVMRustOptStage::PreLinkFatLTO:
|
||||
MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
|
||||
break;
|
||||
case LLVMRustOptStage::ThinLTO:
|
||||
// FIXME: Does it make sense to pass the ModuleSummaryIndex?
|
||||
// It only seems to be needed for C++ specific optimizations.
|
||||
MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
|
||||
break;
|
||||
case LLVMRustOptStage::FatLTO:
|
||||
MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UseThinLTOBuffers) {
|
||||
MPM.addPass(CanonicalizeAliasesPass());
|
||||
MPM.addPass(NameAnonGlobalPass());
|
||||
}
|
||||
|
||||
// Upgrade all calls to old intrinsics first.
|
||||
for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;)
|
||||
UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
|
||||
|
||||
MPM.run(*TheModule, MAM);
|
||||
#else
|
||||
// The new pass manager has been available for a long time,
|
||||
// but we don't bother supporting it on old LLVM versions.
|
||||
report_fatal_error("New pass manager only supported since LLVM 9");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Callback to demangle function name
|
||||
// Parameters:
|
||||
|
|
|
@ -1296,6 +1296,14 @@ extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B,
|
|||
#endif
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B,
|
||||
LLVMValueRef Dst, unsigned DstAlign,
|
||||
LLVMValueRef Val,
|
||||
LLVMValueRef Size, bool IsVolatile) {
|
||||
return wrap(unwrap(B)->CreateMemSet(
|
||||
unwrap(Dst), unwrap(Val), unwrap(Size), DstAlign, IsVolatile));
|
||||
}
|
||||
|
||||
extern "C" LLVMValueRef
|
||||
LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
||||
unsigned NumArgs, LLVMBasicBlockRef Then,
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
#![crate_type="lib"]
|
||||
|
||||
// MSAN-0-NOT: @__msan_track_origins
|
||||
// MSAN-1: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1
|
||||
// MSAN-2: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2
|
||||
// MSAN-1-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1
|
||||
// MSAN-2-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2
|
||||
// MSAN-1: @__msan_track_origins = weak_odr {{.*}}constant i32 1
|
||||
// MSAN-2: @__msan_track_origins = weak_odr {{.*}}constant i32 2
|
||||
// MSAN-1-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 1
|
||||
// MSAN-2-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 2
|
||||
//
|
||||
// MSAN-0-LABEL: define void @copy(
|
||||
// MSAN-1-LABEL: define void @copy(
|
||||
|
|
|
@ -17,16 +17,22 @@ fn black_box<T>(_: T) {
|
|||
fn main() {
|
||||
let a = -std::i8::MIN;
|
||||
//~^ ERROR const_err
|
||||
let a_i128 = -std::i128::MIN;
|
||||
//~^ ERROR const_err
|
||||
let b = 200u8 + 200u8 + 200u8;
|
||||
//~^ ERROR const_err
|
||||
let b_i128 = std::i128::MIN - std::i128::MAX;
|
||||
//~^ ERROR const_err
|
||||
let c = 200u8 * 4;
|
||||
//~^ ERROR const_err
|
||||
let d = 42u8 - (42u8 + 1);
|
||||
//~^ ERROR const_err
|
||||
let _e = [5u8][1];
|
||||
//~^ ERROR index out of bounds
|
||||
//~^ ERROR const_err
|
||||
black_box(a);
|
||||
black_box(a_i128);
|
||||
black_box(b);
|
||||
black_box(b_i128);
|
||||
black_box(c);
|
||||
black_box(d);
|
||||
}
|
||||
|
|
|
@ -11,28 +11,40 @@ LL | #![deny(const_err)]
|
|||
| ^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/const-err2.rs:20:13
|
||||
--> $DIR/const-err2.rs:20:18
|
||||
|
|
||||
LL | let a_i128 = -std::i128::MIN;
|
||||
| ^^^^^^^^^^^^^^^ attempt to negate with overflow
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/const-err2.rs:22:13
|
||||
|
|
||||
LL | let b = 200u8 + 200u8 + 200u8;
|
||||
| ^^^^^^^^^^^^^ attempt to add with overflow
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/const-err2.rs:22:13
|
||||
--> $DIR/const-err2.rs:24:18
|
||||
|
|
||||
LL | let b_i128 = std::i128::MIN - std::i128::MAX;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/const-err2.rs:26:13
|
||||
|
|
||||
LL | let c = 200u8 * 4;
|
||||
| ^^^^^^^^^ attempt to multiply with overflow
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/const-err2.rs:24:13
|
||||
--> $DIR/const-err2.rs:28:13
|
||||
|
|
||||
LL | let d = 42u8 - (42u8 + 1);
|
||||
| ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
|
||||
|
||||
error: index out of bounds: the len is 1 but the index is 1
|
||||
--> $DIR/const-err2.rs:26:14
|
||||
--> $DIR/const-err2.rs:30:14
|
||||
|
|
||||
LL | let _e = [5u8][1];
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
@ -17,8 +17,12 @@ fn black_box<T>(_: T) {
|
|||
fn main() {
|
||||
let a = -std::i8::MIN;
|
||||
//~^ ERROR const_err
|
||||
let a_i128 = -std::i128::MIN;
|
||||
//~^ ERROR const_err
|
||||
let b = 200u8 + 200u8 + 200u8;
|
||||
//~^ ERROR const_err
|
||||
let b_i128 = std::i128::MIN - std::i128::MAX;
|
||||
//~^ ERROR const_err
|
||||
let c = 200u8 * 4;
|
||||
//~^ ERROR const_err
|
||||
let d = 42u8 - (42u8 + 1);
|
||||
|
@ -26,7 +30,9 @@ fn main() {
|
|||
let _e = [5u8][1];
|
||||
//~^ ERROR const_err
|
||||
black_box(a);
|
||||
black_box(a_i128);
|
||||
black_box(b);
|
||||
black_box(b_i128);
|
||||
black_box(c);
|
||||
black_box(d);
|
||||
}
|
||||
|
|
|
@ -10,29 +10,41 @@ note: the lint level is defined here
|
|||
LL | #![deny(const_err)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: attempt to negate with overflow
|
||||
--> $DIR/const-err3.rs:20:18
|
||||
|
|
||||
LL | let a_i128 = -std::i128::MIN;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to add with overflow
|
||||
--> $DIR/const-err3.rs:20:13
|
||||
--> $DIR/const-err3.rs:22:13
|
||||
|
|
||||
LL | let b = 200u8 + 200u8 + 200u8;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to subtract with overflow
|
||||
--> $DIR/const-err3.rs:24:18
|
||||
|
|
||||
LL | let b_i128 = std::i128::MIN - std::i128::MAX;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to multiply with overflow
|
||||
--> $DIR/const-err3.rs:22:13
|
||||
--> $DIR/const-err3.rs:26:13
|
||||
|
|
||||
LL | let c = 200u8 * 4;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: attempt to subtract with overflow
|
||||
--> $DIR/const-err3.rs:24:13
|
||||
--> $DIR/const-err3.rs:28:13
|
||||
|
|
||||
LL | let d = 42u8 - (42u8 + 1);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: index out of bounds: the len is 1 but the index is 1
|
||||
--> $DIR/const-err3.rs:26:14
|
||||
--> $DIR/const-err3.rs:30:14
|
||||
|
|
||||
LL | let _e = [5u8][1];
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
26
src/test/ui/consts/const-int-arithmetic-overflow.rs
Normal file
26
src/test/ui/consts/const-int-arithmetic-overflow.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
// run-pass
|
||||
// compile-flags: -O
|
||||
#![allow(const_err)]
|
||||
|
||||
// Make sure arithmetic unary/binary ops actually return the right result, even when overflowing.
|
||||
// We have to put them in `const fn` and turn on optimizations to avoid overflow checks.
|
||||
|
||||
const fn add(x: i8, y: i8) -> i8 { x+y }
|
||||
const fn sub(x: i8, y: i8) -> i8 { x-y }
|
||||
const fn mul(x: i8, y: i8) -> i8 { x*y }
|
||||
// div and rem are always checked, so we cannot test their result in case of oveflow.
|
||||
const fn neg(x: i8) -> i8 { -x }
|
||||
|
||||
fn main() {
|
||||
const ADD_OFLOW: i8 = add(100, 100);
|
||||
assert_eq!(ADD_OFLOW, -56);
|
||||
|
||||
const SUB_OFLOW: i8 = sub(100, -100);
|
||||
assert_eq!(SUB_OFLOW, -56);
|
||||
|
||||
const MUL_OFLOW: i8 = mul(-100, -2);
|
||||
assert_eq!(MUL_OFLOW, -56);
|
||||
|
||||
const NEG_OFLOW: i8 = neg(-128);
|
||||
assert_eq!(NEG_OFLOW, -128);
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
#![feature(const_saturating_int_methods)]
|
||||
#![feature(const_wrapping_int_methods)]
|
||||
|
||||
use std::i8;
|
||||
use std::{i8, i128};
|
||||
|
||||
macro_rules! suite {
|
||||
($(
|
||||
|
@ -65,6 +65,10 @@ suite!(
|
|||
C26: 5i8.checked_rem_euclid(0), None;
|
||||
C27: i8::MIN.checked_rem_euclid(-1), None;
|
||||
}
|
||||
checked_i128 -> Option<i128> {
|
||||
CHK_ADD_I128: i128::MAX.checked_add(1), None;
|
||||
CHK_MUL_I128: i128::MIN.checked_mul(-1), None;
|
||||
}
|
||||
|
||||
saturating_and_wrapping -> i8 {
|
||||
// `const_saturating_int_methods`
|
||||
|
@ -104,6 +108,13 @@ suite!(
|
|||
C47: 100i8.wrapping_rem_euclid(10), 0;
|
||||
C48: (-128i8).wrapping_rem_euclid(-1), 0;
|
||||
}
|
||||
saturating_and_wrapping_i128 -> i128 {
|
||||
SAT_ADD_I128: i128::MAX.saturating_add(1), i128::MAX;
|
||||
SAT_MUL_I128: i128::MAX.saturating_mul(2), i128::MAX;
|
||||
|
||||
WRP_ADD_I128: i128::MAX.wrapping_add(1), i128::MIN;
|
||||
WRP_MUL_I128: i128::MAX.wrapping_mul(3), i128::MAX-2;
|
||||
}
|
||||
|
||||
overflowing -> (i8, bool) {
|
||||
// `const_overflowing_int_methods`
|
||||
|
@ -119,12 +130,18 @@ suite!(
|
|||
|
||||
C55: 5i8.overflowing_rem_euclid(2), (1, false);
|
||||
C56: i8::MIN.overflowing_rem_euclid(-1), (0, true);
|
||||
|
||||
}
|
||||
overflowing_i128 -> (i128, bool) {
|
||||
OFL_ADD_I128: i128::MAX.overflowing_add(1), (i128::MIN, true);
|
||||
OFL_MUL_I128: i128::MAX.overflowing_mul(3), (i128::MAX-2, true);
|
||||
}
|
||||
);
|
||||
|
||||
fn main() {
|
||||
checked();
|
||||
checked_i128();
|
||||
saturating_and_wrapping();
|
||||
saturating_and_wrapping_i128();
|
||||
overflowing();
|
||||
overflowing_i128();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#![deny(const_err)]
|
||||
|
||||
use std::{isize, i8, i16, i32, i64};
|
||||
use std::{isize, i8, i16, i32, i64, i128};
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
@ -22,6 +22,9 @@ fn main() {
|
|||
assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
|
||||
//~^ ERROR attempt to divide with overflow
|
||||
//~| ERROR this expression will panic at runtime
|
||||
assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
|
||||
//~^ ERROR attempt to divide with overflow
|
||||
//~| ERROR this expression will panic at runtime
|
||||
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
|
||||
|
@ -32,6 +35,8 @@ fn main() {
|
|||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
//~| ERROR this expression will panic at runtime
|
||||
|
@ -47,6 +52,9 @@ fn main() {
|
|||
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
//~| ERROR this expression will panic at runtime
|
||||
assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
//~| ERROR this expression will panic at runtime
|
||||
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
|
||||
|
@ -57,4 +65,6 @@ fn main() {
|
|||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
}
|
||||
|
|
|
@ -64,125 +64,161 @@ error: this expression will panic at runtime
|
|||
LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^ attempt to divide with overflow
|
||||
|
||||
error: attempt to divide by zero
|
||||
error: attempt to divide with overflow
|
||||
--> $DIR/issue-8460-const.rs:25:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:25:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^ attempt to divide with overflow
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:28:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:27:36
|
||||
--> $DIR/issue-8460-const.rs:30:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:29:36
|
||||
--> $DIR/issue-8460-const.rs:32:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:31:36
|
||||
--> $DIR/issue-8460-const.rs:34:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:33:36
|
||||
--> $DIR/issue-8460-const.rs:36:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const.rs:38:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:35:36
|
||||
--> $DIR/issue-8460-const.rs:40:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:35:36
|
||||
--> $DIR/issue-8460-const.rs:40:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:38:36
|
||||
--> $DIR/issue-8460-const.rs:43:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:38:36
|
||||
--> $DIR/issue-8460-const.rs:43:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:41:36
|
||||
--> $DIR/issue-8460-const.rs:46:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:41:36
|
||||
--> $DIR/issue-8460-const.rs:46:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:44:36
|
||||
--> $DIR/issue-8460-const.rs:49:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:44:36
|
||||
--> $DIR/issue-8460-const.rs:49:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:47:36
|
||||
--> $DIR/issue-8460-const.rs:52:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:47:36
|
||||
--> $DIR/issue-8460-const.rs:52:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const.rs:55:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression will panic at runtime
|
||||
--> $DIR/issue-8460-const.rs:55:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:50:36
|
||||
--> $DIR/issue-8460-const.rs:58:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:52:36
|
||||
--> $DIR/issue-8460-const.rs:60:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:54:36
|
||||
--> $DIR/issue-8460-const.rs:62:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:56:36
|
||||
--> $DIR/issue-8460-const.rs:64:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:58:36
|
||||
--> $DIR/issue-8460-const.rs:66:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 30 previous errors
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const.rs:68:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 36 previous errors
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#![deny(const_err)]
|
||||
|
||||
use std::{isize, i8, i16, i32, i64};
|
||||
use std::{isize, i8, i16, i32, i64, i128};
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
@ -17,6 +17,8 @@ fn main() {
|
|||
//~^ ERROR attempt to divide with overflow
|
||||
assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
|
||||
//~^ ERROR attempt to divide with overflow
|
||||
assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
|
||||
//~^ ERROR attempt to divide with overflow
|
||||
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
|
||||
|
@ -27,6 +29,8 @@ fn main() {
|
|||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
|
||||
//~^ ERROR attempt to divide by zero
|
||||
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
|
||||
|
@ -37,6 +41,8 @@ fn main() {
|
|||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
|
||||
|
@ -47,4 +53,6 @@ fn main() {
|
|||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
|
||||
//~^ ERROR attempt to calculate the remainder with a divisor of zero
|
||||
}
|
||||
|
|
|
@ -34,95 +34,119 @@ error: attempt to divide with overflow
|
|||
LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
error: attempt to divide with overflow
|
||||
--> $DIR/issue-8460-const2.rs:20:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:22:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:22:36
|
||||
--> $DIR/issue-8460-const2.rs:24:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:24:36
|
||||
--> $DIR/issue-8460-const2.rs:26:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:26:36
|
||||
--> $DIR/issue-8460-const2.rs:28:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:28:36
|
||||
--> $DIR/issue-8460-const2.rs:30:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/issue-8460-const2.rs:32:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:30:36
|
||||
--> $DIR/issue-8460-const2.rs:34:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:32:36
|
||||
--> $DIR/issue-8460-const2.rs:36:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:34:36
|
||||
--> $DIR/issue-8460-const2.rs:38:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:36:36
|
||||
--> $DIR/issue-8460-const2.rs:40:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:38:36
|
||||
--> $DIR/issue-8460-const2.rs:42:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with overflow
|
||||
--> $DIR/issue-8460-const2.rs:44:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:40:36
|
||||
--> $DIR/issue-8460-const2.rs:46:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:42:36
|
||||
--> $DIR/issue-8460-const2.rs:48:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:44:36
|
||||
--> $DIR/issue-8460-const2.rs:50:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:46:36
|
||||
--> $DIR/issue-8460-const2.rs:52:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:48:36
|
||||
--> $DIR/issue-8460-const2.rs:54:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: attempt to calculate the remainder with a divisor of zero
|
||||
--> $DIR/issue-8460-const2.rs:56:36
|
||||
|
|
||||
LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ fn main() {
|
|||
y: 2,
|
||||
};
|
||||
f.x::<isize>;
|
||||
//~^ ERROR field expressions may not have generic arguments
|
||||
//~^ ERROR field expressions cannot have generic arguments
|
||||
f.x::<>;
|
||||
//~^ ERROR field expressions may not have generic arguments
|
||||
//~^ ERROR field expressions cannot have generic arguments
|
||||
f.x::();
|
||||
//~^ ERROR field expressions may not have generic arguments
|
||||
//~^ ERROR field expressions cannot have generic arguments
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
error: field expressions may not have generic arguments
|
||||
error: field expressions cannot have generic arguments
|
||||
--> $DIR/type-parameters-in-field-exprs.rs:11:10
|
||||
|
|
||||
LL | f.x::<isize>;
|
||||
| ^^^^^^^
|
||||
|
||||
error: field expressions may not have generic arguments
|
||||
error: field expressions cannot have generic arguments
|
||||
--> $DIR/type-parameters-in-field-exprs.rs:13:10
|
||||
|
|
||||
LL | f.x::<>;
|
||||
| ^^
|
||||
|
||||
error: field expressions may not have generic arguments
|
||||
error: field expressions cannot have generic arguments
|
||||
--> $DIR/type-parameters-in-field-exprs.rs:15:7
|
||||
|
|
||||
LL | f.x::();
|
||||
|
|
5
src/test/ui/suggestions/method-missing-parentheses.rs
Normal file
5
src/test/ui/suggestions/method-missing-parentheses.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
let _ = vec![].into_iter().collect::<usize>;
|
||||
//~^ ERROR attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
|
||||
//~| ERROR field expressions cannot have generic arguments
|
||||
}
|
17
src/test/ui/suggestions/method-missing-parentheses.stderr
Normal file
17
src/test/ui/suggestions/method-missing-parentheses.stderr
Normal file
|
@ -0,0 +1,17 @@
|
|||
error: field expressions cannot have generic arguments
|
||||
--> $DIR/method-missing-parentheses.rs:2:41
|
||||
|
|
||||
LL | let _ = vec![].into_iter().collect::<usize>;
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0615]: attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
|
||||
--> $DIR/method-missing-parentheses.rs:2:32
|
||||
|
|
||||
LL | let _ = vec![].into_iter().collect::<usize>;
|
||||
| ^^^^^^^---------
|
||||
| |
|
||||
| help: use parentheses to call the method: `collect::<usize>()`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0615`.
|
Loading…
Add table
Add a link
Reference in a new issue