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.
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,
/// and should be considered unusable (unless of course it was
/// 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
/// 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::ops::Deref;
use crate::result;
use crate::slice;
use crate::str;
mod builders;
@ -234,8 +233,6 @@ pub struct Formatter<'a> {
precision: Option<usize>,
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,
@ -1043,8 +1040,6 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
buf: output,
align: rt::v1::Alignment::Unknown,
fill: ' ',
args: args.args,
curarg: args.args.iter(),
};
let mut idx = 0;
@ -1063,7 +1058,7 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
// a string piece.
for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
formatter.buf.write_str(*piece)?;
formatter.run(arg)?;
run(&mut formatter, arg, &args.args)?;
idx += 1;
}
}
@ -1077,6 +1072,39 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
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`.
#[must_use = "don't forget to write the post padding"]
struct PostPadding {
@ -1114,41 +1142,6 @@ impl<'a> Formatter<'a> {
align: self.align,
width: self.width,
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)]
pub struct Argument {
#[cfg(bootstrap)]
pub position: Position,
#[cfg(not(bootstrap))]
pub position: usize,
pub format: FormatSpec,
}
@ -37,12 +40,11 @@ pub enum Alignment {
pub enum Count {
Is(usize),
Param(usize),
NextParam,
Implied,
}
#[cfg(bootstrap)]
#[derive(Copy, Clone)]
pub enum Position {
Next,
At(usize),
}

View File

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

View File

@ -1156,11 +1156,11 @@ rustc_queries! {
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
desc { |tcx|
"testing substituted normalized predicates in mode {:?}:`{}`",
key.2, tcx.def_path_str(key.0)
"testing substituted normalized predicates:`{}`",
tcx.def_path_str(key.0)
}
}

View File

@ -16,7 +16,6 @@ use super::CodeSelectionError;
use super::{ConstEvalFailure, Unimplemented};
use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation};
use crate::traits::TraitQueryMode;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
type Predicate = ty::Predicate<'tcx>;
@ -63,9 +62,6 @@ pub struct FulfillmentContext<'tcx> {
// a snapshot (they don't *straddle* a snapshot, so there
// is no trouble there).
usable_in_snapshot: bool,
// The `TraitQueryMode` used when constructing a `SelectionContext`
query_mode: TraitQueryMode,
}
#[derive(Clone, Debug)]
@ -79,26 +75,12 @@ pub struct PendingPredicateObligation<'tcx> {
static_assert_size!(PendingPredicateObligation<'_>, 136);
impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context with `TraitQueryMode::Standard`
/// You almost always want to use this instead of `with_query_mode`
/// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
register_region_obligations: true,
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(),
register_region_obligations: true,
usable_in_snapshot: true,
query_mode: TraitQueryMode::Standard,
}
}
@ -116,7 +97,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
predicates: ObligationForest::new(),
register_region_obligations: false,
usable_in_snapshot: false,
query_mode: TraitQueryMode::Standard,
}
}
@ -237,7 +217,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
&mut self,
infcx: &InferCtxt<'_, '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)
}

View File

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

View File

@ -141,7 +141,12 @@ impl<'tcx> InstanceDef<'tcx> {
}
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>) {
fn query_crate(&self) -> CrateNum {
self.1.def_id().krate

View File

@ -590,17 +590,6 @@ impl<'a, 'b> Context<'a, 'b> {
parse::NextArgument(ref arg) => {
// Build the position
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 {
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => {
// Map to index in final generated argument array
@ -615,7 +604,7 @@ impl<'a, 'b> Context<'a, 'b> {
arg_idx
}
};
pos("At", Some(arg_idx))
self.ecx.expr_usize(sp, arg_idx)
}
// 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 {
ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
ty::InstanceDef::VtableShim(def_id) => {
build_call_shim(tcx, instance, Adjustment::DerefMove, CallKind::Direct(def_id), None)
}
ty::InstanceDef::VtableShim(def_id) => build_call_shim(
tcx,
instance,
Some(Adjustment::DerefMove),
CallKind::Direct(def_id),
None,
),
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
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 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
// 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
// (such as `#[track_caller]`).
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: _ } => {
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()
.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::CloneShim(def_id, ty) => {
@ -648,7 +658,7 @@ impl CloneShimBuilder<'tcx> {
fn build_call_shim<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
rcvr_adjustment: Adjustment,
rcvr_adjustment: Option<Adjustment>,
call_kind: CallKind,
untuple_args: Option<&[Ty<'tcx>]>,
) -> BodyAndCache<'tcx> {
@ -680,14 +690,16 @@ fn build_call_shim<'tcx>(
let mut local_decls = local_decls_for_sig(&sig, span);
let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
let rcvr_arg = Local::new(1 + 0);
let rcvr_l = Place::from(rcvr_arg);
let rcvr_place = || {
assert!(rcvr_adjustment.is_some());
Place::from(Local::new(1 + 0))
};
let mut statements = vec![];
let rcvr = match rcvr_adjustment {
Adjustment::Identity => Operand::Move(rcvr_l),
Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_l)),
Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_l)),
let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
Adjustment::Identity => Operand::Move(rcvr_place()),
Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_place())),
Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())),
Adjustment::RefMut => {
// let rcvr = &mut rcvr;
let ref_rcvr = local_decls.push(temp_decl(
@ -703,15 +715,15 @@ fn build_call_shim<'tcx>(
source_info,
kind: StatementKind::Assign(box (
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))
}
};
});
let (callee, mut args) = match call_kind {
CallKind::Indirect => (rcvr, vec![]),
CallKind::Indirect => (rcvr.unwrap(), vec![]),
CallKind::Direct(def_id) => {
let ty = tcx.type_of(def_id);
(
@ -720,21 +732,35 @@ fn build_call_shim<'tcx>(
user_ty: None,
literal: ty::Const::zero_sized(tcx, ty),
}),
vec![rcvr],
rcvr.into_iter().collect::<Vec<_>>(),
)
}
};
if let Some(untuple_args) = untuple_args {
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
let arg_place = Place::from(Local::new(1 + 1));
Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity))
}));
} else {
args.extend((1..sig.inputs().len()).map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
let mut arg_range = 0..sig.inputs().len();
// Take the `self` ("receiver") argument out of the range (it's adjusted above).
if rcvr_adjustment.is_some() {
arg_range.start += 1;
}
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 block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
@ -752,7 +778,7 @@ fn build_call_shim<'tcx>(
func: callee,
args,
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))
} else {
None
@ -762,13 +788,13 @@ fn build_call_shim<'tcx>(
false,
);
if let Adjustment::RefMut = rcvr_adjustment {
if let Some(Adjustment::RefMut) = rcvr_adjustment {
// BB #1 - drop for Self
block(
&mut blocks,
vec![],
TerminatorKind::Drop {
location: Place::from(rcvr_arg),
location: rcvr_place(),
target: BasicBlock::new(2),
unwind: None,
},
@ -777,13 +803,13 @@ fn build_call_shim<'tcx>(
}
// BB #1/#2 - return
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
block(
&mut blocks,
vec![],
TerminatorKind::Drop {
location: Place::from(rcvr_arg),
location: rcvr_place(),
target: BasicBlock::new(4),
unwind: None,
},

View File

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

View File

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

View File

@ -15,6 +15,11 @@ pub async fn baz<T>(a: T) -> T {
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 {}
impl Bar for () {}
@ -26,8 +31,10 @@ pub async fn quux() -> impl Bar {
// @has async_fn/struct.Foo.html
// @matches - '//code' 'pub async fn f\(\)$'
// @matches - '//code' 'pub async unsafe fn g\(\)$'
pub struct Foo;
impl Foo {
pub async fn f() {}
pub async unsafe fn g() {}
}

View File

@ -2,15 +2,15 @@
// edition:2018
// compile-flags: --crate-type lib
use std::{
cell::RefCell,
fmt::Debug,
rc::Rc,
};
use std::{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) {}
@ -53,5 +53,4 @@ pub fn pass_assert() {
//~^ ERROR future cannot be sent between threads safely
assert_send(non_sync_with_method_call());
//~^ ERROR future cannot be sent between threads safely
//~^^ ERROR future cannot be sent between threads safely
}

View File

@ -62,27 +62,5 @@ LL | }
LL | }
| - `f` is later dropped here
error: future cannot be sent between threads safely
--> $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
error: aborting due to 3 previous errors

View File

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

View File

@ -1,17 +1,17 @@
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] };
| ^^^^^^^^^^^^
|
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)]
| ^^^^^^^^^
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] };
| ---^^^^^^^^^^^^--
@ -19,7 +19,7 @@ LL | &{ [1, 2, 3][4] };
| indexing out of bounds: the len is 3 but the index is 4
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] };
| ^^^^^^^^^^^^^^^^^ referenced constant has errors

View File

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

View File

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

View File

@ -1,4 +1,5 @@
// 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
#![warn(const_err)]

View File

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

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",
"riscv64imac-unknown-none-elf",
"riscv64gc-unknown-none-elf",
"riscv64gc-unknown-linux-gnu",
"s390x-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"sparcv9-sun-solaris",