1
Fork 0

Auto merge of #68405 - JohnTitor:rollup-kj0x4za, r=JohnTitor

Rollup of 8 pull requests

Successful merges:

 - #67734 (Remove appendix from Apache license)
 - #67795 (Cleanup formatting code)
 - #68290 (Fix some tests failing in `--pass check` mode)
 - #68297 ( Filter and test predicates using `normalize_and_test_predicates` for const-prop)
 - #68302 (Fix #[track_caller] and function pointers)
 - #68339 (Add `riscv64gc-unknown-linux-gnu` into target list in build-manifest)
 - #68381 (Added minor clarification to specification of GlobalAlloc::realloc.)
 - #68397 (rustdoc: Correct order of `async` and `unsafe` in `async unsafe fn`s)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-01-20 23:35:50 +00:00
commit 06b945049b
27 changed files with 269 additions and 245 deletions

View file

@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
of your accepting any such warranty or additional liability. of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -525,7 +525,8 @@ pub unsafe trait GlobalAlloc {
/// The memory may or may not have been deallocated, /// The memory may or may not have been deallocated,
/// and should be considered unusable (unless of course it was /// and should be considered unusable (unless of course it was
/// transferred back to the caller again via the return value of /// transferred back to the caller again via the return value of
/// this method). /// this method). The new memory block is allocated with `layout`, but
/// with the `size` updated to `new_size`.
/// ///
/// If this method returns null, then ownership of the memory /// If this method returns null, then ownership of the memory
/// block has not been transferred to this allocator, and the /// block has not been transferred to this allocator, and the

View file

@ -10,7 +10,6 @@ use crate::mem;
use crate::num::flt2dec; use crate::num::flt2dec;
use crate::ops::Deref; use crate::ops::Deref;
use crate::result; use crate::result;
use crate::slice;
use crate::str; use crate::str;
mod builders; mod builders;
@ -234,8 +233,6 @@ pub struct Formatter<'a> {
precision: Option<usize>, precision: Option<usize>,
buf: &'a mut (dyn Write + 'a), buf: &'a mut (dyn Write + 'a),
curarg: slice::Iter<'a, ArgumentV1<'a>>,
args: &'a [ArgumentV1<'a>],
} }
// NB. Argument is essentially an optimized partially applied formatting function, // NB. Argument is essentially an optimized partially applied formatting function,
@ -1043,8 +1040,6 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
buf: output, buf: output,
align: rt::v1::Alignment::Unknown, align: rt::v1::Alignment::Unknown,
fill: ' ', fill: ' ',
args: args.args,
curarg: args.args.iter(),
}; };
let mut idx = 0; let mut idx = 0;
@ -1063,7 +1058,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
// a string piece. // a string piece.
for (arg, piece) in fmt.iter().zip(args.pieces.iter()) { for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
formatter.buf.write_str(*piece)?; formatter.buf.write_str(*piece)?;
formatter.run(arg)?; run(&mut formatter, arg, &args.args)?;
idx += 1; idx += 1;
} }
} }
@ -1077,6 +1072,39 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
Ok(()) Ok(())
} }
fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument, args: &[ArgumentV1<'_>]) -> Result {
fmt.fill = arg.format.fill;
fmt.align = arg.format.align;
fmt.flags = arg.format.flags;
fmt.width = getcount(args, &arg.format.width);
fmt.precision = getcount(args, &arg.format.precision);
// Extract the correct argument
let value = {
#[cfg(bootstrap)]
{
match arg.position {
rt::v1::Position::At(i) => args[i],
}
}
#[cfg(not(bootstrap))]
{
args[arg.position]
}
};
// Then actually do some printing
(value.formatter)(value.value, fmt)
}
fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option<usize> {
match *cnt {
rt::v1::Count::Is(n) => Some(n),
rt::v1::Count::Implied => None,
rt::v1::Count::Param(i) => args[i].as_usize(),
}
}
/// Padding after the end of something. Returned by `Formatter::padding`. /// Padding after the end of something. Returned by `Formatter::padding`.
#[must_use = "don't forget to write the post padding"] #[must_use = "don't forget to write the post padding"]
struct PostPadding { struct PostPadding {
@ -1114,41 +1142,6 @@ impl<'a> Formatter<'a> {
align: self.align, align: self.align,
width: self.width, width: self.width,
precision: self.precision, precision: self.precision,
// These only exist in the struct for the `run` method,
// which wont be used together with this method.
curarg: self.curarg.clone(),
args: self.args,
}
}
// First up is the collection of functions used to execute a format string
// at runtime. This consumes all of the compile-time statics generated by
// the format! syntax extension.
fn run(&mut self, arg: &rt::v1::Argument) -> Result {
// Fill in the format parameters into the formatter
self.fill = arg.format.fill;
self.align = arg.format.align;
self.flags = arg.format.flags;
self.width = self.getcount(&arg.format.width);
self.precision = self.getcount(&arg.format.precision);
// Extract the correct argument
let value = match arg.position {
rt::v1::Position::Next => *self.curarg.next().unwrap(),
rt::v1::Position::At(i) => self.args[i],
};
// Then actually do some printing
(value.formatter)(value.value, self)
}
fn getcount(&mut self, cnt: &rt::v1::Count) -> Option<usize> {
match *cnt {
rt::v1::Count::Is(n) => Some(n),
rt::v1::Count::Implied => None,
rt::v1::Count::Param(i) => self.args[i].as_usize(),
rt::v1::Count::NextParam => self.curarg.next()?.as_usize(),
} }
} }

