diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index f51b0086dc8b6..8730aeb0f3bff 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -52,7 +52,10 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { // when we try to compute the "horizontal trim". let lines = if kind == CommentKind::Block { // Whatever happens, we skip the first line. - let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 }; + let mut i = lines + .get(0) + .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 }) + .unwrap_or(0); let mut j = lines.len(); while i < j && lines[i].trim().is_empty() { diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 990b88295690c..72397aa2500f9 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -13,7 +13,7 @@ pub fn expand_compile_error<'cx>( return DummyResult::any(sp); }; - cx.span_err(sp, &var); + cx.span_err(sp, var.as_str()); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 66ee93ce3c90e..b8828fa671a5d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -21,8 +21,8 @@ pub fn expand_option_env<'cx>( }; let sp = cx.with_def_site_ctxt(sp); - let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern); - cx.sess.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value)); + let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern); + cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index ece250f61d54f..2817fce463b91 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -104,7 +104,7 @@ pub fn expand_include<'cx>( return DummyResult::any(sp); }; // The file will be added to the code map by the parser - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); @@ -176,7 +176,7 @@ pub fn expand_include_str( let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { return DummyResult::any(sp); }; - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); @@ -210,7 +210,7 @@ pub fn expand_include_bytes( let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { return DummyResult::any(sp); }; - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 6c22296db716d..7f15bc75fda23 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -288,8 +288,8 @@ fn load_imported_symbols_for_jit( match data[cnum.as_usize() - 1] { Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - let name = &crate_info.crate_name[&cnum]; - let mut err = sess.struct_err(&format!("Can't load static lib {}", name.as_str())); + let name = crate_info.crate_name[&cnum]; + let mut err = sess.struct_err(&format!("Can't load static lib {}", name)); err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); err.emit(); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a727da0570449..cf32d558d4a51 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -216,7 +216,7 @@ pub fn each_linked_rlib( Some(_) => {} None => return Err("could not find formats for rlibs".to_string()), } - let name = &info.crate_name[&cnum]; + let name = info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.rlib { f(cnum, &path); @@ -467,7 +467,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { - let name = &codegen_results.crate_info.crate_name[&cnum]; + let name = codegen_results.crate_info.crate_name[&cnum]; let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; // Here when we include the rlib into our staticlib we need to make a diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 010560248054e..7933afb50e8ce 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -861,7 +861,7 @@ impl CrateInfo { for &cnum in crates.iter() { info.native_libraries .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); - info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); + info.crate_name.insert(cnum, tcx.crate_name(cnum)); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum).clone()); if tcx.is_compiler_builtins(cnum) { info.compiler_builtins = Some(cnum); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a2d60472ed9ed..5273b6cc83725 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -146,7 +146,7 @@ pub struct CrateInfo { pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, pub native_libraries: FxHashMap>, - pub crate_name: FxHashMap, + pub crate_name: FxHashMap, pub used_libraries: Vec, pub used_crate_source: FxHashMap>, pub used_crates: Vec, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 12b117d6fc9b4..3799623563f83 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1221,7 +1221,7 @@ pub fn get_single_str_from_tts( sp: Span, tts: TokenStream, name: &str, -) -> Option { +) -> Option { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); @@ -1233,7 +1233,7 @@ pub fn get_single_str_from_tts( if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } - expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s.to_string()) + expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s) } /// Extracts comma-separated expressions from `tts`. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 28466315c8687..8340a0b360ef7 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -505,6 +505,8 @@ declare_features! ( (active, static_nobundle, "1.16.0", Some(37403), None), /// Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + /// Allows lints part of the strict provenance effort. + (active, strict_provenance, "1.61.0", Some(95228), None), /// Allows the use of `#[target_feature]` on safe functions. (active, target_feature_11, "1.45.0", Some(69098), None), /// Allows using `#[thread_local]` on `static` items. diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 4b235213f7f5c..7569abfbb10e5 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -22,12 +22,12 @@ //! was re-used. use rustc_ast as ast; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::*; use rustc_span::symbol::{sym, Symbol}; -use std::collections::BTreeSet; #[allow(missing_docs)] pub fn assert_module_sources(tcx: TyCtxt<'_>) { @@ -36,12 +36,8 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { return; } - let available_cgus = tcx - .collect_and_partition_mono_items(()) - .1 - .iter() - .map(|cgu| cgu.name().to_string()) - .collect::>(); + let available_cgus = + tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect(); let ams = AssertModuleSource { tcx, available_cgus }; @@ -53,7 +49,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, - available_cgus: BTreeSet, + available_cgus: FxHashSet, } impl<'tcx> AssertModuleSource<'tcx> { @@ -124,18 +120,17 @@ impl<'tcx> AssertModuleSource<'tcx> { debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name); - if !self.available_cgus.contains(cgu_name.as_str()) { + if !self.available_cgus.contains(&cgu_name) { + let mut cgu_names: Vec<&str> = + self.available_cgus.iter().map(|cgu| cgu.as_str()).collect(); + cgu_names.sort(); self.tcx.sess.span_err( attr.span, &format!( "no module named `{}` (mangled: {}). Available modules: {}", user_path, cgu_name, - self.available_cgus - .iter() - .map(|cgu| cgu.to_string()) - .collect::>() - .join(", ") + cgu_names.join(", ") ), ); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5704c6ed3b25d..89ce307d12cd7 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2648,6 +2648,96 @@ declare_lint! { }; } +declare_lint! { + /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer + /// and a pointer. + /// + /// ### Example + /// + /// ```rust + /// #![feature(strict_provenance)] + /// #![warn(fuzzy_provenance_casts)] + /// + /// fn main() { + /// let _dangling = 16_usize as *const u8; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is part of the strict provenance effort, see [issue #95228]. + /// Casting an integer to a pointer is considered bad style, as a pointer + /// contains, besides the *address* also a *provenance*, indicating what + /// memory the pointer is allowed to read/write. Casting an integer, which + /// doesn't have provenance, to a pointer requires the compiler to assign + /// (guess) provenance. The compiler assigns "all exposed valid" (see the + /// docs of [`ptr::from_exposed_addr`] for more information about this + /// "exposing"). This penalizes the optimiser and is not well suited for + /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI + /// platforms). + /// + /// It is much better to use [`ptr::with_addr`] instead to specify the + /// provenance you want. If using this function is not possible because the + /// code relies on exposed provenance then there is as an escape hatch + /// [`ptr::from_exposed_addr`]. + /// + /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 + /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr + /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr + pub FUZZY_PROVENANCE_CASTS, + Allow, + "a fuzzy integer to pointer cast is used", + @feature_gate = sym::strict_provenance; +} + +declare_lint! { + /// The `lossy_provenance_casts` lint detects an `as` cast between a pointer + /// and an integer. + /// + /// ### Example + /// + /// ```rust + /// #![feature(strict_provenance)] + /// #![warn(lossy_provenance_casts)] + /// + /// fn main() { + /// let x: u8 = 37; + /// let _addr: usize = &x as *const u8 as usize; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is part of the strict provenance effort, see [issue #95228]. + /// Casting a pointer to an integer is a lossy operation, because beyond + /// just an *address* a pointer may be associated with a particular + /// *provenance*. This information is used by the optimiser and for dynamic + /// analysis/dynamic program verification (e.g. Miri or CHERI platforms). + /// + /// Since this cast is lossy, it is considered good style to use the + /// [`ptr::addr`] method instead, which has a similar effect, but doesn't + /// "expose" the pointer provenance. This improves optimisation potential. + /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information + /// about exposing pointer provenance. + /// + /// If your code can't comply with strict provenance and needs to expose + /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch, + /// which preserves the behaviour of `as usize` casts while being explicit + /// about the semantics. + /// + /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 + /// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr + /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr + pub LOSSY_PROVENANCE_CASTS, + Allow, + "a lossy pointer to integer cast is used", + @feature_gate = sym::strict_provenance; +} + declare_lint! { /// The `const_evaluatable_unchecked` lint detects a generic constant used /// in a type. @@ -3101,6 +3191,8 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, + FUZZY_PROVENANCE_CASTS, + LOSSY_PROVENANCE_CASTS, CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, MUST_NOT_SUSPEND, diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 98375cbad9f9b..bc50730ab8b83 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -6,6 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::ItemLocalId; use rustc_macros::HashStable; +use rustc_span::symbol::Symbol; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { @@ -23,7 +24,7 @@ pub enum Region { pub enum LifetimeScopeForPath { // Contains all lifetime names that are in scope and could possibly be used in generics // arguments of path. - NonElided(Vec), + NonElided(Vec), // Information that allows us to suggest args of the form `<'_>` in case // no generic arguments were provided for a path. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b2dd67fb16dce..69dac03883940 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -561,8 +561,7 @@ fn write_scope_tree( } indented_decl.push(';'); - let local_name = - if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; + let local_name = if local == RETURN_PLACE { " return place" } else { "" }; writeln!( w, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1f12f99efb3d5..c45326e1e6e6c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -20,7 +20,7 @@ use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::collections::hash_map::Entry; @@ -536,7 +536,7 @@ impl CheckAttrVisitor<'_> { fn check_doc_alias_value( &self, meta: &NestedMetaItem, - doc_alias: &str, + doc_alias: Symbol, hir_id: HirId, target: Target, is_list: bool, @@ -554,14 +554,17 @@ impl CheckAttrVisitor<'_> { ); false }; - if doc_alias.is_empty() { + if doc_alias == kw::Empty { return err_fn( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), "attribute cannot have empty value", ); } - if let Some(c) = - doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + + let doc_alias_str = doc_alias.as_str(); + if let Some(c) = doc_alias_str + .chars() + .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { self.tcx.sess.span_err( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), @@ -573,7 +576,7 @@ impl CheckAttrVisitor<'_> { ); return false; } - if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') { return err_fn( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), "cannot start or end with ' '", @@ -608,11 +611,11 @@ impl CheckAttrVisitor<'_> { return err_fn(meta.span(), &format!("isn't allowed on {}", err)); } let item_name = self.tcx.hir().name(hir_id); - if item_name.as_str() == doc_alias { + if item_name == doc_alias { return err_fn(meta.span(), "is the same as the item's name"); } let span = meta.span(); - if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) { + if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { lint.build("doc alias is duplicated") .span_label(*entry.entry.get(), "first defined here") @@ -635,14 +638,7 @@ impl CheckAttrVisitor<'_> { match v.literal() { Some(l) => match l.kind { LitKind::Str(s, _) => { - if !self.check_doc_alias_value( - v, - s.as_str(), - hir_id, - target, - true, - aliases, - ) { + if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) { errors += 1; } } @@ -670,8 +666,8 @@ impl CheckAttrVisitor<'_> { } } errors == 0 - } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) { - self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases) + } else if let Some(doc_alias) = meta.value_str() { + self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases) } else { self.tcx .sess @@ -686,8 +682,8 @@ impl CheckAttrVisitor<'_> { } fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { - let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); - if doc_keyword.is_empty() { + let doc_keyword = meta.value_str().unwrap_or(kw::Empty); + if doc_keyword == kw::Empty { self.doc_attr_str_error(meta, "keyword"); return false; } @@ -718,7 +714,7 @@ impl CheckAttrVisitor<'_> { return false; } } - if !rustc_lexer::is_ident(&doc_keyword) { + if !rustc_lexer::is_ident(doc_keyword.as_str()) { self.tcx .sess .struct_span_err( @@ -911,20 +907,20 @@ impl CheckAttrVisitor<'_> { ) -> bool { let mut is_valid = true; - if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) { - for meta in &list { + if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() { + for meta in list { if let Some(i_meta) = meta.meta_item() { match i_meta.name_or_empty() { sym::alias - if !self.check_attr_not_crate_level(&meta, hir_id, "alias") - || !self.check_doc_alias(&meta, hir_id, target, aliases) => + if !self.check_attr_not_crate_level(meta, hir_id, "alias") + || !self.check_doc_alias(meta, hir_id, target, aliases) => { is_valid = false } sym::keyword - if !self.check_attr_not_crate_level(&meta, hir_id, "keyword") - || !self.check_doc_keyword(&meta, hir_id) => + if !self.check_attr_not_crate_level(meta, hir_id, "keyword") + || !self.check_doc_keyword(meta, hir_id) => { is_valid = false } @@ -936,15 +932,15 @@ impl CheckAttrVisitor<'_> { | sym::html_root_url | sym::html_no_source | sym::test - if !self.check_attr_crate_level(&attr, &meta, hir_id) => + if !self.check_attr_crate_level(attr, meta, hir_id) => { is_valid = false; } sym::inline | sym::no_inline if !self.check_doc_inline( - &attr, - &meta, + attr, + meta, hir_id, target, specified_inline, @@ -976,7 +972,7 @@ impl CheckAttrVisitor<'_> { | sym::plugins => {} sym::test => { - if !self.check_test_attr(&meta, hir_id) { + if !self.check_test_attr(meta, hir_id) { is_valid = false; } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 84b4a803403f9..ff033cbb57299 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -696,7 +696,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. // `std` is still checked for the `restricted-std` feature. - if item.span.is_dummy() && item.ident.as_str() != "std" { + if item.span.is_dummy() && item.ident.name != sym::std { return; } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index afb19d7df9fce..1460b5efbb058 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -587,7 +587,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { match scope { Scope::Binder { lifetimes, s, .. } => { available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { - hir::ParamName::Plain(ident) => Some(ident.name.to_string()), + hir::ParamName::Plain(ident) => Some(ident.name), _ => None, })); scope = s; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5803aaa0786e..dc4d10f699c75 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1348,6 +1348,7 @@ symbols! { str_trim, str_trim_end, str_trim_start, + strict_provenance, stringify, stringify_macro, struct_field_attributes, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9998c5bb087e1..ac98dd5801e40 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -36,6 +36,7 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; +use std::ops::ControlFlow; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; @@ -2226,9 +2227,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { post.dedup(); if self.is_tainted_by_errors() - && crate_names.len() == 1 - && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) - && spans.len() == 0 + && (crate_names.len() == 1 + && spans.len() == 0 + && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) + || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) { // Avoid complaining about other inference issues for expressions like // `42 >> 1`, where the types are still `{integer}`, but we want to @@ -2666,3 +2668,17 @@ impl ArgKind { } } } + +struct HasNumericInferVisitor; + +impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { + type BreakTy = (); + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { + ControlFlow::Break(()) + } else { + ControlFlow::CONTINUE + } + } +} diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7ce428ea12466..6091b8fee00b6 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -807,11 +807,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { // ptr -> * (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast - (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast - (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), - // * -> ptr - (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast + // ptr-addr-cast + (Ptr(m_expr), Int(t_c)) => { + self.lossy_provenance_ptr2int_lint(fcx, t_c); + self.check_ptr_addr_cast(fcx, m_expr) + } + (FnPtr, Int(_)) => { + // FIXME(#95489): there should eventually be a lint for these casts + Ok(CastKind::FnPtrAddrCast) + } + // addr-ptr-cast + (Int(_), Ptr(mt)) => { + self.fuzzy_provenance_int2ptr_lint(fcx); + self.check_addr_ptr_cast(fcx, mt) + } + // fn-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // prim -> prim @@ -973,6 +984,74 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } } + + fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::LOSSY_PROVENANCE_CASTS, + self.expr.hir_id, + self.span, + |err| { + let mut err = err.build(&format!( + "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", + self.expr_ty, self.cast_ty + )); + + let msg = "use `.addr()` to obtain the address of a pointer"; + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + let scalar_cast = match t_c { + ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(), + _ => format!(" as {}", self.cast_ty), + }; + err.span_suggestion( + self.span, + msg, + format!("({}).addr(){}", snippet, scalar_cast), + Applicability::MaybeIncorrect + ); + } else { + err.help(msg); + } + err.help( + "if you can't comply with strict provenance and need to expose the pointer\ + provenance you can use `.expose_addr()` instead" + ); + + err.emit(); + }, + ); + } + + fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::FUZZY_PROVENANCE_CASTS, + self.expr.hir_id, + self.span, + |err| { + + let mut err = err.build(&format!( + "strict provenance disallows casting integer `{}` to pointer `{}`", + self.expr_ty, self.cast_ty + )); + let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + err.span_suggestion( + self.span, + msg, + format!("(...).with_addr({})", snippet), + Applicability::HasPlaceholders, + ); + } else { + err.help(msg); + } + err.help( + "if you can't comply with strict provenance and don't have a pointer with \ + the correct provenance you can use `std::ptr::from_exposed_addr()` instead" + ); + + err.emit(); + }, + ); + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 24b6639d7f275..1b1a2037d9eaa 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { param_names .iter() .take(num_params_to_take) - .map(|p| (*p).clone()) + .map(|p| p.as_str()) .collect::>() .join(", ") } else { diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 630351d0dc278..d97777e4da29d 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -1,5 +1,6 @@ +use crate::cell::UnsafeCell; use crate::sync::atomic::{ - AtomicI32, + AtomicI32, AtomicUsize, Ordering::{Acquire, Relaxed, Release}, }; use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; @@ -162,3 +163,98 @@ impl Condvar { r } } + +/// A reentrant mutex. Used by stdout().lock() and friends. +/// +/// The 'owner' field tracks which thread has locked the mutex. +/// +/// We use current_thread_unique_ptr() as the thread identifier, +/// which is just the address of a thread local variable. +/// +/// If `owner` is set to the identifier of the current thread, +/// we assume the mutex is already locked and instead of locking it again, +/// we increment `lock_count`. +/// +/// When unlocking, we decrement `lock_count`, and only unlock the mutex when +/// it reaches zero. +/// +/// `lock_count` is protected by the mutex and only accessed by the thread that has +/// locked the mutex, so needs no synchronization. +/// +/// `owner` can be checked by other threads that want to see if they already +/// hold the lock, so needs to be atomic. If it compares equal, we're on the +/// same thread that holds the mutex and memory access can use relaxed ordering +/// since we're not dealing with multiple threads. If it compares unequal, +/// synchronization is left to the mutex, making relaxed memory ordering for +/// the `owner` field fine in all cases. +pub struct ReentrantMutex { + mutex: Mutex, + owner: AtomicUsize, + lock_count: UnsafeCell, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + #[inline] + pub const unsafe fn uninitialized() -> Self { + Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) } + } + + #[inline] + pub unsafe fn init(&self) {} + + #[inline] + pub unsafe fn destroy(&self) {} + + pub unsafe fn try_lock(&self) -> bool { + let this_thread = current_thread_unique_ptr(); + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count(); + true + } else if self.mutex.try_lock() { + self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); + *self.lock_count.get() = 1; + true + } else { + false + } + } + + pub unsafe fn lock(&self) { + let this_thread = current_thread_unique_ptr(); + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count(); + } else { + self.mutex.lock(); + self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); + *self.lock_count.get() = 1; + } + } + + unsafe fn increment_lock_count(&self) { + *self.lock_count.get() = (*self.lock_count.get()) + .checked_add(1) + .expect("lock count overflow in reentrant mutex"); + } + + pub unsafe fn unlock(&self) { + *self.lock_count.get() -= 1; + if *self.lock_count.get() == 0 { + self.owner.store(0, Relaxed); + self.mutex.unlock(); + } + } +} + +/// Get an address that is unique per running thread. +/// +/// This can be used as a non-null usize-sized ID. +pub fn current_thread_unique_ptr() -> usize { + // Use a non-drop type to make sure it's still available during thread destruction. + thread_local! { static X: u8 = const { 0 } } + X.with(|x| <*const _>::addr(x)) +} diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index 2b8dd168068b5..e6b8438cff999 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -4,12 +4,8 @@ cfg_if::cfg_if! { target_os = "android", ))] { mod futex; - #[allow(dead_code)] - mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex. - mod pthread_remutex; // FIXME: Implement this using a futex mod pthread_rwlock; // FIXME: Implement this using a futex - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use pthread_remutex::ReentrantMutex; + pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex}; pub use pthread_rwlock::{RwLock, MovableRwLock}; } else { mod pthread_mutex; diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index fc307c5666d63..99baca66df092 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -179,6 +179,7 @@ macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ #[cfg_attr(not(windows), inline(always))] // see comments below + #[deny(unsafe_op_in_unsafe_fn)] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { diff --git a/src/doc/unstable-book/src/language-features/strict-provenance.md b/src/doc/unstable-book/src/language-features/strict-provenance.md new file mode 100644 index 0000000000000..dc60f3f375d3c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/strict-provenance.md @@ -0,0 +1,22 @@ +# `strict_provenance` + +The tracking issue for this feature is: [#95228] + +[#95228]: https://github.com/rust-lang/rust/issues/95228 +----- + +The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints. +These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model. +The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`). + +## Example + +```rust +#![feature(strict_provenance)] +#![warn(fuzzy_provenance_casts)] + +fn main() { + let _dangling = 16_usize as *const u8; + //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8` +} +``` diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5c59609d5b8c6..228976cb171b5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -371,7 +371,8 @@ crate fn print_where_clause<'a, 'tcx: 'a>( clause = clause.replace("
", &format!("
{}", padding)); clause.insert_str(0, &" ".repeat(indent.saturating_sub(1))); if !end_newline { - clause.insert_str(0, "
"); + // we insert the
after a single space but before multiple spaces at the start + clause.insert_str(if indent == 0 { 1 } else { 0 }, "
"); } } write!(f, "{}", clause) diff --git a/src/test/rustdoc/empty-doc-comment.rs b/src/test/rustdoc/empty-doc-comment.rs new file mode 100644 index 0000000000000..b1dae930e066b --- /dev/null +++ b/src/test/rustdoc/empty-doc-comment.rs @@ -0,0 +1,22 @@ +// Ensure that empty doc comments don't panic. + +/*! +*/ + +/// +/// +pub struct Foo; + +#[doc = " +"] +pub mod Mod { + //! + //! +} + +/** +*/ +pub mod Another { + #![doc = " +"] +} diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html new file mode 100644 index 0000000000000..d941ad7de4c48 --- /dev/null +++ b/src/test/rustdoc/where.SWhere_Simd_item-decl.html @@ -0,0 +1 @@ +
pub struct Simd<T, const LANES: usize>(_) 
where
    T: Sized
;
\ No newline at end of file diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html new file mode 100644 index 0000000000000..54026ff034e00 --- /dev/null +++ b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html @@ -0,0 +1,3 @@ +
pub trait TraitWhere {
+    type Item<'a>
    where
        Self: 'a
; +}
\ No newline at end of file diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 549cfff96cb6d..73c75fdb61bcd 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -1,3 +1,4 @@ +#![feature(generic_associated_types)] #![crate_name = "foo"] pub trait MyTrait { fn dummy(&self) { } } @@ -19,6 +20,18 @@ impl Delta where D: MyTrait { pub struct Echo(E); +// @has 'foo/struct.Simd.html' +// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]' +pub struct Simd([T; LANES]) +where + T: Sized; + +// @has 'foo/trait.TraitWhere.html' +// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]' +pub trait TraitWhere { + type Item<'a> where Self: 'a; +} + // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ // "impl MyTrait for Echo where E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \ diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.rs b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs new file mode 100644 index 0000000000000..75d0ee5700d07 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs @@ -0,0 +1,19 @@ +// check-pass + +#![deny(fuzzy_provenance_casts)] +//~^ WARNING unknown lint: `fuzzy_provenance_casts` +//~| WARNING unknown lint: `fuzzy_provenance_casts` +//~| WARNING unknown lint: `fuzzy_provenance_casts` +#![deny(lossy_provenance_casts)] +//~^ WARNING unknown lint: `lossy_provenance_casts` +//~| WARNING unknown lint: `lossy_provenance_casts` +//~| WARNING unknown lint: `lossy_provenance_casts` + +fn main() { + // no warnings emitted since the lints are not activated + + let _dangling = 16_usize as *const u8; + + let x: u8 = 37; + let _addr: usize = &x as *const u8 as usize; +} diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr new file mode 100644 index 0000000000000..34bd240c304a7 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr @@ -0,0 +1,63 @@ +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_lints)]` on by default + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: 6 warnings emitted + diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs new file mode 100644 index 0000000000000..d2d72a68f1396 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs @@ -0,0 +1,7 @@ +#![feature(strict_provenance)] +#![deny(fuzzy_provenance_casts)] + +fn main() { + let dangling = 16_usize as *const u8; + //~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const u8` +} diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr new file mode 100644 index 0000000000000..e50d243b6ad6d --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr @@ -0,0 +1,19 @@ +error: strict provenance disallows casting integer `usize` to pointer `*const u8` + --> $DIR/lint-strict-provenance-fuzzy-casts.rs:5:20 + | +LL | let dangling = 16_usize as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead +help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address + | +LL | let dangling = (...).with_addr(16_usize); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs new file mode 100644 index 0000000000000..3690fbc904d99 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs @@ -0,0 +1,11 @@ +#![feature(strict_provenance)] +#![deny(lossy_provenance_casts)] + +fn main() { + let x: u8 = 37; + let addr: usize = &x as *const u8 as usize; + //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` + + let addr_32bit = &x as *const u8 as u32; + //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` +} diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr new file mode 100644 index 0000000000000..489cb03ddd316 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr @@ -0,0 +1,23 @@ +error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` + --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23 + | +LL | let addr: usize = &x as *const u8 as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()` + | +note: the lint level is defined here + --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + +error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` + --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22 + | +LL | let addr_32bit = &x as *const u8 as u32; + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32` + | + = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs index cff6f29a15386..b4fef11f1e29a 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs +++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs @@ -5,5 +5,40 @@ macro_rules! count { }; } +macro_rules! dollar_dollar { + () => { + macro_rules! bar { + ( $$( $$any:tt )* ) => { $$( $$any )* }; + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + } + }; +} + +macro_rules! index { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${index()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + +macro_rules! ignore { + ( $( $i:stmt ),* ) => {{ + 0 $( + 1 ${ignore(i)} )* + //~^ ERROR meta-variable expressions are unstable + }}; +} + +macro_rules! length { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${length()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + fn main() { } diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr index f573194479314..ecf598b104d05 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr +++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr @@ -7,6 +7,87 @@ LL | ${ count(e) } = note: see issue #83527 for more information = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:16 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:20 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:39 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:43 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:13 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:26 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:30:19 + | +LL | 0 $( + 1 ${ignore(i)} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:13 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:26 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/traits/no-fallback-multiple-impls.rs b/src/test/ui/traits/no-fallback-multiple-impls.rs new file mode 100644 index 0000000000000..7ed3796f08b76 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.rs @@ -0,0 +1,16 @@ +trait Fallback { + fn foo(&self) {} +} + +impl Fallback for i32 {} + +impl Fallback for u64 {} + +impl Fallback for usize {} + +fn main() { + missing(); + //~^ ERROR cannot find function `missing` in this scope + 0.foo(); + // But then we shouldn't report an inference ambiguity here... +} diff --git a/src/test/ui/traits/no-fallback-multiple-impls.stderr b/src/test/ui/traits/no-fallback-multiple-impls.stderr new file mode 100644 index 0000000000000..61c9e5aaabdb4 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `missing` in this scope + --> $DIR/no-fallback-multiple-impls.rs:12:5 + | +LL | missing(); + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/traits/test-2.rs b/src/test/ui/traits/test-2.rs index d062de25ac8c1..342928e882a55 100644 --- a/src/test/ui/traits/test-2.rs +++ b/src/test/ui/traits/test-2.rs @@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { - 10.dup::(); //~ ERROR type annotations needed + 10.dup::(); //~^ ERROR this associated function takes 0 generic arguments but 1 - 10.blah::(); //~ ERROR type annotations needed + 10.blah::(); //~^ ERROR this associated function takes 1 generic argument but 2 (Box::new(10) as Box).dup(); //~^ ERROR E0038 diff --git a/src/test/ui/traits/test-2.stderr b/src/test/ui/traits/test-2.stderr index 5eec012458450..77ea4e4e974eb 100644 --- a/src/test/ui/traits/test-2.stderr +++ b/src/test/ui/traits/test-2.stderr @@ -79,35 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` = note: required by cast to type `Box` -error[E0283]: type annotations needed - --> $DIR/test-2.rs:9:8 - | -LL | 10.dup::(); - | ^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/test-2.rs:11:8 - | -LL | 10.blah::(); - | ^^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0038, E0107, E0283. +Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`.