From 2ccf65c7eba519dcc407cb76f08d04ac00d05851 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Mon, 30 Dec 2019 14:25:53 +0000 Subject: [PATCH 01/17] Remove appendix from LICENCE-APACHE --- LICENSE-APACHE | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 16fe87b06e802..1b5ec8b78e237 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -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. From d088d8a2c1bd706c458d36eac941949169514d86 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 16 Jan 2020 18:47:52 -0500 Subject: [PATCH 02/17] Revert previous attempt at detecting unsatisfiable predicates --- src/librustc/mir/mono.rs | 5 +---- src/librustc/query/mod.rs | 6 +++--- src/librustc/traits/fulfill.rs | 24 ++---------------------- src/librustc/traits/mod.rs | 20 ++++++++------------ src/librustc/ty/query/keys.rs | 9 --------- 5 files changed, 14 insertions(+), 50 deletions(-) diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index e7a4c5b592105..51ce575e51f3b 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -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 { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index a20e011b91a75..f4c262fbac1d4 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1148,11 +1148,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) } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 9e5abc80822c7..46ece6fc40593 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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>> { - let mut selcx = SelectionContext::with_query_mode(infcx, self.query_mode); + let mut selcx = SelectionContext::new(infcx); self.select(&mut selcx) } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 31de5409fc8be..7509c2251f083 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -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>, - 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; } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 3fb3720a5638a..cbf335ad607ef 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -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 From 171fe82efc2ab420e3fe2e9ad5a44db093a751f1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 16 Jan 2020 18:53:51 -0500 Subject: [PATCH 03/17] Filter and test predicates using `normalize_and_test_predicates` for const-prop Fixes #68264 Previously, I attempted to use `substitute_normalize_and_test_predicates` to detect unsatisfiable bounds. Unfortunately, since const-prop runs in a generic environment (we don't have any of the function's generic parameters substituted), this could lead to cycle errors when attempting to normalize predicates. This check is replaced with a more precise check. We now only call `normalize_and_test_predicates` on predicates that have the possibility of being proved unsatisfiable - that is, predicates that don't depend on anything local to the function (e.g. generic parameters). This ensures that we don't hit cycle errors when we normalize said predicates, while still ensuring that we detect unsatisfiable predicates. --- src/librustc_mir/transform/const_prop.rs | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 9d5dbe3564ee0..badca10569404 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -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 substituging 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. `` + // 2. We avoid trying to normalize predicates involving generic + // parameters (e.g. `::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; } From c431cd751f6b0257443cd4d25c67ab36a8e9bc12 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 17 Jan 2020 08:13:04 -0500 Subject: [PATCH 04/17] Fix typo Co-Authored-By: Oliver Scherer --- src/librustc_mir/transform/const_prop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index badca10569404..5cbee929019dd 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -92,7 +92,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // // 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 substituging generic + // (e.g. we are evaluating a function without substituting generic // parameters, so this filtering serves two purposes: // // 1. We skip evaluating any predicates that we would From 3fef3d8b76e70da88366e45a62f98592cf9be76c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 17 Jan 2020 08:22:40 -0500 Subject: [PATCH 05/17] Add @weiznich's regression test --- src/test/ui/consts/issue-68264-overflow.rs | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/ui/consts/issue-68264-overflow.rs diff --git a/src/test/ui/consts/issue-68264-overflow.rs b/src/test/ui/consts/issue-68264-overflow.rs new file mode 100644 index 0000000000000..8f21e0648d4c7 --- /dev/null +++ b/src/test/ui/consts/issue-68264-overflow.rs @@ -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: RunQueryDsl {} + +impl AsQuery for T { + type Query = Self; +} + +impl LimitDsl for T +where + T: Table, + T::Query: LimitDsl, +{ + type Output = ::Output; +} + +pub(crate) trait RunQueryDsl: Sized { + fn first(self, _conn: &Conn) -> U + where + Self: LimitDsl, + Self::Output: LoadQuery, + { + // Overflow is caused by this function body + unimplemented!() + } +} + +fn main() {} From 8fa8b81a7701ba8c14476d86b641d5cbe6cfa713 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Jan 2020 00:34:33 +0300 Subject: [PATCH 06/17] Fix some tests failing in `--pass check` mode --- src/test/ui/consts/array-literal-index-oob.rs | 1 + .../ui/consts/array-literal-index-oob.stderr | 8 +++---- .../ui/consts/const-eval/promoted_errors.rs | 1 + .../consts/const-eval/promoted_errors.stderr | 20 ++++++++--------- .../ui/consts/const-eval/promoted_errors2.rs | 1 + .../consts/const-eval/promoted_errors2.stderr | 22 +++++++++---------- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index 64aeb46894d16..af63d1f75a770 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -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)] diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 50ad8e83e905c..e93aa324784c3 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -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 diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index fee232185d29a..22f863fb15ac4 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -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)] diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 4de22fdf4ab1e..b4330deb3ef10 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -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); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs index 41a989d91c5d3..62c77f76d9064 100644 --- a/src/test/ui/consts/const-eval/promoted_errors2.rs +++ b/src/test/ui/consts/const-eval/promoted_errors2.rs @@ -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)] diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr index 4f7ba8bf385d3..a4dad295edd79 100644 --- a/src/test/ui/consts/const-eval/promoted_errors2.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr @@ -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); | ^^^^^^^^^^^^^^^^^^ From 45dd44c0e130479e6532ddb0505401a41884d2bb Mon Sep 17 00:00:00 2001 From: msizanoen1 <55322658+msizanoen1@users.noreply.github.com> Date: Sat, 18 Jan 2020 18:59:51 +0700 Subject: [PATCH 07/17] Add `riscv64gc-unknown-linux-gnu` into target list in build-manifest Missed in #68037 r? @alexcrichton --- src/tools/build-manifest/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 481163a1a9abe..cff04e197e48a 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -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", From fd90e56120c9fec88808f9464e27283b0c6954ad Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 16 Jan 2020 18:58:32 -0800 Subject: [PATCH 08/17] Add failing #[track_caller] test with fn pointers. --- .../tracked-fn-ptr-with-arg.rs | 16 ++++++++++++++++ .../ui/rfc-2091-track-caller/tracked-fn-ptr.rs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs create mode 100644 src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs new file mode 100644 index 0000000000000..210a4f22f09cd --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(track_caller)] + +fn pass_to_ptr_call(f: fn(T), x: T) { + f(x); +} + +#[track_caller] +fn tracked_unit(_: ()) { + assert_eq!(std::panic::Location::caller().file(), file!()); +} + +fn main() { + pass_to_ptr_call(tracked_unit, ()); +} diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs new file mode 100644 index 0000000000000..1ce8f678b60f7 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(track_caller)] + +fn ptr_call(f: fn()) { + f(); +} + +#[track_caller] +fn tracked() { + assert_eq!(std::panic::Location::caller().file(), file!()); +} + +fn main() { + ptr_call(tracked); +} From 0ee922123facae1a170257bf1d6c493f8fa9f29e Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 16 Jan 2020 19:23:45 -0800 Subject: [PATCH 09/17] InstanceDef::requires_caller_location limited to items. --- src/librustc/ty/instance.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 9be50d19a5030..1ea695e40b255 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -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, + } } } From 19d8527890b59ed25432fbf5a9f1bd75ac814ae2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sun, 19 Jan 2020 21:21:48 +0200 Subject: [PATCH 10/17] rustc_mir: don't require a self argument for ReifyShim. --- src/librustc_mir/shim.rs | 80 ++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 01cecdd067945..b84616142cb07 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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, 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::>(), ) } }; + 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; + } + + // 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)| { - let arg_place = Place::from(Local::new(1 + 1)); - Operand::Move(tcx.mk_place_field(arg_place, Field::new(i), *ity)) + Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity)) })); - } 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 }; + 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, }, From 72dffac6cf170c6c16c043299e35848014aae8d4 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 19 Jan 2020 14:25:43 -0800 Subject: [PATCH 11/17] Test that ReifyShim + caller_location return the def site. --- src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs | 5 ++++- src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs index 210a4f22f09cd..0407eafbfd41c 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -8,7 +8,10 @@ fn pass_to_ptr_call(f: fn(T), x: T) { #[track_caller] fn tracked_unit(_: ()) { - assert_eq!(std::panic::Location::caller().file(), file!()); + 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() { diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs index 1ce8f678b60f7..a4baaa26ced1e 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -8,7 +8,10 @@ fn ptr_call(f: fn()) { #[track_caller] fn tracked() { - assert_eq!(std::panic::Location::caller().file(), file!()); + 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() { From 6be3446f92b444cd6584c7948be9f7cf20ce5518 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Mon, 20 Jan 2020 10:01:17 +0000 Subject: [PATCH 12/17] Added minor clarification to specification of realloc. The `layout` for the returned allocation of a `realloc` is only implicitly specified. This change makes it explicit. --- src/libcore/alloc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 4354e1c7b5f69..09f743fb81e4c 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -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 From fdef4f185ea6a1b560c1370c10ee561135af483d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 1 Jan 2020 13:14:33 -0500 Subject: [PATCH 13/17] Delete unused "next" variants from formatting infrastructure The formatting infrastructure stopped emitting these a while back, and in removing them we can simplify related code. --- src/libcore/fmt/mod.rs | 19 +++++++++++-------- src/libcore/fmt/rt/v1.rs | 6 ++++-- src/librustc_builtin_macros/format.rs | 13 +------------ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e68f3c58a3e07..64c270522d39d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -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,7 +233,6 @@ pub struct Formatter<'a> { precision: Option, buf: &'a mut (dyn Write + 'a), - curarg: slice::Iter<'a, ArgumentV1<'a>>, args: &'a [ArgumentV1<'a>], } @@ -1044,7 +1042,6 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { align: rt::v1::Alignment::Unknown, fill: ' ', args: args.args, - curarg: args.args.iter(), }; let mut idx = 0; @@ -1117,7 +1114,6 @@ impl<'a> Formatter<'a> { // These only exist in the struct for the `run` method, // which won’t be used together with this method. - curarg: self.curarg.clone(), args: self.args, } } @@ -1134,9 +1130,17 @@ impl<'a> Formatter<'a> { 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], + let value = { + #[cfg(bootstrap)] + { + match arg.position { + rt::v1::Position::At(i) => self.args[i], + } + } + #[cfg(not(bootstrap))] + { + self.args[arg.position] + } }; // Then actually do some printing @@ -1148,7 +1152,6 @@ impl<'a> Formatter<'a> { 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(), } } diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs index 826ae36d2d100..fd81f93242b89 100644 --- a/src/libcore/fmt/rt/v1.rs +++ b/src/libcore/fmt/rt/v1.rs @@ -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), } diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs index 6fca74e223944..3f4e24ca993db 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/src/librustc_builtin_macros/format.rs @@ -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 From 4919b96f81d9df0a7c0fe83ad5d66cef18ddfcfb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 1 Jan 2020 13:58:57 -0500 Subject: [PATCH 14/17] Move run/getcount to functions These are only called from one place and don't generally support being called from other places; furthermore, they're the only formatter functions that look at the `args` field (which a future commit will remove). --- src/libcore/fmt/mod.rs | 73 ++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 64c270522d39d..e76a8490f51fe 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1060,7 +1060,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)?; idx += 1; } } @@ -1074,6 +1074,40 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } +fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument) -> Result { + // Fill in the format parameters into the formatter + fmt.fill = arg.format.fill; + fmt.align = arg.format.align; + fmt.flags = arg.format.flags; + fmt.width = getcount(&fmt.args, &arg.format.width); + fmt.precision = getcount(&fmt.args, &arg.format.precision); + + // Extract the correct argument + let value = { + #[cfg(bootstrap)] + { + match arg.position { + rt::v1::Position::At(i) => fmt.args[i], + } + } + #[cfg(not(bootstrap))] + { + fmt.args[arg.position] + } + }; + + // Then actually do some printing + (value.formatter)(value.value, fmt) +} + +fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option { + 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 { @@ -1118,43 +1152,6 @@ impl<'a> Formatter<'a> { } } - // 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 = { - #[cfg(bootstrap)] - { - match arg.position { - rt::v1::Position::At(i) => self.args[i], - } - } - #[cfg(not(bootstrap))] - { - self.args[arg.position] - } - }; - - // Then actually do some printing - (value.formatter)(value.value, self) - } - - fn getcount(&mut self, cnt: &rt::v1::Count) -> Option { - match *cnt { - rt::v1::Count::Is(n) => Some(n), - rt::v1::Count::Implied => None, - rt::v1::Count::Param(i) => self.args[i].as_usize(), - } - } - // Helper methods used for padding and processing formatting arguments that // all formatting traits can use. From 9ae32c9b27e5c13e6903c21856a403ec7067cadd Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 1 Jan 2020 14:09:50 -0500 Subject: [PATCH 15/17] Drop args from Formatter These are no longer used by Formatter methods. --- src/libcore/fmt/mod.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e76a8490f51fe..900ef63f1dfcc 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -233,7 +233,6 @@ pub struct Formatter<'a> { precision: Option, buf: &'a mut (dyn Write + 'a), - args: &'a [ArgumentV1<'a>], } // NB. Argument is essentially an optimized partially applied formatting function, @@ -1041,7 +1040,6 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { buf: output, align: rt::v1::Alignment::Unknown, fill: ' ', - args: args.args, }; let mut idx = 0; @@ -1060,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)?; - run(&mut formatter, arg)?; + run(&mut formatter, arg, &args.args)?; idx += 1; } } @@ -1074,25 +1072,24 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { Ok(()) } -fn run(fmt: &mut Formatter<'_>, arg: &rt::v1::Argument) -> Result { - // Fill in the format parameters into the formatter +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(&fmt.args, &arg.format.width); - fmt.precision = getcount(&fmt.args, &arg.format.precision); + 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) => fmt.args[i], + rt::v1::Position::At(i) => args[i], } } #[cfg(not(bootstrap))] { - fmt.args[arg.position] + args[arg.position] } }; @@ -1145,10 +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 won’t be used together with this method. - args: self.args, } } From a804a455289cfa6d39ec92903959c4614c48d080 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 20 Jan 2020 12:17:12 -0500 Subject: [PATCH 16/17] Fix UI test fmt::Formatter is still not Send/Sync, but the UI test emitted two errors, for the dyn Write and the Void inside Formatter. As of this PR, the Void is now gone, but the dyn Write remains. --- src/test/ui/async-await/async-fn-nonsend.rs | 15 ++++++------ .../ui/async-await/async-fn-nonsend.stderr | 24 +------------------ 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs index 645c903c6bab2..ceeebbca5195a 100644 --- a/src/test/ui/async-await/async-fn-nonsend.rs +++ b/src/test/ui/async-await/async-fn-nonsend.rs @@ -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) {} @@ -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 } diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 5c870ca2d0276..105fd23ecfb66 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -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 From 3e0bfe1238e26ce57c2201172f0a4bb7cfbbba0a Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Mon, 20 Jan 2020 18:14:51 +0000 Subject: [PATCH 17/17] rustdoc: Correct order of `async` and `unsafe` in `async unsafe fn`s --- src/librustdoc/html/render.rs | 10 +++++----- src/test/rustdoc/async-fn.rs | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9406803825350..ab38eec5f3ea9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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}", 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, diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index 5f9708a39722a..5a03e821e8a2f 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -15,6 +15,11 @@ pub async fn baz(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() {} }