View file

@ -7,7 +7,10 @@
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Argument { pub struct Argument {
#[cfg(bootstrap)]
pub position: Position, pub position: Position,
#[cfg(not(bootstrap))]
pub position: usize,
pub format: FormatSpec, pub format: FormatSpec,
} }
@ -37,12 +40,11 @@ pub enum Alignment {
pub enum Count { pub enum Count {
Is(usize), Is(usize),
Param(usize), Param(usize),
NextParam,
Implied, Implied,
} }
#[cfg(bootstrap)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Position { pub enum Position {
Next,
At(usize), At(usize),
} }

View file

@ -1,7 +1,6 @@
use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId};
use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext}; use crate::ich::{Fingerprint, NodeIdHashingMode, StableHashingContext};
use crate::session::config::OptLevel; use crate::session::config::OptLevel;
use crate::traits::TraitQueryMode;
use crate::ty::print::obsolete::DefPathBasedNames; use crate::ty::print::obsolete::DefPathBasedNames;
use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
@ -168,9 +167,7 @@ impl<'tcx> MonoItem<'tcx> {
MonoItem::GlobalAsm(..) => return true, MonoItem::GlobalAsm(..) => return true,
}; };
// We shouldn't encounter any overflow here, so we use TraitQueryMode::Standard\ tcx.substitute_normalize_and_test_predicates((def_id, &substs))
// to report an error if overflow somehow occurs.
tcx.substitute_normalize_and_test_predicates((def_id, &substs, TraitQueryMode::Standard))
} }
pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {

View file

@ -1156,11 +1156,11 @@ rustc_queries! {
desc { "normalizing `{:?}`", goal } desc { "normalizing `{:?}`", goal }
} }
query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>, traits::TraitQueryMode)) -> bool { query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
no_force no_force
desc { |tcx| desc { |tcx|
"testing substituted normalized predicates in mode {:?}:`{}`", "testing substituted normalized predicates:`{}`",
key.2, tcx.def_path_str(key.0) tcx.def_path_str(key.0)
} }
} }

View file

@ -16,7 +16,6 @@ use super::CodeSelectionError;
use super::{ConstEvalFailure, Unimplemented}; use super::{ConstEvalFailure, Unimplemented};
use super::{FulfillmentError, FulfillmentErrorCode}; use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation}; use super::{ObligationCause, PredicateObligation};
use crate::traits::TraitQueryMode;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
type Predicate = ty::Predicate<'tcx>; type Predicate = ty::Predicate<'tcx>;
@ -63,9 +62,6 @@ pub struct FulfillmentContext<'tcx> {
// a snapshot (they don't *straddle* a snapshot, so there // a snapshot (they don't *straddle* a snapshot, so there
// is no trouble there). // is no trouble there).
usable_in_snapshot: bool, usable_in_snapshot: bool,
// The `TraitQueryMode` used when constructing a `SelectionContext`
query_mode: TraitQueryMode,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -79,26 +75,12 @@ pub struct PendingPredicateObligation<'tcx> {
static_assert_size!(PendingPredicateObligation<'_>, 136); static_assert_size!(PendingPredicateObligation<'_>, 136);
impl<'a, 'tcx> FulfillmentContext<'tcx> { impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context with `TraitQueryMode::Standard` /// Creates a new fulfillment context.
/// You almost always want to use this instead of `with_query_mode`
pub fn new() -> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext { FulfillmentContext {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: true, register_region_obligations: true,
usable_in_snapshot: false, usable_in_snapshot: false,
query_mode: TraitQueryMode::Standard,
}
}
/// Creates a new fulfillment context with the specified query mode.
/// This should only be used when you want to ignore overflow,
/// rather than reporting it as an error.
pub fn with_query_mode(query_mode: TraitQueryMode) -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
register_region_obligations: true,
usable_in_snapshot: false,
query_mode,
} }
} }
@ -107,7 +89,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: true, register_region_obligations: true,
usable_in_snapshot: true, usable_in_snapshot: true,
query_mode: TraitQueryMode::Standard,
} }
} }
@ -116,7 +97,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(), predicates: ObligationForest::new(),
register_region_obligations: false, register_region_obligations: false,
usable_in_snapshot: false, usable_in_snapshot: false,
query_mode: TraitQueryMode::Standard,
} }
} }
@ -237,7 +217,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode); let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx) self.select(&mut selcx)
} }

