diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index d80101753cbef..6abe19dc155d1 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -333,31 +333,31 @@ pub trait Hasher { #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i16(&mut self, i: i16) { - self.write(&i.to_ne_bytes()) + self.write_u16(i as u16) } /// Writes a single `i32` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i32(&mut self, i: i32) { - self.write(&i.to_ne_bytes()) + self.write_u32(i as u32) } /// Writes a single `i64` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i64(&mut self, i: i64) { - self.write(&i.to_ne_bytes()) + self.write_u64(i as u64) } /// Writes a single `i128` into this hasher. #[inline] #[stable(feature = "i128", since = "1.26.0")] fn write_i128(&mut self, i: i128) { - self.write(&i.to_ne_bytes()) + self.write_u128(i as u128) } /// Writes a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_isize(&mut self, i: isize) { - self.write(&i.to_ne_bytes()) + self.write_usize(i as usize) } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2b26e5303a89c..15466ce94a82e 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -279,9 +279,9 @@ pub mod primitive; // crate uses the this crate as its libcore. #[path = "../stdarch/crates/core_arch/src/mod.rs"] #[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] -// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_decl is +// FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. -#[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] +#[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))] #[unstable(feature = "stdsimd", issue = "48556")] mod core_arch; diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 57bacdd99eff4..6a50cdbc1d9fb 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2663,6 +2663,60 @@ impl [T] { { self.iter().is_sorted_by_key(f) } + + /// Returns the index of the partition point according to the given predicate + /// (the index of the first element of the second partition). + /// + /// The slice is assumed to be partitioned according to the given predicate. + /// This means that all elements for which the predicate returns true are at the start of the slice + /// and all elements for which the predicate returns false are at the end. + /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0 + /// (all odd numbers are at the start, all even at the end). + /// + /// If this slice is not partitioned, the returned result is unspecified and meaningless, + /// as this method performs a kind of binary search. + /// + /// # Examples + /// + /// ``` + /// #![feature(partition_point)] + /// + /// let v = [1, 2, 3, 3, 5, 6, 7]; + /// let i = v.partition_point(|&x| x < 5); + /// + /// assert_eq!(i, 4); + /// assert!(v[..i].iter().all(|&x| x < 5)); + /// assert!(v[i..].iter().all(|&x| !(x < 5))); + /// ``` + #[unstable(feature = "partition_point", reason = "new API", issue = "73831")] + pub fn partition_point

(&self, mut pred: P) -> usize + where + P: FnMut(&T) -> bool, + { + let mut left = 0; + let mut right = self.len(); + + while left != right { + let mid = left + (right - left) / 2; + // SAFETY: + // When left < right, left <= mid < right. + // Therefore left always increases and right always decreases, + // and eigher of them is selected. + // In both cases left <= right is satisfied. + // Therefore if left < right in a step, + // left <= right is satisfied in the next step. + // Therefore as long as left != right, 0 <= left < right <= len is satisfied + // and if this case 0 <= mid < len is satisfied too. + let value = unsafe { self.get_unchecked(mid) }; + if pred(value) { + left = mid + 1; + } else { + right = mid; + } + } + + left + } } #[lang = "slice_u8"] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 4e55452a4c31b..524c38a7ab4c1 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(const_forget)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] +#![feature(partition_point)] extern crate test; diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index cd46117f76322..fba73be92be09 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -81,6 +81,46 @@ fn test_binary_search_implementation_details() { assert_eq!(b.binary_search(&3), Ok(8)); } +#[test] +fn test_partition_point() { + let b: [i32; 0] = []; + assert_eq!(b.partition_point(|&x| x < 5), 0); + + let b = [4]; + assert_eq!(b.partition_point(|&x| x < 3), 0); + assert_eq!(b.partition_point(|&x| x < 4), 0); + assert_eq!(b.partition_point(|&x| x < 5), 1); + + let b = [1, 2, 4, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 4); + + let b = [1, 2, 4, 5, 6, 8]; + assert_eq!(b.partition_point(|&x| x < 9), 6); + + let b = [1, 2, 4, 6, 7, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 6), 3); + assert_eq!(b.partition_point(|&x| x < 5), 3); + assert_eq!(b.partition_point(|&x| x < 8), 5); + + let b = [1, 2, 4, 5, 6, 8, 9]; + assert_eq!(b.partition_point(|&x| x < 7), 5); + assert_eq!(b.partition_point(|&x| x < 0), 0); + + let b = [1, 3, 3, 3, 7]; + assert_eq!(b.partition_point(|&x| x < 0), 0); + assert_eq!(b.partition_point(|&x| x < 1), 0); + assert_eq!(b.partition_point(|&x| x < 2), 1); + assert_eq!(b.partition_point(|&x| x < 3), 1); + assert_eq!(b.partition_point(|&x| x < 4), 4); + assert_eq!(b.partition_point(|&x| x < 5), 4); + assert_eq!(b.partition_point(|&x| x < 6), 4); + assert_eq!(b.partition_point(|&x| x < 7), 4); + assert_eq!(b.partition_point(|&x| x < 8), 5); +} + #[test] fn test_iterator_nth() { let v: &[_] = &[0, 1, 2, 3, 4]; diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 863f525bdc8f3..bc0980f041b94 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -91,7 +91,7 @@ struct LoweringContext<'a, 'hir: 'a> { /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, - resolver: &'a mut dyn Resolver, + resolver: &'a mut dyn ResolverAstLowering, /// HACK(Centril): there is a cyclic dependency between the parser and lowering /// if we don't have this function pointer. To avoid that dependency so that @@ -172,7 +172,7 @@ struct LoweringContext<'a, 'hir: 'a> { allow_gen_future: Option>, } -pub trait Resolver { +pub trait ResolverAstLowering { fn def_key(&mut self, id: DefId) -> DefKey; fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize; @@ -299,7 +299,7 @@ impl<'a> ImplTraitContext<'_, 'a> { pub fn lower_crate<'a, 'hir>( sess: &'a Session, krate: &'a Crate, - resolver: &'a mut dyn Resolver, + resolver: &'a mut dyn ResolverAstLowering, nt_to_tokenstream: NtToTokenstream, arena: &'hir Arena<'hir>, ) -> hir::Crate<'hir> { diff --git a/src/librustc_builtin_macros/lib.rs b/src/librustc_builtin_macros/lib.rs index f56d8a372a73e..173a823dc7d52 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/src/librustc_builtin_macros/lib.rs @@ -15,7 +15,7 @@ extern crate proc_macro; use crate::deriving::*; -use rustc_expand::base::{MacroExpanderFn, Resolver, SyntaxExtension, SyntaxExtensionKind}; +use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Ident}; @@ -45,7 +45,7 @@ pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; -pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) { +pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) { let mut register = |name, kind| { resolver.register_builtin_macro( Ident::with_dummy_span(name), diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs index adaf5f03079eb..7cc9c1f76631e 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/src/librustc_builtin_macros/proc_macro_harness.rs @@ -6,7 +6,7 @@ use rustc_ast::expand::is_proc_macro_attr; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; use rustc_ast_pretty::pprust; -use rustc_expand::base::{ExtCtxt, Resolver}; +use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_session::parse::ParseSess; use rustc_span::hygiene::AstPass; @@ -52,7 +52,7 @@ struct CollectProcMacros<'a> { pub fn inject( sess: &ParseSess, - resolver: &mut dyn Resolver, + resolver: &mut dyn ResolverExpand, mut krate: ast::Crate, is_proc_macro_crate: bool, has_proc_macro_decls: bool, diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/src/librustc_builtin_macros/standard_library_imports.rs index cd3773c76c483..671ff8ce54f0e 100644 --- a/src/librustc_builtin_macros/standard_library_imports.rs +++ b/src/librustc_builtin_macros/standard_library_imports.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::{ast, attr}; -use rustc_expand::base::{ExtCtxt, Resolver}; +use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::ExpansionConfig; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; @@ -10,7 +10,7 @@ use rustc_span::DUMMY_SP; pub fn inject( mut krate: ast::Crate, - resolver: &mut dyn Resolver, + resolver: &mut dyn ResolverExpand, sess: &ParseSess, alt_std_name: Option, ) -> (ast::Crate, Option) { diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 34ed4c800e04f..da8bf2b8b5169 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -6,7 +6,7 @@ use rustc_ast::attr; use rustc_ast::entry::{self, EntryPointType}; use rustc_ast::mut_visit::{ExpectOne, *}; use rustc_ast::ptr::P; -use rustc_expand::base::{ExtCtxt, Resolver}; +use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::parse::ParseSess; @@ -37,7 +37,7 @@ struct TestCtxt<'a> { // existing main functions, and synthesizing a main test harness pub fn inject( sess: &ParseSess, - resolver: &mut dyn Resolver, + resolver: &mut dyn ResolverExpand, should_test: bool, krate: &mut ast::Crate, span_diagnostic: &rustc_errors::Handler, @@ -192,7 +192,7 @@ impl MutVisitor for EntryPointCleaner { /// Crawl over the crate, inserting test reexports and the test main function fn generate_test_harness( sess: &ParseSess, - resolver: &mut dyn Resolver, + resolver: &mut dyn ResolverExpand, reexport_test_harness_main: Option, krate: &mut ast::Crate, features: &Features, diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index d4c756c9ec7f8..757eee8bb46e1 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -889,7 +889,7 @@ pub enum InvocationRes { /// Error type that denotes indeterminacy. pub struct Indeterminate; -pub trait Resolver { +pub trait ResolverExpand { fn next_node_id(&mut self) -> NodeId; fn resolve_dollar_crates(&mut self); @@ -946,7 +946,7 @@ pub struct ExtCtxt<'a> { pub ecfg: expand::ExpansionConfig<'a>, pub reduced_recursion_limit: Option, pub root_path: PathBuf, - pub resolver: &'a mut dyn Resolver, + pub resolver: &'a mut dyn ResolverExpand, pub current_expansion: ExpansionData, pub expansions: FxHashMap>, /// Called directly after having parsed an external `mod foo;` in expansion. @@ -957,7 +957,7 @@ impl<'a> ExtCtxt<'a> { pub fn new( parse_sess: &'a ParseSess, ecfg: expand::ExpansionConfig<'a>, - resolver: &'a mut dyn Resolver, + resolver: &'a mut dyn ResolverExpand, extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, ) -> ExtCtxt<'a> { ExtCtxt { diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 8f8ce03d638c0..76ac61c067280 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -570,7 +570,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { /// Necessary because we can't write the following bound: /// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`. pub struct InferCtxtBuilder<'tcx> { - global_tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, fresh_tables: Option>>, } @@ -580,7 +580,7 @@ pub trait TyCtxtInferExt<'tcx> { impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { - InferCtxtBuilder { global_tcx: self, fresh_tables: None } + InferCtxtBuilder { tcx: self, fresh_tables: None } } } @@ -616,24 +616,22 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn enter(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self; + let InferCtxtBuilder { tcx, ref fresh_tables } = *self; let in_progress_tables = fresh_tables.as_ref(); - global_tcx.enter_local(|tcx| { - f(InferCtxt { - tcx, - in_progress_tables, - inner: RefCell::new(InferCtxtInner::new()), - lexical_region_resolutions: RefCell::new(None), - selection_cache: Default::default(), - evaluation_cache: Default::default(), - reported_trait_errors: Default::default(), - reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: tcx.sess.err_count(), - in_snapshot: Cell::new(false), - skip_leak_check: Cell::new(false), - universe: Cell::new(ty::UniverseIndex::ROOT), - }) + f(InferCtxt { + tcx, + in_progress_tables, + inner: RefCell::new(InferCtxtInner::new()), + lexical_region_resolutions: RefCell::new(None), + selection_cache: Default::default(), + evaluation_cache: Default::default(), + reported_trait_errors: Default::default(), + reported_closure_mismatch: Default::default(), + tainted_by_errors_flag: Cell::new(false), + err_count_on_creation: tcx.sess.err_count(), + in_snapshot: Cell::new(false), + skip_leak_check: Cell::new(false), + universe: Cell::new(ty::UniverseIndex::ROOT), }) } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d8f3caa2c4434..36d2954ac6ef7 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2055,12 +2055,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { } declare_lint! { - pub CLASHING_EXTERN_DECL, + pub CLASHING_EXTERN_DECLARATIONS, Warn, "detects when an extern fn has been declared with the same name but different types" } -pub struct ClashingExternDecl { +pub struct ClashingExternDeclarations { seen_decls: FxHashMap, } @@ -2083,9 +2083,9 @@ impl SymbolName { } } -impl ClashingExternDecl { +impl ClashingExternDeclarations { crate fn new() -> Self { - ClashingExternDecl { seen_decls: FxHashMap::default() } + ClashingExternDeclarations { seen_decls: FxHashMap::default() } } /// Insert a new foreign item into the seen set. If a symbol with the same name already exists /// for the item, return its HirId without updating the set. @@ -2211,18 +2211,18 @@ impl ClashingExternDecl { } } -impl_lint_pass!(ClashingExternDecl => [CLASHING_EXTERN_DECL]); +impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]); -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDecl { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDeclarations { fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, this_fi: &hir::ForeignItem<'_>) { - trace!("ClashingExternDecl: check_foreign_item: {:?}", this_fi); + trace!("ClashingExternDeclarations: check_foreign_item: {:?}", this_fi); if let ForeignItemKind::Fn(..) = this_fi.kind { let tcx = *&cx.tcx; if let Some(existing_hid) = self.insert(tcx, this_fi) { let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid)); let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id)); debug!( - "ClashingExternDecl: Comparing existing {:?}: {:?} to this {:?}: {:?}", + "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty ); // Check that the declarations match. @@ -2239,7 +2239,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ClashingExternDecl { }; // Finally, emit the diagnostic. tcx.struct_span_lint_hir( - CLASHING_EXTERN_DECL, + CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id, get_relevant_span(this_fi), |lint| { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b39abe7b411bb..4da98d201593b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -155,7 +155,7 @@ macro_rules! late_lint_passes { // and change this to a module lint pass MissingDebugImplementations: MissingDebugImplementations::default(), ArrayIntoIter: ArrayIntoIter, - ClashingExternDecl: ClashingExternDecl::new(), + ClashingExternDeclarations: ClashingExternDeclarations::new(), ] ); }; diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 44c8c1f6fdba4..e2f601371b1ee 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1560,28 +1560,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> GlobalCtxt<'tcx> { - /// Calls the closure with a local `TyCtxt` using the given arena. - /// `interners` is a slot passed so we can create a CtxtInterners - /// with the same lifetime as `arena`. - pub fn enter_local(&'tcx self, f: F) -> R - where - F: FnOnce(TyCtxt<'tcx>) -> R, - { - let tcx = TyCtxt { gcx: self }; - ty::tls::with_related_context(tcx, |icx| { - let new_icx = ty::tls::ImplicitCtxt { - tcx, - query: icx.query, - diagnostics: icx.diagnostics, - layout_depth: icx.layout_depth, - task_deps: icx.task_deps, - }; - ty::tls::enter_context(&new_icx, |_| f(tcx)) - }) - } -} - /// A trait implemented for all `X<'a>` types that can be safely and /// efficiently converted to `X<'tcx>` as long as they are part of the /// provided `TyCtxt<'tcx>`. @@ -1818,11 +1796,11 @@ pub mod tls { with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls"))) } - /// Allows access to the current `ImplicitCtxt` whose tcx field has the same global - /// interner as the tcx argument passed in. This means the closure is given an `ImplicitCtxt` - /// with the same `'tcx` lifetime as the `TyCtxt` passed in. - /// This will panic if you pass it a `TyCtxt` which has a different global interner from - /// the current `ImplicitCtxt`'s `tcx` field. + /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument + /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime + /// as the `TyCtxt` passed in. + /// This will panic if you pass it a `TyCtxt` which is different from the current + /// `ImplicitCtxt`'s `tcx` field. #[inline] pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R where diff --git a/src/librustc_mir/dataflow/impls/liveness.rs b/src/librustc_mir/dataflow/impls/liveness.rs index d24faacd3779e..784b0bd9293e2 100644 --- a/src/librustc_mir/dataflow/impls/liveness.rs +++ b/src/librustc_mir/dataflow/impls/liveness.rs @@ -92,7 +92,27 @@ impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> where T: GenKill, { + fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { + let mir::Place { projection, local } = *place; + + // We purposefully do not call `super_place` here to avoid calling `visit_local` for this + // place with one of the `Projection` variants of `PlaceContext`. + self.visit_projection(local, projection, context, location); + + match DefUse::for_place(context) { + // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use. + Some(_) if place.is_indirect() => self.0.gen(local), + + Some(DefUse::Def) if projection.is_empty() => self.0.kill(local), + Some(DefUse::Use) => self.0.gen(local), + _ => {} + } + } + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + // Because we do not call `super_place` above, `visit_local` is only called for locals that + // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use + // of the return place in a `Return` terminator or the index in an `Index` projection. match DefUse::for_place(context) { Some(DefUse::Def) => self.0.kill(local), Some(DefUse::Use) => self.0.gen(local), @@ -126,7 +146,6 @@ impl DefUse { | MutatingUseContext::AsmOutput | MutatingUseContext::Borrow | MutatingUseContext::Drop - | MutatingUseContext::Projection | MutatingUseContext::Retag, ) | PlaceContext::NonMutatingUse( @@ -134,11 +153,15 @@ impl DefUse { | NonMutatingUseContext::Copy | NonMutatingUseContext::Inspect | NonMutatingUseContext::Move - | NonMutatingUseContext::Projection | NonMutatingUseContext::ShallowBorrow | NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::UniqueBorrow, ) => Some(DefUse::Use), + + PlaceContext::MutatingUse(MutatingUseContext::Projection) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => { + unreachable!("A projection could be a def or a use and must be handled separately") + } } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 9c72a18c6d469..602876e3de168 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -132,6 +132,10 @@ pub enum LocalValue { } impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { + /// Read the local's value or error if the local is not yet live or not live anymore. + /// + /// Note: This may only be invoked from the `Machine::access_local` hook and not from + /// anywhere else. You may be invalidating machine invariants if you do! pub fn access(&self) -> InterpResult<'tcx, Operand> { match self.value { LocalValue::Dead => throw_ub!(DeadLocal), @@ -144,6 +148,9 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { /// Overwrite the local. If the local can be overwritten in place, return a reference /// to do so; otherwise return the `MemPlace` to consult instead. + /// + /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from + /// anywhere else. You may be invalidating machine invariants if you do! pub fn access_mut( &mut self, ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index b5dc40d955191..ec1c93c81657e 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -11,7 +11,7 @@ use rustc_span::def_id::DefId; use super::{ AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, - Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, + LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, }; /// Data returned by Machine::stack_pop, @@ -192,6 +192,8 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to read the specified `local` from the `frame`. + /// Since reading a ZST is not actually accessing memory or locals, this is never invoked + /// for ZST reads. #[inline] fn access_local( _ecx: &InterpCx<'mir, 'tcx, Self>, @@ -201,6 +203,21 @@ pub trait Machine<'mir, 'tcx>: Sized { frame.locals[local].access() } + /// Called to write the specified `local` from the `frame`. + /// Since writing a ZST is not actually accessing memory or locals, this is never invoked + /// for ZST reads. + #[inline] + fn access_local_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + frame: usize, + local: mir::Local, + ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> + where + 'tcx: 'mir, + { + ecx.stack_mut()[frame].locals[local].access_mut() + } + /// Called before a basic block terminator is executed. /// You can use this to detect endlessly running programs. #[inline] diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index fd55deaf83bba..b02b5219ba1a4 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -432,7 +432,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } - /// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local + /// Read from a local. Will not actually access the local if reading from a ZST. + /// Will not access memory, instead an indirect `Operand` is returned. + /// + /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an + /// OpTy from a local pub fn access_local( &self, frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 98a1cea97e220..3868150c6bd28 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -741,7 +741,7 @@ where // but not factored as a separate function. let mplace = match dest.place { Place::Local { frame, local } => { - match self.stack_mut()[frame].locals[local].access_mut()? { + match M::access_local_mut(self, frame, local)? { Ok(local) => { // Local can be updated in-place. *local = LocalValue::Live(Operand::Immediate(src)); @@ -974,7 +974,7 @@ where ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { let (mplace, size) = match place.place { Place::Local { frame, local } => { - match self.stack_mut()[frame].locals[local].access_mut()? { + match M::access_local_mut(self, frame, local)? { Ok(&mut local_val) => { // We need to make an allocation. @@ -998,7 +998,7 @@ where } // Now we can call `access_mut` again, asserting it goes well, // and actually overwrite things. - *self.stack_mut()[frame].locals[local].access_mut().unwrap().unwrap() = + *M::access_local_mut(self, frame, local).unwrap().unwrap() = LocalValue::Live(Operand::Indirect(mplace)); (mplace, Some(size)) } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index a891f12c8e15f..841f1c2b647f6 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -4,6 +4,7 @@ use std::cell::Cell; use rustc_ast::ast::Mutability; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::HirId; use rustc_index::bit_set::BitSet; @@ -28,7 +29,7 @@ use rustc_trait_selection::traits; use crate::const_eval::error_to_const_error; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState, - LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, + LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup, }; use crate::transform::{MirPass, MirSource}; @@ -151,11 +152,19 @@ impl<'tcx> MirPass<'tcx> for ConstProp { struct ConstPropMachine<'mir, 'tcx> { /// The virtual call stack. stack: Vec>, + /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end. + written_only_inside_own_block_locals: FxHashSet, + /// Locals that need to be cleared after every block terminates. + only_propagate_inside_block_locals: BitSet, } impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { - fn new() -> Self { - Self { stack: Vec::new() } + fn new(only_propagate_inside_block_locals: BitSet) -> Self { + Self { + stack: Vec::new(), + written_only_inside_own_block_locals: Default::default(), + only_propagate_inside_block_locals, + } } } @@ -227,6 +236,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> l.access() } + fn access_local_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + frame: usize, + local: Local, + ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> + { + if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) { + ecx.machine.written_only_inside_own_block_locals.insert(local); + } + ecx.machine.stack[frame].locals[local].access_mut() + } + fn before_access_global( _memory_extra: &(), _alloc_id: AllocId, @@ -274,8 +295,6 @@ struct ConstPropagator<'mir, 'tcx> { // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store // the last known `SourceInfo` here and just keep revisiting it. source_info: Option, - // Locals we need to forget at the end of the current block - locals_of_current_block: BitSet, } impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { @@ -313,8 +332,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let param_env = tcx.param_env(def_id).with_reveal_all(); let span = tcx.def_span(def_id); - let mut ecx = InterpCx::new(tcx, span, param_env, ConstPropMachine::new(), ()); let can_const_prop = CanConstProp::check(body); + let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len()); + for (l, mode) in can_const_prop.iter_enumerated() { + if *mode == ConstPropMode::OnlyInsideOwnBlock { + only_propagate_inside_block_locals.insert(l); + } + } + let mut ecx = InterpCx::new( + tcx, + span, + param_env, + ConstPropMachine::new(only_propagate_inside_block_locals), + (), + ); let ret = ecx .layout_of(body.return_ty().subst(tcx, substs)) @@ -345,7 +376,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), source_info: None, - locals_of_current_block: BitSet::new_empty(body.local_decls.len()), } } @@ -900,7 +930,6 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { Will remove it from const-prop after block is finished. Local: {:?}", place.local ); - self.locals_of_current_block.insert(place.local); } ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => { trace!("can't propagate into {:?}", place); @@ -1089,10 +1118,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { } } } - // We remove all Locals which are restricted in propagation to their containing blocks. - for local in self.locals_of_current_block.iter() { + + // We remove all Locals which are restricted in propagation to their containing blocks and + // which were modified in the current block. + // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const` + let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals); + for &local in locals.iter() { Self::remove_const(&mut self.ecx, local); } - self.locals_of_current_block.clear(); + locals.clear(); + // Put it back so we reuse the heap of the storage + self.ecx.machine.written_only_inside_own_block_locals = locals; + if cfg!(debug_assertions) { + // Ensure we are correctly erasing locals with the non-debug-assert logic. + for local in self.ecx.machine.only_propagate_inside_block_locals.iter() { + assert!( + self.get_const(local.into()).is_none() + || self + .layout_of(self.local_decls[local].ty) + .map_or(true, |layout| layout.is_zst()) + ) + } + } } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 72faa68d0b243..a92d451dfd006 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -19,7 +19,7 @@ use rustc_ast::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, use rustc_ast::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::token::{self, Token}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_attr as attr; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 0ca01a384e73e..1f36e1ed83de7 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -29,7 +29,7 @@ use crate::Resolver; use rustc_ast::ast; use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{self, Visitor}; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; use rustc_middle::ty; diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index dc8d1a8d3fdf9..c25a20210e026 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::*; use rustc_ast::token::{self, Token}; use rustc_ast::visit::{self, FnKind}; use rustc_ast::walk_list; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; diff --git a/src/librustc_resolve/imports.rs b/src/librustc_resolve/imports.rs index 8a6541b399e38..ded0ee8a96699 100644 --- a/src/librustc_resolve/imports.rs +++ b/src/librustc_resolve/imports.rs @@ -12,7 +12,7 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin use rustc_ast::ast::NodeId; use rustc_ast::unwrap_or; use rustc_ast::util::lev_distance::find_best_match_for_name; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::ptr_key::PtrKey; use rustc_errors::{pluralize, struct_span_err, Applicability}; diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index b8fb813ea155f..84ba9094ea16f 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -16,7 +16,7 @@ use rustc_ast::ptr::P; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{unwrap_or, walk_list}; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9ddcf9e1de7d1..dccaf76723a58 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -27,7 +27,7 @@ use rustc_ast::attr; use rustc_ast::node_id::NodeMap; use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::ptr_key::PtrKey; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 398b0e92d9d8c..3976e501c169f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -7,12 +7,11 @@ use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::ast::{self, NodeId}; -use rustc_ast_lowering::Resolver as ResolverAstLowering; +use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, StabilityLevel}; use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::SyntaxExtension; -use rustc_expand::base::{self, Indeterminate, InvocationRes}; +use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; use rustc_feature::is_builtin_attr_name; @@ -141,7 +140,7 @@ crate fn registered_attrs_and_tools( (registered_attrs, registered_tools) } -impl<'a> base::Resolver for Resolver<'a> { +impl<'a> ResolverExpand for Resolver<'a> { fn next_node_id(&mut self) -> NodeId { self.next_node_id() } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 0737008a94c9a..b4c91cced43bf 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -400,7 +400,7 @@ impl Seek for BufReader { /// in memory, like a `Vec`. /// /// It is critical to call [`flush`] before `BufWriter` is dropped. Though -/// dropping will attempt to flush the the contents of the buffer, any errors +/// dropping will attempt to flush the contents of the buffer, any errors /// that happen in the process of dropping will be ignored. Calling [`flush`] /// ensures that the buffer is empty and thus dropping will not even attempt /// file operations. diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 1d1cdda1257aa..773fab36be221 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -205,7 +205,7 @@ mod imp { #[cfg(target_arch = "aarch64")] extern "C" { fn objc_msgSend(obj: NsId, sel: Sel) -> NsId; - #[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] + #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))] #[link_name = "objc_msgSend"] fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId; } @@ -213,7 +213,7 @@ mod imp { #[cfg(not(target_arch = "aarch64"))] extern "C" { fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - #[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] + #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))] #[link_name = "objc_msgSend"] fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId; } diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs new file mode 100644 index 0000000000000..c32bd2847f837 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -0,0 +1,33 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Test(*const usize); + +type PassArg = (); + +unsafe extern "C" fn pass(args: PassArg) { + println!("Hello, world!"); +} + +impl Test { + pub fn call_me(&self) { + //~^ ERROR: using function pointers as const generic parameters is forbidden + self.0 = Self::trampiline:: as _ + } + + unsafe extern "C" fn trampiline< + Args: Sized, + const IDX: usize, + const FN: unsafe extern "C" fn(Args), + //~^ ERROR: using function pointers as const generic parameters is forbidden + >( + args: Args, + ) { + FN(args) + } +} + +fn main() { + let x = Test(); + x.call_me::() +} diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr new file mode 100644 index 0000000000000..6bb776fcfc017 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -0,0 +1,14 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:13:61 + | +LL | pub fn call_me(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:21:19 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-71382.rs b/src/test/ui/const-generics/issues/issue-71382.rs new file mode 100644 index 0000000000000..e0cf9812d95ec --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71382.rs @@ -0,0 +1,24 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Test(); + +fn pass() { + println!("Hello, world!"); +} + +impl Test { + pub fn call_me(&self) { + self.test::(); + } + + fn test(&self) { + //~^ ERROR: using function pointers as const generic parameters is forbidden + FN(); + } +} + +fn main() { + let x = Test(); + x.call_me() +} diff --git a/src/test/ui/const-generics/issues/issue-71382.stderr b/src/test/ui/const-generics/issues/issue-71382.stderr new file mode 100644 index 0000000000000..1652b0bdfa879 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71382.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:15:23 + | +LL | fn test(&self) { + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs new file mode 100644 index 0000000000000..64a049e743faf --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn func(outer: A) { + //~^ ERROR: using function pointers as const generic parameters is forbidden + F(outer); +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr new file mode 100644 index 0000000000000..9a7bf1c0a8841 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71611.rs:4:21 + | +LL | fn func(outer: A) { + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72352.rs b/src/test/ui/const-generics/issues/issue-72352.rs new file mode 100644 index 0000000000000..e977af8deb719 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72352.rs @@ -0,0 +1,21 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +use std::ffi::{CStr, CString}; + +unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { + //~^ ERROR: using function pointers as const generic parameters is forbidden + F(CStr::from_ptr(ptr)) +} + +fn safely_do_the_thing(s: &CStr) -> usize { + s.to_bytes().len() +} + +fn main() { + let baguette = CString::new("baguette").unwrap(); + let ptr = baguette.as_ptr(); + println!("{}", unsafe { + unsafely_do_the_thing::(ptr) + }); +} diff --git a/src/test/ui/const-generics/issues/issue-72352.stderr b/src/test/ui/const-generics/issues/issue-72352.stderr new file mode 100644 index 0000000000000..bc48da103936b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72352.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-72352.rs:6:42 + | +LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-1866.rs b/src/test/ui/issues/issue-1866.rs index 668baefa5e4ad..9f8a3a8262444 100644 --- a/src/test/ui/issues/issue-1866.rs +++ b/src/test/ui/issues/issue-1866.rs @@ -1,7 +1,7 @@ // build-pass #![allow(dead_code)] #![allow(non_camel_case_types)] -#![warn(clashing_extern_decl)] +#![warn(clashing_extern_declarations)] // pretty-expanded FIXME #23616 diff --git a/src/test/ui/issues/issue-1866.stderr b/src/test/ui/issues/issue-1866.stderr index 13c08ebd373ed..5edae48a10f23 100644 --- a/src/test/ui/issues/issue-1866.stderr +++ b/src/test/ui/issues/issue-1866.stderr @@ -10,8 +10,8 @@ LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool; note: the lint level is defined here --> $DIR/issue-1866.rs:4:9 | -LL | #![warn(clashing_extern_decl)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `unsafe extern "C" fn(*const usize) -> bool` found `unsafe extern "C" fn(*const bool) -> bool` diff --git a/src/test/ui/issues/issue-5791.rs b/src/test/ui/issues/issue-5791.rs index fda72a1b20e4a..d9be27250cdea 100644 --- a/src/test/ui/issues/issue-5791.rs +++ b/src/test/ui/issues/issue-5791.rs @@ -1,6 +1,6 @@ // run-pass #![allow(dead_code)] -#![warn(clashing_extern_decl)] +#![warn(clashing_extern_declarations)] // pretty-expanded FIXME #23616 extern { diff --git a/src/test/ui/issues/issue-5791.stderr b/src/test/ui/issues/issue-5791.stderr index 7ae83c43f1339..cf60e609deb31 100644 --- a/src/test/ui/issues/issue-5791.stderr +++ b/src/test/ui/issues/issue-5791.stderr @@ -12,8 +12,8 @@ LL | | fn malloc2(len: i32, foo: i32) -> *const u8; note: the lint level is defined here --> $DIR/issue-5791.rs:3:9 | -LL | #![warn(clashing_extern_decl)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `unsafe extern "C" fn(i32) -> *const u8` found `unsafe extern "C" fn(i32, i32) -> *const u8` diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index 32f3a78f4e980..544614100ba28 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -1,17 +1,17 @@ // check-pass // aux-build:external_extern_fn.rs #![crate_type = "lib"] -#![warn(clashing_extern_decl)] +#![warn(clashing_extern_declarations)] extern crate external_extern_fn; -extern { +extern "C" { fn clash(x: u8); fn no_clash(x: u8); } fn redeclared_different_signature() { - extern { + extern "C" { fn clash(x: u64); //~ WARN `clash` redeclared with a different signature } @@ -22,7 +22,7 @@ fn redeclared_different_signature() { } fn redeclared_same_signature() { - extern { + extern "C" { fn no_clash(x: u8); } unsafe { @@ -30,12 +30,12 @@ fn redeclared_same_signature() { } } -extern { +extern "C" { fn extern_fn(x: u64); } fn extern_clash() { - extern { + extern "C" { fn extern_fn(x: u32); //~ WARN `extern_fn` redeclared with a different signature } unsafe { @@ -49,7 +49,7 @@ fn extern_no_clash() { crate::extern_fn(123); } } -extern { +extern "C" { fn some_other_new_name(x: i16); #[link_name = "extern_link_name"] @@ -60,7 +60,7 @@ extern { } fn link_name_clash() { - extern { + extern "C" { fn extern_link_name(x: u32); //~^ WARN `extern_link_name` redeclared with a different signature @@ -75,85 +75,112 @@ fn link_name_clash() { } mod a { - extern { + extern "C" { fn different_mod(x: u8); } } mod b { - extern { + extern "C" { fn different_mod(x: u64); //~ WARN `different_mod` redeclared with a different signature } } -extern { +extern "C" { fn variadic_decl(x: u8, ...); } fn variadic_clash() { - extern { + extern "C" { fn variadic_decl(x: u8); //~ WARN `variadic_decl` redeclared with a different signature } } #[no_mangle] -fn no_mangle_name(x: u8) { } +fn no_mangle_name(x: u8) {} -extern { +extern "C" { #[link_name = "unique_link_name"] fn link_name_specified(x: u8); } fn tricky_no_clash() { - extern { + extern "C" { // Shouldn't warn, because the declaration above actually declares a different symbol (and // Rust's name resolution rules around shadowing will handle this gracefully). fn link_name_specified() -> u32; // The case of a no_mangle name colliding with an extern decl (see #28179) is related but - // shouldn't be reported by ClashingExternDecl, because this is an example of unmangled - // name clash causing bad behaviour in functions with a defined body. + // shouldn't be reported by ClashingExternDeclarations, because this is an example of + // unmangled name clash causing bad behaviour in functions with a defined body. fn no_mangle_name() -> u32; } } mod banana { mod one { - #[repr(C)] struct Banana { weight: u32, length: u16 } - extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + #[repr(C)] + struct Banana { + weight: u32, + length: u16, + } + extern "C" { + fn weigh_banana(count: *const Banana) -> u64; + } } mod two { - #[repr(C)] struct Banana { weight: u32, length: u16 } // note: distinct type - // This should not trigger the lint because two::Banana is structurally equivalent to - // one::Banana. - extern "C" { fn weigh_banana(count: *const Banana) -> u64; } + #[repr(C)] + struct Banana { + weight: u32, + length: u16, + } // note: distinct type + extern "C" { + // This should not trigger the lint because two::Banana is structurally equivalent to + // one::Banana. + fn weigh_banana(count: *const Banana) -> u64; + } } mod three { // This _should_ trigger the lint, because repr(packed) should generate a struct that has a // different layout. - #[repr(packed)] struct Banana { weight: u32, length: u16 } + #[repr(packed)] + struct Banana { + weight: u32, + length: u16, + } #[allow(improper_ctypes)] - extern "C" { fn weigh_banana(count: *const Banana) -> u64; } - //~^ WARN `weigh_banana` redeclared with a different signature + extern "C" { + fn weigh_banana(count: *const Banana) -> u64; + //~^ WARN `weigh_banana` redeclared with a different signature + } } } mod sameish_members { mod a { #[repr(C)] - struct Point { x: i16, y: i16 } + struct Point { + x: i16, + y: i16, + } - extern "C" { fn draw_point(p: Point); } + extern "C" { + fn draw_point(p: Point); + } } mod b { #[repr(C)] - struct Point { coordinates: [i16; 2] } + struct Point { + coordinates: [i16; 2], + } // It's possible we are overconservative for this case, as accessing the elements of the // coordinates array might end up correctly accessing `.x` and `.y`. However, this may not // always be the case, for every architecture and situation. This is also a really odd // thing to do anyway. - extern "C" { fn draw_point(p: Point); } //~ WARN `draw_point` redeclared with a different + extern "C" { + fn draw_point(p: Point); //~ WARN `draw_point` redeclared with a different + } } } diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index fb7bf135f538c..96e51ab5a3ec7 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -10,8 +10,8 @@ LL | fn clash(x: u64); note: the lint level is defined here --> $DIR/clashing-extern-fn.rs:4:9 | -LL | #![warn(clashing_extern_decl)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![warn(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `unsafe extern "C" fn(u8)` found `unsafe extern "C" fn(u64)` @@ -94,25 +94,25 @@ LL | fn variadic_decl(x: u8); found `unsafe extern "C" fn(u8)` warning: `weigh_banana` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:137:22 + --> $DIR/clashing-extern-fn.rs:154:13 | -LL | extern "C" { fn weigh_banana(count: *const Banana) -> u64; } - | --------------------------------------------- `weigh_banana` previously declared here +LL | fn weigh_banana(count: *const Banana) -> u64; + | --------------------------------------------- `weigh_banana` previously declared here ... -LL | extern "C" { fn weigh_banana(count: *const Banana) -> u64; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn weigh_banana(count: *const Banana) -> u64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` found `unsafe extern "C" fn(*const banana::three::Banana) -> u64` warning: `draw_point` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:157:22 + --> $DIR/clashing-extern-fn.rs:183:13 | -LL | extern "C" { fn draw_point(p: Point); } - | ------------------------ `draw_point` previously declared here +LL | fn draw_point(p: Point); + | ------------------------ `draw_point` previously declared here ... -LL | extern "C" { fn draw_point(p: Point); } - | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn draw_point(p: Point); + | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(sameish_members::a::Point)` found `unsafe extern "C" fn(sameish_members::b::Point)` diff --git a/src/test/ui/lint/dead-code/lint-dead-code-3.rs b/src/test/ui/lint/dead-code/lint-dead-code-3.rs index ff33abfa64586..fe3c392ccf100 100644 --- a/src/test/ui/lint/dead-code/lint-dead-code-3.rs +++ b/src/test/ui/lint/dead-code/lint-dead-code-3.rs @@ -1,6 +1,6 @@ #![allow(unused_variables)] #![allow(non_camel_case_types)] -#![allow(clashing_extern_decl)] +#![allow(clashing_extern_declarations)] #![deny(dead_code)] #![crate_type="lib"] diff --git a/src/test/ui/mir-dataflow/liveness-projection.rs b/src/test/ui/mir-dataflow/liveness-projection.rs new file mode 100644 index 0000000000000..486f31b635dca --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-projection.rs @@ -0,0 +1,32 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() { + { + let mut x: (i32, i32) = (42, 0); + + // Assignment to a projection does not cause `x` to become live + unsafe { rustc_peek(x); } //~ ERROR bit not set + x.1 = 42; + + x = (0, 42); + + // ...but a read from a projection does. + unsafe { rustc_peek(x); } + println!("{}", x.1); + } + + { + let mut x = 42; + + // Derefs are treated like a read of a local even if they are on the LHS of an assignment. + let p = &mut x; + unsafe { rustc_peek(&p); } + *p = 24; + unsafe { rustc_peek(&p); } //~ ERROR bit not set + } +} + +fn main() {} diff --git a/src/test/ui/mir-dataflow/liveness-projection.stderr b/src/test/ui/mir-dataflow/liveness-projection.stderr new file mode 100644 index 0000000000000..f9480c880908a --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-projection.stderr @@ -0,0 +1,16 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-projection.rs:11:18 + | +LL | unsafe { rustc_peek(x); } + | ^^^^^^^^^^^^^ + +error: rustc_peek: bit not set + --> $DIR/liveness-projection.rs:28:18 + | +LL | unsafe { rustc_peek(&p); } + | ^^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs index a516aa44c6576..8f5d7f4f7f8fd 100644 --- a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs +++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs @@ -1,4 +1,4 @@ -#![allow(clashing_extern_decl)] +#![allow(clashing_extern_declarations)] // check-pass // In this test we check that the parser accepts an ABI string when it