View file

@ -95,7 +95,7 @@ pub enum IntercrateMode {
} }
/// The mode that trait queries run in. /// The mode that trait queries run in.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TraitQueryMode { pub enum TraitQueryMode {
// Standard/un-canonicalized queries get accurate // Standard/un-canonicalized queries get accurate
// spans etc. passed in and hence can do reasonable // spans etc. passed in and hence can do reasonable
@ -1014,17 +1014,16 @@ where
/// environment. If this returns false, then either normalize /// environment. If this returns false, then either normalize
/// encountered an error or one of the predicates did not hold. Used /// encountered an error or one of the predicates did not hold. Used
/// when creating vtables to check for unsatisfiable methods. /// when creating vtables to check for unsatisfiable methods.
fn normalize_and_test_predicates<'tcx>( pub fn normalize_and_test_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>, predicates: Vec<ty::Predicate<'tcx>>,
mode: TraitQueryMode,
) -> bool { ) -> bool {
debug!("normalize_and_test_predicates(predicates={:?}, mode={:?})", predicates, mode); debug!("normalize_and_test_predicates(predicates={:?})", predicates);
let result = tcx.infer_ctxt().enter(|infcx| { let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::reveal_all(); let param_env = ty::ParamEnv::reveal_all();
let mut selcx = SelectionContext::with_query_mode(&infcx, mode); let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::with_query_mode(mode); let mut fulfill_cx = FulfillmentContext::new();
let cause = ObligationCause::dummy(); let cause = ObligationCause::dummy();
let Normalized { value: predicates, obligations } = let Normalized { value: predicates, obligations } =
normalize(&mut selcx, param_env, cause.clone(), &predicates); normalize(&mut selcx, param_env, cause.clone(), &predicates);
@ -1044,12 +1043,12 @@ fn normalize_and_test_predicates<'tcx>(
fn substitute_normalize_and_test_predicates<'tcx>( fn substitute_normalize_and_test_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
key: (DefId, SubstsRef<'tcx>, TraitQueryMode), key: (DefId, SubstsRef<'tcx>),
) -> bool { ) -> bool {
debug!("substitute_normalize_and_test_predicates(key={:?})", key); debug!("substitute_normalize_and_test_predicates(key={:?})", key);
let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
let result = normalize_and_test_predicates(tcx, predicates, key.2); let result = normalize_and_test_predicates(tcx, predicates);
debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
result result
@ -1102,10 +1101,7 @@ fn vtable_methods<'tcx>(
// Note that this method could then never be called, so we // Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435). // do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
// We don't expect overflow here, so report an error if it somehow ends if !normalize_and_test_predicates(tcx, predicates.predicates) {
// up happening.
if !normalize_and_test_predicates(tcx, predicates.predicates, TraitQueryMode::Standard)
{
debug!("vtable_methods: predicates do not hold"); debug!("vtable_methods: predicates do not hold");
return None; return None;
} }

View file

@ -141,7 +141,12 @@ impl<'tcx> InstanceDef<'tcx> {
} }
pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) match *self {
InstanceDef::Item(def_id) => {
tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
}
_ => false,
}
} }
} }

View file

@ -125,15 +125,6 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
} }
} }
impl<'tcx> Key for (DefId, SubstsRef<'tcx>, traits::TraitQueryMode) {
fn query_crate(&self) -> CrateNum {
self.0.krate
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
}
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
fn query_crate(&self) -> CrateNum { fn query_crate(&self) -> CrateNum {
self.1.def_id().krate self.1.def_id().krate

View file

@ -590,17 +590,6 @@ impl<'a, 'b> Context<'a, 'b> {
parse::NextArgument(ref arg) => { parse::NextArgument(ref arg) => {
// Build the position // Build the position
let pos = { let pos = {
let pos = |c, arg| {
let mut path = Context::rtpath(self.ecx, "Position");
path.push(self.ecx.ident_of(c, sp));
match arg {
Some(i) => {
let arg = self.ecx.expr_usize(sp, i);
self.ecx.expr_call_global(sp, path, vec![arg])
}
None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
}
};
match arg.position { match arg.position {
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => { parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => {
// Map to index in final generated argument array // Map to index in final generated argument array
@ -615,7 +604,7 @@ impl<'a, 'b> Context<'a, 'b> {
arg_idx arg_idx
} }
}; };
pos("At", Some(arg_idx)) self.ecx.expr_usize(sp, arg_idx)
} }
// should never be the case, because names are already // should never be the case, because names are already

View file

@ -31,9 +31,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
let mut result = match instance { let mut result = match instance {
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
ty::InstanceDef::VtableShim(def_id) => { ty::InstanceDef::VtableShim(def_id) => build_call_shim(
build_call_shim(tcx, instance, Adjustment::DerefMove, CallKind::Direct(def_id), None) tcx,
} instance,
Some(Adjustment::DerefMove),
CallKind::Direct(def_id),
None,
),
ty::InstanceDef::FnPtrShim(def_id, ty) => { ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap(); let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.lang_items().fn_trait_kind(trait_) { let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
@ -50,7 +54,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
let arg_tys = sig.inputs(); let arg_tys = sig.inputs();
build_call_shim(tcx, instance, adjustment, CallKind::Indirect, Some(arg_tys)) build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys))
} }
// We are generating a call back to our def-id, which the // We are generating a call back to our def-id, which the
// codegen backend knows to turn to an actual call, be it // codegen backend knows to turn to an actual call, be it
@ -58,7 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
// indirect calls must be codegen'd differently than direct ones // indirect calls must be codegen'd differently than direct ones
// (such as `#[track_caller]`). // (such as `#[track_caller]`).
ty::InstanceDef::ReifyShim(def_id) => { ty::InstanceDef::ReifyShim(def_id) => {
build_call_shim(tcx, instance, Adjustment::Identity, CallKind::Direct(def_id), None) build_call_shim(tcx, instance, None, CallKind::Direct(def_id), None)
} }
ty::InstanceDef::ClosureOnceShim { call_once: _ } => { ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); let fn_mut = tcx.lang_items().fn_mut_trait().unwrap();
@ -68,7 +72,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx
.unwrap() .unwrap()
.def_id; .def_id;
build_call_shim(tcx, instance, Adjustment::RefMut, CallKind::Direct(call_mut), None) build_call_shim(
tcx,
instance,
Some(Adjustment::RefMut),
CallKind::Direct(call_mut),
None,
)
} }
ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
ty::InstanceDef::CloneShim(def_id, ty) => { ty::InstanceDef::CloneShim(def_id, ty) => {
@ -648,7 +658,7 @@ impl CloneShimBuilder<'tcx> {
fn build_call_shim<'tcx>( fn build_call_shim<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>, instance: ty::InstanceDef<'tcx>,
rcvr_adjustment: Adjustment, rcvr_adjustment: Option<Adjustment>,
call_kind: CallKind, call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>, untuple_args: Option<&[Ty<'tcx>]>,
) -> BodyAndCache<'tcx> { ) -> BodyAndCache<'tcx> {
@ -680,14 +690,16 @@ fn build_call_shim<'tcx>(
let mut local_decls = local_decls_for_sig(&sig, span); let mut local_decls = local_decls_for_sig(&sig, span);
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
let rcvr_arg = Local::new(1 + 0); let rcvr_place = || {
let rcvr_l = Place::from(rcvr_arg); assert!(rcvr_adjustment.is_some());
Place::from(Local::new(1 + 0))
};
let mut statements = vec![]; let mut statements = vec![];
let rcvr = match rcvr_adjustment { let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
Adjustment::Identity => Operand::Move(rcvr_l), Adjustment::Identity => Operand::Move(rcvr_place()),
Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)), Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_place())),
Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_l)), Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
Adjustment::RefMut => { Adjustment::RefMut => {
// let rcvr = &mut rcvr; // let rcvr = &mut rcvr;
let ref_rcvr = local_decls.push(temp_decl( let ref_rcvr = local_decls.push(temp_decl(
@ -703,15 +715,15 @@ fn build_call_shim<'tcx>(
source_info, source_info,
kind: StatementKind::Assign(box ( kind: StatementKind::Assign(box (
Place::from(ref_rcvr), Place::from(ref_rcvr),
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_l), Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
)), )),
}); });
Operand::Move(Place::from(ref_rcvr)) Operand::Move(Place::from(ref_rcvr))
} }
}; });
let (callee, mut args) = match call_kind { let (callee, mut args) = match call_kind {
CallKind::Indirect => (rcvr, vec![]), CallKind::Indirect => (rcvr.unwrap(), vec![]),
CallKind::Direct(def_id) => { CallKind::Direct(def_id) => {
let ty = tcx.type_of(def_id); let ty = tcx.type_of(def_id);
( (
@ -720,21 +732,35 @@ fn build_call_shim<'tcx>(
user_ty: None, user_ty: None,
literal: ty::Const::zero_sized(tcx, ty), literal: ty::Const::zero_sized(tcx, ty),
}), }),
vec![rcvr], rcvr.into_iter().collect::<Vec<_>>(),
) )
} }
}; };
if let Some(untuple_args) = untuple_args { let mut arg_range = 0..sig.inputs().len();
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
let arg_place = Place::from(Local::new(1 + 1)); // Take the `self` ("receiver") argument out of the range (it's adjusted above).
Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity)) if rcvr_adjustment.is_some() {
})); arg_range.start += 1;
} else {
args.extend((1..sig.inputs().len()).map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
} }
let n_blocks = if let Adjustment::RefMut = rcvr_adjustment { 5 } else { 2 }; // Take the last argument, if we need to untuple it (handled below).
if untuple_args.is_some() {
arg_range.end -= 1;
}
// Pass all of the non-special arguments directly.
args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
// Untuple the last argument, if we have to.
if let Some(untuple_args) = untuple_args {
let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity))
}));
}
let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
let mut blocks = IndexVec::with_capacity(n_blocks); let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData { blocks.push(BasicBlockData {
@ -752,7 +778,7 @@ fn build_call_shim<'tcx>(
func: callee, func: callee,
args, args,
destination: Some((Place::return_place(), BasicBlock::new(1))), destination: Some((Place::return_place(), BasicBlock::new(1))),
cleanup: if let Adjustment::RefMut = rcvr_adjustment { cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
Some(BasicBlock::new(3)) Some(BasicBlock::new(3))
} else { } else {
None None
@ -762,13 +788,13 @@ fn build_call_shim<'tcx>(
false, false,
); );
if let Adjustment::RefMut = rcvr_adjustment { if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #1 - drop for Self // BB #1 - drop for Self
block( block(
&mut blocks, &mut blocks,
vec![], vec![],
TerminatorKind::Drop { TerminatorKind::Drop {
location: Place::from(rcvr_arg), location: rcvr_place(),
target: BasicBlock::new(2), target: BasicBlock::new(2),
unwind: None, unwind: None,
}, },
@ -777,13 +803,13 @@ fn build_call_shim<'tcx>(
} }
// BB #1/#2 - return // BB #1/#2 - return
block(&mut blocks, vec![], TerminatorKind::Return, false); block(&mut blocks, vec![], TerminatorKind::Return, false);
if let Adjustment::RefMut = rcvr_adjustment { if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #3 - drop if closure panics // BB #3 - drop if closure panics
block( block(
&mut blocks, &mut blocks,
vec![], vec![],
TerminatorKind::Drop { TerminatorKind::Drop {
location: Place::from(rcvr_arg), location: rcvr_place(),
target: BasicBlock::new(4), target: BasicBlock::new(4),
unwind: None, unwind: None,
}, },

View file

@ -14,7 +14,7 @@ use rustc::mir::{
SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind,
UnOp, RETURN_PLACE, UnOp, RETURN_PLACE,
}; };
use rustc::traits::TraitQueryMode; use rustc::traits;
use rustc::ty::layout::{ use rustc::ty::layout::{
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
}; };
@ -90,28 +90,28 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
// If there are unsatisfiable where clauses, then all bets are // If there are unsatisfiable where clauses, then all bets are
// off, and we just give up. // off, and we just give up.
// //
// Note that we use TraitQueryMode::Canonical here, which causes // We manually filter the predicates, skipping anything that's not
// us to treat overflow like any other error. This is because we // "global". We are in a potentially generic context
// are "speculatively" evaluating this item with the default substs. // (e.g. we are evaluating a function without substituting generic
// While this usually succeeds, it may fail with tricky impls // parameters, so this filtering serves two purposes:
// (e.g. the typenum crate). Const-propagation is fundamentally
// "best-effort", and does not affect correctness in any way.
// Therefore, it's perfectly fine to just "give up" if we're
// unable to check the bounds with the default substs.
// //
// False negatives (failing to run const-prop on something when we actually // 1. We skip evaluating any predicates that we would
// could) are fine. However, false positives (running const-prop on // never be able prove are unsatisfiable (e.g. `<T as Foo>`
// an item with unsatisfiable bounds) can lead to us generating invalid // 2. We avoid trying to normalize predicates involving generic
// MIR. // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
if !tcx.substitute_normalize_and_test_predicates(( // the normalization code (leading to cycle errors), since
source.def_id(), // it's usually never invoked in this way.
InternalSubsts::identity_for_item(tcx, source.def_id()), let predicates = tcx
TraitQueryMode::Canonical, .predicates_of(source.def_id())
)) { .predicates
trace!( .iter()
"ConstProp skipped for item with unsatisfiable predicates: {:?}", .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None })
source.def_id() .collect();
); if !traits::normalize_and_test_predicates(
tcx,
traits::elaborate_predicates(tcx, predicates).collect(),
) {
trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", source.def_id());
return; return;
} }

View file

@ -2321,8 +2321,8 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
"{}{}{}{}{:#}fn {}{:#}", "{}{}{}{}{:#}fn {}{:#}",
it.visibility.print_with_space(), it.visibility.print_with_space(),
f.header.constness.print_with_space(), f.header.constness.print_with_space(),
f.header.unsafety.print_with_space(),
f.header.asyncness.print_with_space(), f.header.asyncness.print_with_space(),
f.header.unsafety.print_with_space(),
print_abi_with_space(f.header.abi), print_abi_with_space(f.header.abi),
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
f.generics.print() f.generics.print()
@ -2332,12 +2332,12 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
render_attributes(w, it, false); render_attributes(w, it, false);
write!( write!(
w, w,
"{vis}{constness}{unsafety}{asyncness}{abi}fn \ "{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>", {name}{generics}{decl}{where_clause}</pre>",
vis = it.visibility.print_with_space(), vis = it.visibility.print_with_space(),
constness = f.header.constness.print_with_space(), constness = f.header.constness.print_with_space(),
unsafety = f.header.unsafety.print_with_space(),
asyncness = f.header.asyncness.print_with_space(), asyncness = f.header.asyncness.print_with_space(),
unsafety = f.header.unsafety.print_with_space(),
abi = print_abi_with_space(f.header.abi), abi = print_abi_with_space(f.header.abi),
name = it.name.as_ref().unwrap(), name = it.name.as_ref().unwrap(),
generics = f.generics.print(), generics = f.generics.print(),
@ -2832,8 +2832,8 @@ fn render_assoc_item(
"{}{}{}{}{}{:#}fn {}{:#}", "{}{}{}{}{}{:#}fn {}{:#}",
meth.visibility.print_with_space(), meth.visibility.print_with_space(),
header.constness.print_with_space(), header.constness.print_with_space(),
header.unsafety.print_with_space(),
header.asyncness.print_with_space(), header.asyncness.print_with_space(),
header.unsafety.print_with_space(),
print_default_space(meth.is_default()), print_default_space(meth.is_default()),
print_abi_with_space(header.abi), print_abi_with_space(header.abi),
name, name,
@ -2854,8 +2854,8 @@ fn render_assoc_item(
if parent == ItemType::Trait { " " } else { "" }, if parent == ItemType::Trait { " " } else { "" },
meth.visibility.print_with_space(), meth.visibility.print_with_space(),
header.constness.print_with_space(), header.constness.print_with_space(),
header.unsafety.print_with_space(),
header.asyncness.print_with_space(), header.asyncness.print_with_space(),
header.unsafety.print_with_space(),
print_default_space(meth.is_default()), print_default_space(meth.is_default()),
print_abi_with_space(header.abi), print_abi_with_space(header.abi),
href = href, href = href,

View file

@ -15,6 +15,11 @@ pub async fn baz<T>(a: T) -> T {
a a
} }
// @has async_fn/fn.qux.html '//pre[@class="rust fn"]' 'pub async unsafe fn qux() -> char'
pub async unsafe fn qux() -> char {
'⚠'
}
trait Bar {} trait Bar {}
impl Bar for () {} impl Bar for () {}
@ -26,8 +31,10 @@ pub async fn quux() -> impl Bar {
// @has async_fn/struct.Foo.html // @has async_fn/struct.Foo.html
// @matches - '//code' 'pub async fn f\(\)$' // @matches - '//code' 'pub async fn f\(\)$'
// @matches - '//code' 'pub async unsafe fn g\(\)$'
pub struct Foo; pub struct Foo;
impl Foo { impl Foo {
pub async fn f() {} pub async fn f() {}
pub async unsafe fn g() {}
} }

View file

@ -2,15 +2,15 @@
// edition:2018 // edition:2018
// compile-flags: --crate-type lib // compile-flags: --crate-type lib
use std::{ use std::{cell::RefCell, fmt::Debug, rc::Rc};
cell::RefCell,
fmt::Debug,
rc::Rc,
};
fn non_sync() -> impl Debug { RefCell::new(()) } fn non_sync() -> impl Debug {
RefCell::new(())
}
fn non_send() -> impl Debug { Rc::new(()) } fn non_send() -> impl Debug {
Rc::new(())
}
fn take_ref<T>(_: &T) {} fn take_ref<T>(_: &T) {}
@ -53,5 +53,4 @@ pub fn pass_assert() {
//~^ ERROR future cannot be sent between threads safely //~^ ERROR future cannot be sent between threads safely
assert_send(non_sync_with_method_call()); assert_send(non_sync_with_method_call());
//~^ ERROR future cannot be sent between threads safely //~^ ERROR future cannot be sent between threads safely
//~^^ ERROR future cannot be sent between threads safely
} }

View file

@ -62,27 +62,5 @@ LL | }
LL | } LL | }
| - `f` is later dropped here | - `f` is later dropped here
error: future cannot be sent between threads safely error: aborting due to 3 previous errors
--> $DIR/async-fn-nonsend.rs:54:5
|
LL | fn assert_send(_: impl Send) {}
| ----------- ---- required by this bound in `assert_send`
...
LL | assert_send(non_sync_with_method_call());
| ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
= help: within `std::fmt::ArgumentV1<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:43:9
|
LL | let f: &mut std::fmt::Formatter = panic!();
| - has type `&mut std::fmt::Formatter<'_>`
LL | if non_sync().fmt(f).unwrap() == () {
LL | fut().await;
| ^^^^^^^^^^^ await occurs here, with `f` maybe used later
LL | }
LL | }
| - `f` is later dropped here
error: aborting due to 4 previous errors

View file

@ -1,4 +1,5 @@
// build-pass // build-pass
// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
#![warn(const_err)] #![warn(const_err)]

View file

@ -1,17 +1,17 @@
warning: index out of bounds: the len is 3 but the index is 4 warning: index out of bounds: the len is 3 but the index is 4
--> $DIR/array-literal-index-oob.rs:6:8 --> $DIR/array-literal-index-oob.rs:7:8
| |
LL | &{ [1, 2, 3][4] }; LL | &{ [1, 2, 3][4] };
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
note: lint level defined here note: lint level defined here
--> $DIR/array-literal-index-oob.rs:3:9 --> $DIR/array-literal-index-oob.rs:4:9
| |
LL | #![warn(const_err)] LL | #![warn(const_err)]
| ^^^^^^^^^ | ^^^^^^^^^
warning: reaching this expression at runtime will panic or abort warning: reaching this expression at runtime will panic or abort
--> $DIR/array-literal-index-oob.rs:6:8 --> $DIR/array-literal-index-oob.rs:7:8
| |
LL | &{ [1, 2, 3][4] }; LL | &{ [1, 2, 3][4] };
| ---^^^^^^^^^^^^-- | ---^^^^^^^^^^^^--
@ -19,7 +19,7 @@ LL | &{ [1, 2, 3][4] };
| indexing out of bounds: the len is 3 but the index is 4 | indexing out of bounds: the len is 3 but the index is 4
warning: erroneous constant used warning: erroneous constant used
--> $DIR/array-literal-index-oob.rs:6:5 --> $DIR/array-literal-index-oob.rs:7:5
| |
LL | &{ [1, 2, 3][4] }; LL | &{ [1, 2, 3][4] };
| ^^^^^^^^^^^^^^^^^ referenced constant has errors | ^^^^^^^^^^^^^^^^^ referenced constant has errors

View file

@ -1,4 +1,5 @@
// build-pass // build-pass
// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
// compile-flags: -O // compile-flags: -O
#![warn(const_err)] #![warn(const_err)]

View file

@ -1,59 +1,59 @@
warning: this expression will panic at runtime warning: this expression will panic at runtime
--> $DIR/promoted_errors.rs:8:14 --> $DIR/promoted_errors.rs:9:14
| |
LL | let _x = 0u32 - 1; LL | let _x = 0u32 - 1;
| ^^^^^^^^ attempt to subtract with overflow | ^^^^^^^^ attempt to subtract with overflow
| |
note: lint level defined here note: lint level defined here
--> $DIR/promoted_errors.rs:4:9 --> $DIR/promoted_errors.rs:5:9
| |
LL | #![warn(const_err)] LL | #![warn(const_err)]
| ^^^^^^^^^ | ^^^^^^^^^
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors.rs:10:20 --> $DIR/promoted_errors.rs:11:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ | ^^^^^^^^^^^
warning: reaching this expression at runtime will panic or abort warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors.rs:10:20 --> $DIR/promoted_errors.rs:11:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ dividing by zero | ^^^^^^^^^^^ dividing by zero
warning: erroneous constant used warning: erroneous constant used
--> $DIR/promoted_errors.rs:10:20 --> $DIR/promoted_errors.rs:11:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ referenced constant has errors | ^^^^^^^^^^^ referenced constant has errors
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors.rs:14:14 --> $DIR/promoted_errors.rs:15:14
| |
LL | let _x = 1 / (1 - 1); LL | let _x = 1 / (1 - 1);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors.rs:16:20 --> $DIR/promoted_errors.rs:17:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
warning: reaching this expression at runtime will panic or abort warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors.rs:16:20 --> $DIR/promoted_errors.rs:17:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ dividing by zero | ^^^^^^^^^^^^^^^^^^ dividing by zero
warning: erroneous constant used warning: erroneous constant used
--> $DIR/promoted_errors.rs:16:20 --> $DIR/promoted_errors.rs:17:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ referenced constant has errors | ^^^^^^^^^^^^^^^^^^ referenced constant has errors
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors.rs:20:14 --> $DIR/promoted_errors.rs:21:14
| |
LL | let _x = 1 / (false as u32); LL | let _x = 1 / (false as u32);
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^

View file

@ -1,4 +1,5 @@
// build-pass // build-pass
// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors)
// compile-flags: -C overflow-checks=on -O // compile-flags: -C overflow-checks=on -O
#![warn(const_err)] #![warn(const_err)]

View file

@ -1,65 +1,65 @@
warning: attempt to subtract with overflow warning: attempt to subtract with overflow
--> $DIR/promoted_errors2.rs:7:20 --> $DIR/promoted_errors2.rs:8:20
| |
LL | println!("{}", 0u32 - 1); LL | println!("{}", 0u32 - 1);
| ^^^^^^^^ | ^^^^^^^^
| |
note: lint level defined here note: lint level defined here
--> $DIR/promoted_errors2.rs:4:9 --> $DIR/promoted_errors2.rs:5:9
| |
LL | #![warn(const_err)] LL | #![warn(const_err)]
| ^^^^^^^^^ | ^^^^^^^^^
warning: attempt to subtract with overflow warning: attempt to subtract with overflow
--> $DIR/promoted_errors2.rs:9:14 --> $DIR/promoted_errors2.rs:10:14
| |
LL | let _x = 0u32 - 1; LL | let _x = 0u32 - 1;
| ^^^^^^^^ | ^^^^^^^^
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors2.rs:11:20 --> $DIR/promoted_errors2.rs:12:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ | ^^^^^^^^^^^
warning: reaching this expression at runtime will panic or abort warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors2.rs:11:20 --> $DIR/promoted_errors2.rs:12:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ dividing by zero | ^^^^^^^^^^^ dividing by zero
warning: erroneous constant used warning: erroneous constant used
--> $DIR/promoted_errors2.rs:11:20 --> $DIR/promoted_errors2.rs:12:20
| |
LL | println!("{}", 1 / (1 - 1)); LL | println!("{}", 1 / (1 - 1));
| ^^^^^^^^^^^ referenced constant has errors | ^^^^^^^^^^^ referenced constant has errors
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors2.rs:15:14 --> $DIR/promoted_errors2.rs:16:14
| |
LL | let _x = 1 / (1 - 1); LL | let _x = 1 / (1 - 1);
| ^^^^^^^^^^^ | ^^^^^^^^^^^
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors2.rs:17:20 --> $DIR/promoted_errors2.rs:18:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
warning: reaching this expression at runtime will panic or abort warning: reaching this expression at runtime will panic or abort
--> $DIR/promoted_errors2.rs:17:20 --> $DIR/promoted_errors2.rs:18:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ dividing by zero | ^^^^^^^^^^^^^^^^^^ dividing by zero
warning: erroneous constant used warning: erroneous constant used
--> $DIR/promoted_errors2.rs:17:20 --> $DIR/promoted_errors2.rs:18:20
| |
LL | println!("{}", 1 / (false as u32)); LL | println!("{}", 1 / (false as u32));
| ^^^^^^^^^^^^^^^^^^ referenced constant has errors | ^^^^^^^^^^^^^^^^^^ referenced constant has errors
warning: attempt to divide by zero warning: attempt to divide by zero
--> $DIR/promoted_errors2.rs:21:14 --> $DIR/promoted_errors2.rs:22:14
| |
LL | let _x = 1 / (false as u32); LL | let _x = 1 / (false as u32);
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,43 @@
// check-pass
// compile-flags: --emit=mir,link
// Regression test for issue #68264
// Checks that we don't encounter overflow
// when running const-prop on functions with
// complicated bounds
pub trait Query {}
pub trait AsQuery {
type Query: Query;
}
pub trait Table: AsQuery + Sized {}
pub trait LimitDsl {
type Output;
}
pub(crate) trait LoadQuery<Conn, U>: RunQueryDsl<Conn> {}
impl<T: Query> AsQuery for T {
type Query = Self;
}
impl<T> LimitDsl for T
where
T: Table,
T::Query: LimitDsl,
{
type Output = <T::Query as LimitDsl>::Output;
}
pub(crate) trait RunQueryDsl<Conn>: Sized {
fn first<U>(self, _conn: &Conn) -> U
where
Self: LimitDsl,
Self::Output: LoadQuery<Conn, U>,
{
// Overflow is caused by this function body
unimplemented!()
}
}
fn main() {}

View file

@ -0,0 +1,19 @@
// run-pass
#![feature(track_caller)]
fn pass_to_ptr_call<T>(f: fn(T), x: T) {
f(x);
}
#[track_caller]
fn tracked_unit(_: ()) {
let expected_line = line!() - 1;
let location = std::panic::Location::caller();
assert_eq!(location.file(), file!());
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
}
fn main() {
pass_to_ptr_call(tracked_unit, ());
}

View file

@ -0,0 +1,19 @@
// run-pass
#![feature(track_caller)]
fn ptr_call(f: fn()) {
f();
}
#[track_caller]
fn tracked() {
let expected_line = line!() - 1;
let location = std::panic::Location::caller();
assert_eq!(location.file(), file!());
assert_eq!(location.line(), expected_line, "call shims report location as fn definition");
}
fn main() {
ptr_call(tracked);
}

View file

@ -110,6 +110,7 @@ static TARGETS: &[&str] = &[
"riscv32imac-unknown-none-elf", "riscv32imac-unknown-none-elf",
"riscv64imac-unknown-none-elf", "riscv64imac-unknown-none-elf",
"riscv64gc-unknown-none-elf", "riscv64gc-unknown-none-elf",
"riscv64gc-unknown-linux-gnu",
"s390x-unknown-linux-gnu", "s390x-unknown-linux-gnu",
"sparc64-unknown-linux-gnu", "sparc64-unknown-linux-gnu",
"sparcv9-sun-solaris", "sparcv9-sun-solaris",