diff options
96 files changed, 1952 insertions, 470 deletions
diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 7a7624893bd..927417f89f8 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -207,10 +207,9 @@ pub fn check_attribute_safety( } } - // - Normal builtin attribute, or any non-builtin attribute - // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is - // not permitted on non-builtin attributes or normal builtin attributes - (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => { + // - Normal builtin attribute + // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes + (Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => { psess.dcx().emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: attr_item.path.clone(), @@ -224,9 +223,8 @@ pub fn check_attribute_safety( } // - Non-builtin attribute - // - No explicit `#[unsafe(..)]` written. - (None, Safety::Default) => { - // OK + (None, Safety::Unsafe(_) | Safety::Default) => { + // OK (not checked here) } ( diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index cc09fa5b69b..93b1cf272ab 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>( bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), ) })); - let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; - let md = bx.get_metadata_value(md); - llvm::LLVMSetMetadata(call, kind, md); + bx.cx.set_metadata_node(call, kind, &srcloc); Some(call) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 5271d0b4bb8..e7cb18ab22d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1,12 +1,12 @@ use std::borrow::{Borrow, Cow}; +use std::iter; use std::ops::Deref; -use std::{iter, ptr}; use rustc_ast::expand::typetree::FncTree; pub(crate) mod autodiff; pub(crate) mod gpu_offload; -use libc::{c_char, c_uint, size_t}; +use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::{Align, Size, WrappingRange}; use rustc_codegen_ssa::MemFlags; @@ -396,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { md.push(weight(is_cold)); } - unsafe { - let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t); - self.cx.set_metadata(switch, llvm::MD_prof, md_node); - } + self.cx.set_metadata_node(switch, llvm::MD_prof, &md); } fn invoke( @@ -801,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - unsafe { - let llty = self.cx.val_ty(load); - let md = [ - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), - llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), - ]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_range, md); - } + let llty = self.cx.val_ty(load); + let md = [ + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)), + llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))), + ]; + self.set_metadata_node(load, llvm::MD_range, &md); } fn nonnull_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_nonnull, md); - } + self.set_metadata_node(load, llvm::MD_nonnull, &[]); } fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value { @@ -865,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // // [1]: https://llvm.org/docs/LangRef.html#store-instruction let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1)); - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1); - self.set_metadata(store, llvm::MD_nontemporal, md); + self.set_metadata_node(store, llvm::MD_nontemporal, &[one]); } } store @@ -1381,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn set_invariant_load(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_invariant_load, md); - } + self.set_metadata_node(load, llvm::MD_invariant_load, &[]); } fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) { @@ -1528,25 +1515,16 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn align_metadata(&mut self, load: &'ll Value, align: Align) { - unsafe { - let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len()); - self.set_metadata(load, llvm::MD_align, md); - } + let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))]; + self.set_metadata_node(load, llvm::MD_align, &md); } fn noundef_metadata(&mut self, load: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(load, llvm::MD_noundef, md); - } + self.set_metadata_node(load, llvm::MD_noundef, &[]); } pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) { - unsafe { - let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0); - self.set_metadata(inst, llvm::MD_unpredictable, md); - } + self.set_metadata_node(inst, llvm::MD_unpredictable, &[]); } } impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 40375ef6510..b4ca85a26c8 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> { let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); let alloc = self.create_metadata(bytes); let data = [section, alloc]; - let meta = - unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; - let val = self.get_metadata_value(meta); - unsafe { - llvm::LLVMAddNamedMetadataOperand( - self.llmod, - c"wasm.custom_sections".as_ptr(), - val, - ) - }; + self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data); } } else { base::set_link_section(g, attrs); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index b1da6f7c740..922575dd63c 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,7 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::{Metadata, MetadataKindId}; +use crate::llvm::{Metadata, MetadataKindId, Module}; use crate::type_::Type; use crate::value::Value; use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util}; @@ -495,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>( format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); - - unsafe { - llvm::LLVMAddNamedMetadataOperand( - llmod, - c"llvm.ident".as_ptr(), - &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), - ); - } + cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]); // Emit RISC-V specific target-abi metadata // to workaround lld as the LTO plugin not @@ -1002,6 +995,11 @@ impl CodegenCx<'_, '_> { } impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { + /// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`. + pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata { + unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) } + } + /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. pub(crate) fn set_metadata<'a>( &self, @@ -1012,6 +1010,61 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { let node = self.get_metadata_value(md); llvm::LLVMSetMetadata(val, kind_id, node); } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`) + pub(crate) fn set_metadata_node( + &self, + instruction: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + self.set_metadata(instruction, kind_id, md); + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`) + /// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`) + pub(crate) fn module_add_named_metadata_node( + &self, + module: &'ll Module, + kind_name: &CStr, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + let md_as_val = self.get_metadata_value(md); + unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) }; + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_add_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) }; + } + + /// Helper method for the sequence of calls: + /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata) + /// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`) + pub(crate) fn global_set_metadata_node( + &self, + global: &'ll Value, + kind_id: MetadataKindId, + md_list: &[&'ll Metadata], + ) { + let md = self.md_node_in_context(md_list); + unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) }; + } } impl HasDataLayout for CodegenCx<'_, '_> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index bc20c759413..2f9e7cae54f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1607,17 +1607,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); - unsafe { - let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; - llvm::LLVMRustGlobalAddMetadata( - vtable, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()), - ); - let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64)); - let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1); - llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata); - } + let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; + cx.global_add_metadata_node(vtable, llvm::MD_type, &type_); + + let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))]; + cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility); } /// Creates debug information for the given vtable, which is for the diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5b97898a4b8..1e5cf8374e3 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -302,26 +302,14 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_add_metadata_node(function, llvm::MD_type, &v); } fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); - unsafe { - let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_type, - llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()), - ) - } + let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; + self.global_set_metadata_node(function, llvm::MD_type, &v); } fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { @@ -329,32 +317,12 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMRustGlobalAddMetadata( - function, - llvm::MD_kcfi_type, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { - let kcfi_type_metadata = self.const_u32(kcfi_typeid); - unsafe { - llvm::LLVMGlobalSetMetadata( - function, - llvm::MD_kcfi_type, - llvm::LLVMMDNodeInContext2( - self.llcx, - &llvm::LLVMValueAsMetadata(kcfi_type_metadata), - 1, - ), - ) - } + let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))]; + self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata); } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index e644a43f883..ac123143738 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -17,7 +17,6 @@ use rustc_middle::middle::exported_symbols::{ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_span::sym; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; @@ -1324,37 +1323,7 @@ struct WasmLd<'a> { impl<'a> WasmLd<'a> { fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { - // If the atomics feature is enabled for wasm then we need a whole bunch - // of flags: - // - // * `--shared-memory` - the link won't even succeed without this, flags - // the one linear memory as `shared` - // - // * `--max-memory=1G` - when specifying a shared memory this must also - // be specified. We conservatively choose 1GB but users should be able - // to override this with `-C link-arg`. - // - // * `--import-memory` - it doesn't make much sense for memory to be - // exported in a threaded module because typically you're - // sharing memory and instantiating the module multiple times. As a - // result if it were exported then we'd just have no sharing. - // - // On wasm32-unknown-unknown, we also export symbols for glue code to use: - // * `--export=*tls*` - when `#[thread_local]` symbols are used these - // symbols are how the TLS segments are initialized and configured. - let mut wasm_ld = WasmLd { cmd, sess }; - if sess.target_features.contains(&sym::atomics) { - wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" || sess.target.os == "none" { - wasm_ld.link_args(&[ - "--export=__wasm_init_tls", - "--export=__tls_size", - "--export=__tls_align", - "--export=__tls_base", - ]); - } - } - wasm_ld + WasmLd { cmd, sess } } } diff --git a/compiler/rustc_error_codes/src/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md index d0ebc3a26f0..3c29484f575 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0608.md +++ b/compiler/rustc_error_codes/src/error_codes/E0608.md @@ -1,5 +1,5 @@ -An attempt to use index on a type which doesn't implement the `std::ops::Index` -trait was performed. +Attempted to index a value whose type doesn't implement the +`std::ops::Index` trait. Erroneous code example: @@ -7,8 +7,8 @@ Erroneous code example: 0u8[2]; // error: cannot index into a value of type `u8` ``` -To be able to index into a type it needs to implement the `std::ops::Index` -trait. Example: +Only values with types that implement the `std::ops::Index` trait +can be indexed with square brackets. Example: ``` let v: Vec<u8> = vec![0, 1, 2, 3]; @@ -16,3 +16,10 @@ let v: Vec<u8> = vec![0, 1, 2, 3]; // The `Vec` type implements the `Index` trait so you can do: println!("{}", v[2]); ``` + +Tuples and structs are indexed with dot (`.`), not with brackets (`[]`), +and tuple element names are their positions: +```ignore(pseudo code) +// this (pseudo code) expression is true for any tuple: +tuple == (tuple.0, tuple.1, ...) +``` diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 33b712e3aed..810a5a21a05 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; -use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; +use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -345,6 +345,21 @@ pub trait AttrProcMacro { annotation: TokenStream, annotated: TokenStream, ) -> Result<TokenStream, ErrorGuaranteed>; + + // Default implementation for safe attributes; override if the attribute can be unsafe. + fn expand_with_safety<'cx>( + &self, + ecx: &'cx mut ExtCtxt<'_>, + safety: Safety, + span: Span, + annotation: TokenStream, + annotated: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + if let Safety::Unsafe(span) = safety { + ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } + self.expand(ecx, span, annotation, annotated) + } } impl<F> AttrProcMacro for F diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 172bc3d1d9f..3dfa3cdcc35 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.to_tokens(), }; let attr_item = attr.get_normal_item(); + let safety = attr_item.unsafety; if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - match expander.expand(self.cx, span, inner_tokens, tokens) { + match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) { Ok(tok_result) => { let fragment = self.parse_ast_fragment( tok_result, @@ -840,6 +841,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { + // `LegacyAttr` is only used for builtin attribute macros, which have their + // safety checked by `check_builtin_meta_item`, so we don't need to check + // `unsafety` here. match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { let item_clone = macro_stats.then(|| item.clone()); @@ -882,6 +886,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } } else if let SyntaxExtensionKind::NonMacroAttr = ext { + if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety { + self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute"); + } // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index d4504ba720e..c548cea537f 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream}; -use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; @@ -131,6 +131,7 @@ pub(super) enum MacroRule { Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree }, /// An attr rule, for use with `#[m]` Attr { + unsafe_rule: bool, args: Vec<MatcherLoc>, args_span: Span, body: Vec<MatcherLoc>, @@ -248,7 +249,18 @@ impl TTMacroExpander for MacroRulesMacroExpander { impl AttrProcMacro for MacroRulesMacroExpander { fn expand( &self, + _cx: &mut ExtCtxt<'_>, + _sp: Span, + _args: TokenStream, + _body: TokenStream, + ) -> Result<TokenStream, ErrorGuaranteed> { + unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`") + } + + fn expand_with_safety( + &self, cx: &mut ExtCtxt<'_>, + safety: Safety, sp: Span, args: TokenStream, body: TokenStream, @@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander { self.node_id, self.name, self.transparency, + safety, args, body, &self.rules, @@ -408,6 +421,7 @@ fn expand_macro_attr( node_id: NodeId, name: Ident, transparency: Transparency, + safety: Safety, args: TokenStream, body: TokenStream, rules: &[MacroRule], @@ -429,13 +443,26 @@ fn expand_macro_attr( // Track nothing for the best performance. match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) { Ok((i, rule, named_matches)) => { - let MacroRule::Attr { rhs, .. } = rule else { + let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else { panic!("try_macro_match_attr returned non-attr rule"); }; let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else { cx.dcx().span_bug(sp, "malformed macro rhs"); }; + match (safety, unsafe_rule) { + (Safety::Default, false) | (Safety::Unsafe(_), true) => {} + (Safety::Default, true) => { + cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`"); + } + (Safety::Unsafe(span), false) => { + cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation"); + } + (Safety::Safe(span), _) => { + cx.dcx().span_bug(span, "unexpected `safe` keyword"); + } + } + let id = cx.current_expansion.id; let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id) .map_err(|e| e.emit())?; @@ -681,6 +708,11 @@ pub fn compile_declarative_macro( let mut rules = Vec::new(); while p.token != token::Eof { + let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe); + let unsafe_keyword_span = p.prev_token.span; + if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") { + return dummy_syn_ext(guar); + } let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) { kinds |= MacroKinds::ATTR; if !features.macro_attr() { @@ -705,6 +737,10 @@ pub fn compile_declarative_macro( feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable") .emit(); } + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") { return dummy_syn_ext(guar); } @@ -730,6 +766,10 @@ pub fn compile_declarative_macro( (None, true) } else { kinds |= MacroKinds::BANG; + if unsafe_rule { + sess.dcx() + .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules"); + } (None, false) }; let lhs_tt = p.parse_token_tree(); @@ -741,10 +781,10 @@ pub fn compile_declarative_macro( if let Some(guar) = check_no_eof(sess, &p, "expected right-hand side of macro rule") { return dummy_syn_ext(guar); } - let rhs_tt = p.parse_token_tree(); - let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition); - check_emission(check_rhs(sess, &rhs_tt)); - check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt)); + let rhs = p.parse_token_tree(); + let rhs = parse_one_tt(rhs, RulePart::Body, sess, node_id, features, edition); + check_emission(check_rhs(sess, &rhs)); + check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs)); let lhs_span = lhs_tt.span(); // Convert the lhs into `MatcherLoc` form, which is better for doing the // actual matching. @@ -760,11 +800,11 @@ pub fn compile_declarative_macro( }; let args = mbe::macro_parser::compute_locs(&delimited.tts); let body_span = lhs_span; - rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt }); + rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs }); } else if is_derive { - rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs }); } else { - rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt }); + rules.push(MacroRule::Func { lhs, lhs_span, rhs }); } if p.token == token::Eof { break; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d1ce0afddf9..f9cdc923670 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3551,35 +3551,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // Try to give some advice about indexing tuples. if let ty::Tuple(types) = base_t.kind() { - let mut needs_note = true; - // If the index is an integer, we can show the actual - // fixed expression: + err.help( + "tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.", + ); + // If index is an unsuffixed integer, show the fixed expression: if let ExprKind::Lit(lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node - && i.get() - < types - .len() - .try_into() - .expect("expected tuple index to be < usize length") + && i.get() < types.len().try_into().expect("tuple length fits in u128") { err.span_suggestion( brackets_span, - "to access tuple elements, use", + format!("to access tuple element `{i}`, use"), format!(".{i}"), Applicability::MachineApplicable, ); - needs_note = false; - } else if let ExprKind::Path(..) = idx.peel_borrows().kind { - err.span_label( - idx.span, - "cannot access tuple elements at a variable index", - ); - } - if needs_note { - err.help( - "to access tuple elements, use tuple indexing \ - syntax (e.g., `tuple.0`)", - ); } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a28af7833c3..a9fbd0fa33d 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2748,28 +2748,7 @@ impl<'a> Parser<'a> { if token::Colon != self.token.kind { return first_pat; } - if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_non_reserved_ident()) - { - let mut snapshot_type = self.create_snapshot_for_diagnostic(); - snapshot_type.bump(); // `:` - match snapshot_type.parse_ty() { - Err(inner_err) => { - inner_err.cancel(); - } - Ok(ty) => { - let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else { - return first_pat; - }; - err.span_label(ty.span, "specifying the type of a pattern isn't supported"); - self.restore_snapshot(snapshot_type); - let span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(span, PatKind::Wild); - err.emit(); - } - } - return first_pat; - } + // The pattern looks like it might be a path with a `::` -> `:` typo: // `match foo { bar:baz => {} }` let colon_span = self.token.span; @@ -2857,7 +2836,13 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } else { - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = self.mk_pat( + new_span, + PatKind::Err( + self.dcx() + .span_delayed_bug(colon_span, "recovered bad path pattern"), + ), + ); } self.restore_snapshot(snapshot_pat); } @@ -2870,7 +2855,14 @@ impl<'a> Parser<'a> { err.span_label(ty.span, "specifying the type of a pattern isn't supported"); self.restore_snapshot(snapshot_type); let new_span = first_pat.span.to(ty.span); - first_pat = self.mk_pat(new_span, PatKind::Wild); + first_pat = + self.mk_pat( + new_span, + PatKind::Err(self.dcx().span_delayed_bug( + colon_span, + "recovered bad pattern with type", + )), + ); } } err.emit(); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 81a5d48d94e..8046abcd70b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3612,7 +3612,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1) } - fn is_certainly_not_a_block(&self) -> bool { + fn is_likely_struct_lit(&self) -> bool { // `{ ident, ` and `{ ident: ` cannot start a block. self.look_ahead(1, |t| t.is_ident()) && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon) @@ -3624,24 +3624,50 @@ impl<'a> Parser<'a> { path: &ast::Path, ) -> Option<PResult<'a, Box<Expr>>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); - if struct_allowed || self.is_certainly_not_a_block() { - if let Err(err) = self.expect(exp!(OpenBrace)) { - return Some(Err(err)); + match (struct_allowed, self.is_likely_struct_lit()) { + // A struct literal isn't expected and one is pretty much assured not to be present. The + // only situation that isn't detected is when a struct with a single field was attempted + // in a place where a struct literal wasn't expected, but regular parser errors apply. + // Happy path. + (false, false) => None, + (true, _) => { + // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for + // any kind of recovery. Happy path. + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + Some(self.parse_expr_struct(qself.clone(), path.clone(), true)) } - let expr = self.parse_expr_struct(qself.clone(), path.clone(), true); - if let (Ok(expr), false) = (&expr, struct_allowed) { - // This is a struct literal, but we don't can't accept them here. - self.dcx().emit_err(errors::StructLiteralNotAllowedHere { - span: expr.span, - sub: errors::StructLiteralNotAllowedHereSugg { - left: path.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); + (false, true) => { + // We have something like `match foo { bar,` or `match foo { bar:`, which means the + // user might have meant to write a struct literal as part of the `match` + // discriminant. This is done purely for error recovery. + let snapshot = self.create_snapshot_for_diagnostic(); + if let Err(err) = self.expect(exp!(OpenBrace)) { + return Some(Err(err)); + } + match self.parse_expr_struct(qself.clone(), path.clone(), false) { + Ok(expr) => { + // This is a struct literal, but we don't accept them here. + self.dcx().emit_err(errors::StructLiteralNotAllowedHere { + span: expr.span, + sub: errors::StructLiteralNotAllowedHereSugg { + left: path.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + Some(Ok(expr)) + } + Err(err) => { + // We couldn't parse a valid struct, rollback and let the parser emit an + // error elsewhere. + err.cancel(); + self.restore_snapshot(snapshot); + None + } + } } - return Some(expr); } - None } pub(super) fn parse_struct_fields( diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs index a0eb4a254fc..06e5cfaed92 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs @@ -6,11 +6,18 @@ use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { let mut options = base::linux_wasm::opts(); - options - .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]); + options.add_pre_link_args( + LinkerFlavor::WasmLld(Cc::No), + &["--export-memory", "--shared-memory", "--max-memory=1073741824"], + ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), - &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"], + &[ + "--target=wasm32-wasi-threads", + "-Wl,--export-memory,", + "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", + ], ); Target { diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 44d906a507d..c735c72cb1c 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::No), - &["--import-memory", "--export-memory", "--shared-memory"], + &["--import-memory", "--export-memory", "--shared-memory", "--max-memory=1073741824"], ); options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), @@ -28,6 +28,7 @@ pub(crate) fn target() -> Target { "-Wl,--import-memory", "-Wl,--export-memory,", "-Wl,--shared-memory", + "-Wl,--max-memory=1073741824", ], ); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5a63d90b95f..49ff768bed1 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -619,6 +619,37 @@ impl<T, A: Allocator> Box<T, A> { pub fn into_inner(boxed: Self) -> T { *boxed } + + /// Consumes the `Box` without consuming its allocation, returning the wrapped value and a `Box` + /// to the uninitialized memory where the wrapped value used to live. + /// + /// This can be used together with [`write`](Box::write) to reuse the allocation for multiple + /// boxed values. + /// + /// # Examples + /// + /// ``` + /// #![feature(box_take)] + /// + /// let c = Box::new(5); + /// + /// // take the value out of the box + /// let (value, uninit) = Box::take(c); + /// assert_eq!(value, 5); + /// + /// // reuse the box for a second value + /// let c = Box::write(uninit, 6); + /// assert_eq!(*c, 6); + /// ``` + #[unstable(feature = "box_take", issue = "147212")] + pub fn take(boxed: Self) -> (T, Box<mem::MaybeUninit<T>, A>) { + unsafe { + let (raw, alloc) = Box::into_raw_with_allocator(boxed); + let value = raw.read(); + let uninit = Box::from_raw_in(raw.cast::<mem::MaybeUninit<T>>(), alloc); + (value, uninit) + } + } } impl<T> Box<[T]> { diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index d5c795093cf..f7f051b1add 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -42,7 +42,7 @@ cfg_select! { } _ => { mod os; - pub use os::{Storage, thread_local_inner}; + pub use os::{Storage, thread_local_inner, value_align}; pub(crate) use os::{LocalPointer, local_pointer}; } } diff --git a/library/std/src/sys/thread_local/native/eager.rs b/library/std/src/sys/thread_local/native/eager.rs index fd48c4f7202..23abad645c1 100644 --- a/library/std/src/sys/thread_local/native/eager.rs +++ b/library/std/src/sys/thread_local/native/eager.rs @@ -10,9 +10,11 @@ enum State { } #[allow(missing_debug_implementations)] +#[repr(C)] pub struct Storage<T> { - state: Cell<State>, + // This field must be first, for correctness of `#[rustc_align_static]` val: UnsafeCell<T>, + state: Cell<State>, } impl<T> Storage<T> { diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs index b556dd9aa25..02939a74fc0 100644 --- a/library/std/src/sys/thread_local/native/lazy.rs +++ b/library/std/src/sys/thread_local/native/lazy.rs @@ -27,9 +27,11 @@ enum State<D> { } #[allow(missing_debug_implementations)] +#[repr(C)] pub struct Storage<T, D> { - state: Cell<State<D>>, + // This field must be first, for correctness of `#[rustc_align_static]` value: UnsafeCell<MaybeUninit<T>>, + state: Cell<State<D>>, } impl<T, D> Storage<T, D> diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs index a5dffe3c458..5dc14240804 100644 --- a/library/std/src/sys/thread_local/native/mod.rs +++ b/library/std/src/sys/thread_local/native/mod.rs @@ -54,7 +54,7 @@ pub macro thread_local_inner { // test in `tests/thread.rs` if these types are renamed. // Used to generate the `LocalKey` value for const-initialized thread locals. - (@key $t:ty, const $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ const __INIT: $t = $init; unsafe { @@ -62,6 +62,7 @@ pub macro thread_local_inner { if $crate::mem::needs_drop::<$t>() { |_| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::EagerStorage<$t> = $crate::thread::local_impl::EagerStorage::new(__INIT); VAL.get() @@ -69,6 +70,7 @@ pub macro thread_local_inner { } else { |_| { #[thread_local] + $(#[$align_attr])* static VAL: $t = __INIT; &VAL } @@ -78,7 +80,7 @@ pub macro thread_local_inner { }}, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ #[inline] fn __init() -> $t { $init @@ -89,6 +91,7 @@ pub macro thread_local_inner { if $crate::mem::needs_drop::<$t>() { |init| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::LazyStorage<$t, ()> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) @@ -96,6 +99,7 @@ pub macro thread_local_inner { } else { |init| { #[thread_local] + $(#[$align_attr])* static VAL: $crate::thread::local_impl::LazyStorage<$t, !> = $crate::thread::local_impl::LazyStorage::new(); VAL.get_or_init(init, __init) @@ -104,10 +108,6 @@ pub macro thread_local_inner { }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); - }, } #[rustc_macro_transparency = "semitransparent"] diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 4da01a84acf..409dfb19518 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -2,6 +2,7 @@ //! thread locals and we can instead just use plain statics! use crate::cell::{Cell, UnsafeCell}; +use crate::mem::MaybeUninit; use crate::ptr; #[doc(hidden)] @@ -11,12 +12,13 @@ use crate::ptr; #[rustc_macro_transparency = "semitransparent"] pub macro thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals - (@key $t:ty, const $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{ const __INIT: $t = $init; // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed. unsafe { $crate::thread::LocalKey::new(|_| { + $(#[$align_attr])* static VAL: $crate::thread::local_impl::EagerStorage<$t> = $crate::thread::local_impl::EagerStorage { value: __INIT }; &VAL.value @@ -25,27 +27,22 @@ pub macro thread_local_inner { }}, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{ #[inline] fn __init() -> $t { $init } unsafe { - use $crate::thread::LocalKey; - use $crate::thread::local_impl::LazyStorage; - - LocalKey::new(|init| { - static VAL: LazyStorage<$t> = LazyStorage::new(); + $crate::thread::LocalKey::new(|init| { + $(#[$align_attr])* + static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new(); VAL.get(init, __init) }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); - }, } #[allow(missing_debug_implementations)] +#[repr(transparent)] // Required for correctness of `#[rustc_align_static]` pub struct EagerStorage<T> { pub value: T, } @@ -53,14 +50,27 @@ pub struct EagerStorage<T> { // SAFETY: the target doesn't have threads. unsafe impl<T> Sync for EagerStorage<T> {} +#[derive(Clone, Copy, PartialEq, Eq)] +enum State { + Initial, + Alive, + Destroying, +} + #[allow(missing_debug_implementations)] +#[repr(C)] pub struct LazyStorage<T> { - value: UnsafeCell<Option<T>>, + // This field must be first, for correctness of `#[rustc_align_static]` + value: UnsafeCell<MaybeUninit<T>>, + state: Cell<State>, } impl<T> LazyStorage<T> { pub const fn new() -> LazyStorage<T> { - LazyStorage { value: UnsafeCell::new(None) } + LazyStorage { + value: UnsafeCell::new(MaybeUninit::uninit()), + state: Cell::new(State::Initial), + } } /// Gets a pointer to the TLS value, potentially initializing it with the @@ -70,24 +80,39 @@ impl<T> LazyStorage<T> { /// has occurred. #[inline] pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { - let value = unsafe { &*self.value.get() }; - match value { - Some(v) => v, - None => self.initialize(i, f), + if self.state.get() == State::Alive { + self.value.get() as *const T + } else { + self.initialize(i, f) } } #[cold] fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let value = i.and_then(Option::take).unwrap_or_else(f); - // Destroy the old value, after updating the TLS variable as the - // destructor might reference it. + + // Destroy the old value if it is initialized // FIXME(#110897): maybe panic on recursive initialization. + if self.state.get() == State::Alive { + self.state.set(State::Destroying); + // Safety: we check for no initialization during drop below + unsafe { + ptr::drop_in_place(self.value.get() as *mut T); + } + self.state.set(State::Initial); + } + + // Guard against initialization during drop + if self.state.get() == State::Destroying { + panic!("Attempted to initialize thread-local while it is being dropped"); + } + unsafe { - self.value.get().replace(Some(value)); + self.value.get().write(MaybeUninit::new(value)); } - // SAFETY: we just set this to `Some`. - unsafe { (*self.value.get()).as_ref().unwrap_unchecked() } + self.state.set(State::Alive); + + self.value.get() as *const T } } diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs index fe6af27db3a..88bb5ae7c65 100644 --- a/library/std/src/sys/thread_local/os.rs +++ b/library/std/src/sys/thread_local/os.rs @@ -1,8 +1,12 @@ use super::key::{Key, LazyKey, get, set}; use super::{abort_on_dtor_unwind, guard}; +use crate::alloc::{self, Layout}; use crate::cell::Cell; use crate::marker::PhantomData; -use crate::ptr; +use crate::mem::ManuallyDrop; +use crate::ops::Deref; +use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; +use crate::ptr::{self, NonNull}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] @@ -10,17 +14,12 @@ use crate::ptr; #[unstable(feature = "thread_local_internals", issue = "none")] #[rustc_macro_transparency = "semitransparent"] pub macro thread_local_inner { - // used to generate the `LocalKey` value for const-initialized thread locals - (@key $t:ty, const $init:expr) => { - $crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR }) - }, - // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user // provided type or type alias with a matching name. Please update the shadowing test in // `tests/thread.rs` if these types are renamed. // used to generate the `LocalKey` value for `thread_local!`. - (@key $t:ty, $init:expr) => {{ + (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{ #[inline] fn __init() -> $t { $init } @@ -29,37 +28,148 @@ pub macro thread_local_inner { // in `tests/thread.rs` if these types are renamed. unsafe { $crate::thread::LocalKey::new(|init| { - static VAL: $crate::thread::local_impl::Storage<$t> + static VAL: $crate::thread::local_impl::Storage<$t, { + $({ + // Ensure that attributes have valid syntax + // and that the proper feature gate is enabled + $(#[$($align_attr)*])+ + #[allow(unused)] + static DUMMY: () = (); + })? + + #[allow(unused_mut)] + let mut final_align = $crate::thread::local_impl::value_align::<$t>(); + $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)? + final_align + }> = $crate::thread::local_impl::Storage::new(); VAL.get(init, __init) }) } }}, - ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { - $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = - $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); + + // process a single `rustc_align_static` attribute + (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => { + let new_align: $crate::primitive::usize = $($align)*; + if new_align > $final_align { + $final_align = new_align; + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + // process a single `cfg_attr` attribute + // by translating it into a `cfg`ed block and recursing. + // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate + + (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg(true)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg(false)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? + }, + + (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => { + #[cfg($cfg_pred)] + { + $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*); + } + + $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)? }, } /// Use a regular global static to store this key; the state provided will then be /// thread-local. +/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`. #[allow(missing_debug_implementations)] -pub struct Storage<T> { +pub struct Storage<T, const ALIGN: usize> { key: LazyKey, marker: PhantomData<Cell<T>>, } -unsafe impl<T> Sync for Storage<T> {} +unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {} +#[repr(C)] struct Value<T: 'static> { + // This field must be first, for correctness of `#[rustc_align_static]` value: T, // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`. key: Key, } -impl<T: 'static> Storage<T> { - pub const fn new() -> Storage<T> { - Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData } +pub const fn value_align<T: 'static>() -> usize { + crate::mem::align_of::<Value<T>>() +} + +/// Equivalent to `Box<Value<T>>`, but potentially over-aligned. +struct AlignedBox<T: 'static, const ALIGN: usize> { + ptr: NonNull<Value<T>>, +} + +impl<T: 'static, const ALIGN: usize> AlignedBox<T, ALIGN> { + #[inline] + fn new(v: Value<T>) -> Self { + let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap(); + + let ptr: *mut Value<T> = (unsafe { alloc::alloc(layout) }).cast(); + let Some(ptr) = NonNull::new(ptr) else { + alloc::handle_alloc_error(layout); + }; + unsafe { ptr.write(v) }; + Self { ptr } + } + + #[inline] + fn into_raw(b: Self) -> *mut Value<T> { + let md = ManuallyDrop::new(b); + md.ptr.as_ptr() + } + + #[inline] + unsafe fn from_raw(ptr: *mut Value<T>) -> Self { + Self { ptr: unsafe { NonNull::new_unchecked(ptr) } } + } +} + +impl<T: 'static, const ALIGN: usize> Deref for AlignedBox<T, ALIGN> { + type Target = Value<T>; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self.ptr.as_ptr()) } + } +} + +impl<T: 'static, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> { + #[inline] + fn drop(&mut self) { + let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap(); + + unsafe { + let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place())); + alloc::dealloc(self.ptr.as_ptr().cast(), layout); + if let Err(payload) = unwind_result { + resume_unwind(payload); + } + } + } +} + +impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> { + pub const fn new() -> Storage<T, ALIGN> { + Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData } } /// Gets a pointer to the TLS value, potentially initializing it with the @@ -95,8 +205,11 @@ impl<T: 'static> Storage<T> { return ptr::null(); } - let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key }); - let ptr = Box::into_raw(value); + let value = AlignedBox::<T, ALIGN>::new(Value { + value: i.and_then(Option::take).unwrap_or_else(f), + key, + }); + let ptr = AlignedBox::into_raw(value); // SAFETY: // * key came from a `LazyKey` and is thus correct. @@ -114,7 +227,7 @@ impl<T: 'static> Storage<T> { // initializer has already returned and the next scope only starts // after we return the pointer. Therefore, there can be no references // to the old value. - drop(unsafe { Box::from_raw(old) }); + drop(unsafe { AlignedBox::<T, ALIGN>::from_raw(old) }); } // SAFETY: We just created this value above. @@ -122,7 +235,7 @@ impl<T: 'static> Storage<T> { } } -unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) { +unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) { // SAFETY: // // The OS TLS ensures that this key contains a null value when this @@ -133,7 +246,7 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) { // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. abort_on_dtor_unwind(|| { - let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) }; + let ptr = unsafe { AlignedBox::<T, ALIGN>::from_raw(ptr as *mut Value<T>) }; let key = ptr.key; // SAFETY: `key` is the TLS key `ptr` was stored under. unsafe { set(key, ptr::without_provenance_mut(1)) }; diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 0a6f2e5d508..4259a4d1f3b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -132,6 +132,216 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { } } +#[doc(hidden)] +#[allow_internal_unstable(thread_local_internals)] +#[unstable(feature = "thread_local_internals", issue = "none")] +#[rustc_macro_transparency = "semitransparent"] +pub macro thread_local_process_attrs { + + // Parse `cfg_attr` to figure out whether it's a `rustc_align_static`. + // Each `cfg_attr` can have zero or more attributes on the RHS, and can be nested. + + // finished parsing the `cfg_attr`, it had no `rustc_align_static` + ( + [] [$(#[$($prev_other_attrs:tt)*])*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)*] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),*)]]; + $($rest)* + ); + ), + + // finished parsing the `cfg_attr`, it had nothing but `rustc_align_static` + ( + [$(#[$($prev_align_attrs:tt)*])+] []; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)*]; + $($rest)* + ); + ), + + // finished parsing the `cfg_attr`, it had a mix of `rustc_align_static` and other attrs + ( + [$(#[$($prev_align_attrs:tt)*])+] [$(#[$($prev_other_attrs:tt)*])+]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] }; + [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*]; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),+)]]; + $($rest)* + ); + ), + + // it's a `rustc_align_static` + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [rustc_align_static($($align_static_args:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)* #[rustc_align_static($($align_static_args)*)]] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's a nested `cfg_attr(true, ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's a nested `cfg_attr(false, ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + + // it's a nested `cfg_attr(..., ...)`; recurse into RHS + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: ($cfg_lhs), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + // it's some other attribute + ( + [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [$meta:meta $(, $($attr_rhs:tt)*)?] }; + $($rest:tt)* + ) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$meta]]; + @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] }; + $($rest)* + ); + ), + + + // Separate attributes into `rustc_align_static` and everything else: + + // `rustc_align_static` attribute + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[rustc_align_static $($attr_rest:tt)*] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)* #[rustc_align_static $($attr_rest)*]] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(true, ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(false, ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // `cfg_attr(..., ...)` attribute; parse it + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [] []; + @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] }; + [$($prev_align_attrs)*] [$($prev_other_attrs)*]; + $($rest)* + ); + ), + + // doc comment not followed by any other attributes; process it all at once to avoid blowing recursion limit + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; $(#[doc $($doc_rhs:tt)*])+ $vis:vis static $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* $(#[doc $($doc_rhs)*])+]; + $vis static $($rest)* + ); + ), + + // 8 lines of doc comment; process them all at once to avoid blowing recursion limit + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; + #[doc $($doc_rhs_1:tt)*] #[doc $($doc_rhs_2:tt)*] #[doc $($doc_rhs_3:tt)*] #[doc $($doc_rhs_4:tt)*] + #[doc $($doc_rhs_5:tt)*] #[doc $($doc_rhs_6:tt)*] #[doc $($doc_rhs_7:tt)*] #[doc $($doc_rhs_8:tt)*] + $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* + #[doc $($doc_rhs_1)*] #[doc $($doc_rhs_2)*] #[doc $($doc_rhs_3)*] #[doc $($doc_rhs_4)*] + #[doc $($doc_rhs_5)*] #[doc $($doc_rhs_6)*] #[doc $($doc_rhs_7)*] #[doc $($doc_rhs_8)*]]; + $($rest)* + ); + ), + + // other attribute + ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[$($attr:tt)*] $($rest:tt)*) => ( + $crate::thread::local_impl::thread_local_process_attrs!( + [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$($attr)*]]; + $($rest)* + ); + ), + + + // Delegate to `thread_local_inner` once attributes are fully categorized: + + // process `const` declaration and recurse + ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = const $init:block $(; $($($rest:tt)+)?)?) => ( + $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> = + $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, const $init); + + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? + ), + + // process non-`const` declaration and recurse + ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = $init:expr $(; $($($rest:tt)+)?)?) => ( + $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> = + $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, $init); + + $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)? + ), +} + /// Declare a new thread local storage key of type [`std::thread::LocalKey`]. /// /// # Syntax @@ -182,28 +392,11 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] #[allow_internal_unstable(thread_local_internals)] macro_rules! thread_local { - // empty (base case for the recursion) () => {}; - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); - $crate::thread_local!($($rest)*); - ); - - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); - ); - - // process multiple declarations - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - $crate::thread_local!($($rest)*); - ); - - // handle a single declaration - ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( - $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init); - ); + ($($tt:tt)+) => { + $crate::thread::local_impl::thread_local_process_attrs!([] []; $($tt)+); + }; } /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 1768369792a..fd7cce3f97d 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -207,6 +207,7 @@ pub use self::local::{AccessError, LocalKey}; #[doc(hidden)] #[unstable(feature = "thread_local_internals", issue = "none")] pub mod local_impl { + pub use super::local::thread_local_process_attrs; pub use crate::sys::thread_local::*; } diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 29f220d8a70..dc8eadd7514 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -66,6 +66,8 @@ fn thread_local_hygeiene() { type Storage = (); type LazyStorage = (); type EagerStorage = (); + #[allow(non_camel_case_types)] + type usize = (); thread_local! { static A: LocalKey = const { () }; static B: Storage = const { () }; diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 9f9af1d9abe..4b0080f1c80 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -587,6 +587,7 @@ Select which editor you would like to set up [default: None]: "; "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9", "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce", "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1", + "e260553b71e4773c30a63c4b23b42b279fc73e72f95b775c47b7b7c511c51595", ], EditorKind::Helix => &[ "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", @@ -594,6 +595,7 @@ Select which editor you would like to set up [default: None]: "; "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5", "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1", + "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6", ], EditorKind::Vim | EditorKind::VsCode => &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", @@ -610,6 +612,7 @@ Select which editor you would like to set up [default: None]: "; "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893", "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12", "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054", + "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47", ], EditorKind::Zed => &[ "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", @@ -617,6 +620,7 @@ Select which editor you would like to set up [default: None]: "; "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26", "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6", "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382", + "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f", ], } } diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml index f61243a4d71..078b877e44b 100644 --- a/src/ci/citool/Cargo.toml +++ b/src/ci/citool/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "citool" version = "0.1.0" -edition = "2021" +edition = "2024" [dependencies] anyhow = "1" diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index fe1b36673a1..255d39846da 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -24,7 +24,7 @@ use crate::github::JobInfoResolver; use crate::jobs::RunType; use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics}; use crate::test_dashboard::generate_test_dashboard; -use crate::utils::{load_env_var, output_details}; +use crate::utils::{init_submodule_if_needed, load_env_var, output_details}; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); pub const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); @@ -121,6 +121,8 @@ fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> any (key.clone(), value) })); + init_submodule_if_needed("src/llvm-project/")?; + let mut cmd = Command::new(Path::new(DOCKER_DIRECTORY).join("run.sh")); cmd.arg(job.image()); cmd.envs(custom_env); diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs index 3176cb62f60..43b220255dc 100644 --- a/src/ci/citool/src/utils.rs +++ b/src/ci/citool/src/utils.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use std::convert::AsRef; use std::path::Path; +use std::process::Command; use anyhow::Context; @@ -34,3 +36,19 @@ where pub fn normalize_path_delimiters(name: &str) -> Cow<'_, str> { if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() } } + +pub fn init_submodule_if_needed<P: AsRef<Path>>(path_to_submodule: P) -> anyhow::Result<()> { + let path_to_submodule = path_to_submodule.as_ref(); + + if let Ok(mut iter) = path_to_submodule.read_dir() + && iter.any(|entry| entry.is_ok()) + { + // Seems like the submodule is already initialized, nothing to be done here. + return Ok(()); + } + let mut child = Command::new("git") + .args(&["submodule", "update", "--init"]) + .arg(path_to_submodule) + .spawn()?; + if !child.wait()?.success() { Err(anyhow::anyhow!("git command failed")) } else { Ok(()) } +} diff --git a/src/doc/book b/src/doc/book -Subproject 33f1af40cc44dde7e3e892f7a508e6f427d2cbc +Subproject 1d7c3e6abec2d5a9bfac798b29b7855b9502542 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject aa6ce337c0adf7a63e33960d184270f2a45ab9e +Subproject e2ed891f00361efc26616d82590b1c85d7a8920 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject f17a018b9989430967d1c58e9a12c51169abc74 +Subproject 23fc2682f8fcb887f77d0eaabba708809f834c1 diff --git a/src/doc/reference b/src/doc/reference -Subproject cc7247d8dfaef4c39000bb12c55c32ba5b5ba97 +Subproject e11adf6016a362766eea5a3f9832e193994dd0c diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4be78fac4ec..3b6c8917464 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -262,6 +262,20 @@ Consider writing the test as a proper incremental test instead. </div> +#### The edition directive + +The `//@ edition` directive can take an exact edition, a bounded half-open range of editions or a left-bounded half-open range of editions, this affects which edition is used by `./x test` to run the test. For example: + +- A test with the `//@ edition: 2018` directive will only run under the 2018 edition. +- A test with the `//@ edition: 2015..2021` directive can be run under both the 2015 and 2018 editions. However, CI will only run the test with the lowest edition possible (2015 in this case). +- A test with the `//@ edition: 2018..` directive will run under any edition greater or equal than 2018. However, CI will only run the test with the lowest edition possible (2018 in this case). + +You can also force `./x test` to use a specific edition by passing the `-- --edition=` argument. However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`: + +- A test with the `//@ edition: 2018` will run with the 2018 edition. +- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. +- A test with the `//@ edition: 2018..` will run with the 2018 edition. + ### Rustdoc | Directive | Explanation | Supported test suites | Possible values | diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 67882bb3813..a9ce738a013 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -47,6 +47,7 @@ - [\*-apple-watchos](platform-support/apple-watchos.md) - [\*-apple-visionos](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) + - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md) - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) @@ -67,6 +68,7 @@ - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) + - [armv7-unknown-linux-gnueabi](platform-support/armv7-unknown-linux-gnueabi.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d0b6ed51bc1..263ea1ddb42 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -34,7 +34,7 @@ target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) [`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC -`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) +[`aarch64-unknown-linux-gnu`](platform-support/aarch64-unknown-linux-gnu.md) | ARM64 Linux (kernel 4.1+, glibc 2.17+) [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) @@ -93,7 +93,7 @@ target | notes [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) +[`armv7-unknown-linux-gnueabihf`](platform-support/armv7-unknown-linux-gnueabi.md) | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required @@ -159,7 +159,7 @@ target | std | notes [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android -`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) +[`armv7-unknown-linux-gnueabi`](platform-support/armv7-unknown-linux-gnueabi.md) | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md new file mode 100644 index 00000000000..2003a3cb9ea --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md @@ -0,0 +1,50 @@ +# `aarch64-unknown-linux-gnu` + +**Tier: 1 (with Host Tools)** + +Target for 64-bit little endian ARMv8-A Linux 4.1+ programs using glibc 2.17+. + +## Target maintainers + +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com + +## Requirements + +Building the target itself requires a 64-bit little endian ARMv8-A compiler that is supported by +`cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build: + +```toml +[build] +target = ["aarch64-unknown-linux-gnu"] +``` + +If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.aarch64-unknown-linux-musl] +cc = "aarch64-linux-gnu-gcc" +cxx = "aarch64-linux-gnu-g++" +ar = "aarch64-linux-gnu-ar" +linker = "aarch64-linux-gnu-gcc" +``` + +## Building Rust programs + +This target is distributed through `rustup`, and otherwise requires no special configuration. + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit little endian ARMv8-A host or via QEMU +emulation. diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md index 7e18e8c157f..3d776677d23 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -14,9 +14,12 @@ Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus ## Target maintainers -[Rust Embedded Devices Working Group Arm Team] +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md index 5f40743f3d0..c461a1a3403 100644 --- a/src/doc/rustc/src/platform-support/arm-linux.md +++ b/src/doc/rustc/src/platform-support/arm-linux.md @@ -14,8 +14,8 @@ Linux (but not Android). Those targets are: * [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md) * `armv5te-unknown-linux-musleabi` * `armv5te-unknown-linux-uclibceabi` -* `armv7-unknown-linux-gnueabi` -* `armv7-unknown-linux-gnueabihf` +* [`armv7-unknown-linux-gnueabi`](armv7-unknown-linux-gnueabi.md) +* [`armv7-unknown-linux-gnueabihf`](armv7-unknown-linux-gnueabi.md) * `armv7-unknown-linux-musleabi` * `armv7-unknown-linux-musleabihf` * `armv7-unknown-linux-ohos` diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md new file mode 100644 index 00000000000..c2fe63a4908 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md @@ -0,0 +1,51 @@ +# `armv7-unknown-linux-gnueabi` and `armv7-unknown-linux-gnueabihf` + +* **Tier: 2 (with Host Tools)** for `armv7-unknown-linux-gnueabihf` +* **Tier: 2** for `armv7-unknown-linux-gnueabi` + +Target for 32-bit little endian ARMv7-A Linux 3.2+ programs using glibc 2.17+. + +## Target maintainers + +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com + +## Requirements + +Building the targets themselves requires a 32-bit little endian ARMv7-A compiler that is supported +by `cc-rs`. + +## Building the target + +These targets can be built by enabling it for a `rustc` build: + +```toml +[build] +target = ["armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabi"] +``` + +If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the +`bootstrap.toml`: + +```toml +[target.aarch64-unknown-linux-musl] +cc = "arm-linux-gnu-gcc" +cxx = "arm-linux-gnu-g++" +ar = "arm-linux-gnu-ar" +linker = "arm-linux-gnu-gcc" +``` + +## Building Rust programs + +These targets is distributed through `rustup`, and otherwise requires no special configuration. + +## Cross-compilation + +These targets can be cross-compiled from any host. + +## Testing + +These targets can be tested as normal with `x.py` on a 32-bit little endian ARMv7-A host or via +QEMU emulation. diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md index 3dadda86a5f..22278a0a7dc 100644 --- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -19,9 +19,12 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team] +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index c1252b4a4bf..9429eb6ab8a 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -15,10 +15,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[@chrisnc](https://github.com/chrisnc) -[Rust Embedded Devices Working Group Arm Team] +- [@chrisnc](https://github.com/chrisnc) +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 0d5a36c3ee2..e465eb79f49 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -17,10 +17,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[@chrisnc](https://github.com/chrisnc) -[Rust Embedded Devices Working Group Arm Team] +- [@chrisnc](https://github.com/chrisnc) +- [Rust Embedded Devices Working Group Arm Team] +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index 98dcf9bd396..192e013d3a4 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -22,7 +22,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md index d8f3970c8bf..b04cb7bfacf 100644 --- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv7-M]. ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md index b16d450275d..104520854b4 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv8-M] Baseline. ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index a2d515d07ea..5cc535ce376 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -26,7 +26,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index 9587590d12d..e8989616b84 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -13,8 +13,12 @@ Available targets: ## Target maintainers -[@dvdhrm](https://github.com/dvdhrm) -[@nicholasbishop](https://github.com/nicholasbishop) +- [@dvdhrm](https://github.com/dvdhrm) +- [@nicholasbishop](https://github.com/nicholasbishop) +- (for `aarch64-unknown-uefi` only) [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email]) + +[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml +[arm_email]: mailto:rust@arm.com ## Requirements diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index 3151cb1a6e7..e5abf67235a 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -6,6 +6,8 @@ :overrideCommand ["python3" "x.py" "check" + "--build-dir" + "build-rust-analyzer" "--json-output"]) :linkedProjects ["Cargo.toml" "compiler/rustc_codegen_cranelift/Cargo.toml" @@ -13,9 +15,9 @@ "library/Cargo.toml" "src/bootstrap/Cargo.toml" "src/tools/rust-analyzer/Cargo.toml"] - :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + :rustfmt ( :overrideCommand ["build-rust-analyzer/host/rustfmt/bin/rustfmt" "--edition=2024"]) - :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :procMacro ( :server "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" :enable t) :cargo ( :buildScripts ( :enable t :invocationLocation "root" @@ -23,6 +25,8 @@ :overrideCommand ["python3" "x.py" "check" + "--build-dir" + "build-rust-analyzer" "--json-output" "--compile-time-deps"])] :sysrootSrc "./library" diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml index 8c1782a1abc..e2de2a374cb 100644 --- a/src/etc/rust_analyzer_helix.toml +++ b/src/etc/rust_analyzer_helix.toml @@ -1,10 +1,10 @@ # This config uses a separate build directory for rust-analyzer, # so that r-a's checks don't block user `x` commands and vice-verse. -# R-a's build directory is located in `build/rust-analyzer`. +# R-a's build directory is located in `build-rust-analyzer`. # # To build rustfmt and proc macro server for r-a run the following command: # ``` -# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer +# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build-rust-analyzer # ``` [language-server.rust-analyzer.config] @@ -26,17 +26,17 @@ overrideCommand = [ "check", "--json-output", "--build-dir", - "build/rust-analyzer", + "build-rust-analyzer", ] [language-server.rust-analyzer.config.rustfmt] overrideCommand = [ - "build/rust-analyzer/host/rustfmt/bin/rustfmt", + "build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ] [language-server.rust-analyzer.config.procMacro] -server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" +server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" enable = true [language-server.rust-analyzer.config.rustc] @@ -58,6 +58,6 @@ overrideCommand = [ "check", "--json-output", "--build-dir", - "build/rust-analyzer", - "--compile-time-deps" + "build-rust-analyzer", + "--compile-time-deps", ] diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index b31169857c5..f89e8a2df18 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -5,6 +5,8 @@ "python3", "x.py", "check", + "--build-dir", + "build-rust-analyzer", "--json-output" ], "rust-analyzer.linkedProjects": [ @@ -16,10 +18,10 @@ "src/tools/rust-analyzer/Cargo.toml" ], "rust-analyzer.rustfmt.overrideCommand": [ - "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", + "${workspaceFolder}/build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ], - "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv", + "rust-analyzer.procMacro.server": "${workspaceFolder}/build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv", "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.buildScripts.enable": true, "rust-analyzer.cargo.buildScripts.invocationStrategy": "once", @@ -27,6 +29,8 @@ "python3", "x.py", "check", + "--build-dir", + "build-rust-analyzer", "--json-output", "--compile-time-deps" ], diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json index 7eace92500e..d98a082a9b8 100644 --- a/src/etc/rust_analyzer_zed.json +++ b/src/etc/rust_analyzer_zed.json @@ -7,7 +7,15 @@ "enable": true, "invocationLocation": "root", "invocationStrategy": "once", - "overrideCommand": ["python3", "x.py", "check", "--json-output", "--compile-time-deps"] + "overrideCommand": [ + "python3", + "x.py", + "check", + "--build-dir", + "build-rust-analyzer", + "--compile-time-deps", + "--json-output" + ] }, "extraEnv": { "RUSTC_BOOTSTRAP": "1" @@ -17,7 +25,14 @@ "check": { "invocationLocation": "root", "invocationStrategy": "once", - "overrideCommand": ["python3", "x.py", "check", "--json-output"] + "overrideCommand": [ + "python3", + "x.py", + "check", + "--json-output", + "--build-dir", + "build-rust-analyzer" + ] }, "linkedProjects": [ "Cargo.toml", @@ -29,14 +44,14 @@ ], "procMacro": { "enable": true, - "server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + "server": "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" }, "rustc": { "source": "./Cargo.toml" }, "rustfmt": { "overrideCommand": [ - "build/host/rustfmt/bin/rustfmt", + "build-rust-analyzer/host/rustfmt/bin/rustfmt", "--edition=2024" ] }, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6d959948918..65db816ad1a 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -7,6 +7,7 @@ use build_helper::git::GitConfig; use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; +use crate::edition::Edition; use crate::executor::ColorConfig; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -612,10 +613,7 @@ pub struct Config { pub git_hash: bool, /// The default Rust edition. - /// - /// FIXME: perform stronger validation for this. There are editions that *definitely* exists, - /// but there might also be "future" edition. - pub edition: Option<String>, + pub edition: Option<Edition>, // Configuration for various run-make tests frobbing things like C compilers or querying about // various LLVM component information. diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index e6916610190..a79978d036c 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -16,10 +16,11 @@ use crate::directives::directive_names::{ KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES, }; use crate::directives::needs::CachedNeedsConditions; +use crate::edition::{Edition, parse_edition}; use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; -use crate::help; use crate::util::static_regex; +use crate::{fatal, help}; pub(crate) mod auxiliary; mod cfg; @@ -415,10 +416,18 @@ impl TestProps { config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile) { let flags = split_flags(&flags); - for flag in &flags { + for (i, flag) in flags.iter().enumerate() { if flag == "--edition" || flag.starts_with("--edition=") { panic!("you must use `//@ edition` to configure the edition"); } + if (flag == "-C" + && flags.get(i + 1).is_some_and(|v| v.starts_with("incremental="))) + || flag.starts_with("-Cincremental=") + { + panic!( + "you must use `//@ incremental` to enable incremental compilation" + ); + } } self.compile_flags.extend(flags); } @@ -429,10 +438,13 @@ impl TestProps { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } - if let Some(edition) = config.parse_edition(ln, testfile) { + if let Some(range) = parse_edition_range(config, ln, testfile) { // The edition is added at the start, since flags from //@compile-flags must // be passed to rustc last. - self.compile_flags.insert(0, format!("--edition={}", edition.trim())); + self.compile_flags.insert( + 0, + format!("--edition={}", range.edition_to_test(config.edition)), + ); has_edition = true; } @@ -1116,10 +1128,6 @@ impl Config { } } - fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<String> { - self.parse_name_value_directive(line, "edition", testfile) - } - fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) { // If the flag is already true, don't bother looking at the directive. *value = *value || self.parse_name_directive(line, directive); @@ -1761,3 +1769,86 @@ enum IgnoreDecision { Continue, Error { message: String }, } + +fn parse_edition_range( + config: &Config, + line: &DirectiveLine<'_>, + testfile: &Utf8Path, +) -> Option<EditionRange> { + let raw = config.parse_name_value_directive(line, "edition", testfile)?; + let line_number = line.line_number; + + // Edition range is half-open: `[lower_bound, upper_bound)` + if let Some((lower_bound, upper_bound)) = raw.split_once("..") { + Some(match (maybe_parse_edition(lower_bound), maybe_parse_edition(upper_bound)) { + (Some(lower_bound), Some(upper_bound)) if upper_bound <= lower_bound => { + fatal!( + "{testfile}:{line_number}: the left side of `//@ edition` cannot be greater than or equal to the right side" + ); + } + (Some(lower_bound), Some(upper_bound)) => { + EditionRange::Range { lower_bound, upper_bound } + } + (Some(lower_bound), None) => EditionRange::RangeFrom(lower_bound), + (None, Some(_)) => { + fatal!( + "{testfile}:{line_number}: `..edition` is not a supported range in `//@ edition`" + ); + } + (None, None) => { + fatal!("{testfile}:{line_number}: `..` is not a supported range in `//@ edition`"); + } + }) + } else { + match maybe_parse_edition(&raw) { + Some(edition) => Some(EditionRange::Exact(edition)), + None => { + fatal!("{testfile}:{line_number}: empty value for `//@ edition`"); + } + } + } +} + +fn maybe_parse_edition(mut input: &str) -> Option<Edition> { + input = input.trim(); + if input.is_empty() { + return None; + } + Some(parse_edition(input)) +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum EditionRange { + Exact(Edition), + RangeFrom(Edition), + /// Half-open range: `[lower_bound, upper_bound)` + Range { + lower_bound: Edition, + upper_bound: Edition, + }, +} + +impl EditionRange { + fn edition_to_test(&self, requested: impl Into<Option<Edition>>) -> Edition { + let min_edition = Edition::Year(2015); + let requested = requested.into().unwrap_or(min_edition); + + match *self { + EditionRange::Exact(exact) => exact, + EditionRange::RangeFrom(lower_bound) => { + if requested >= lower_bound { + requested + } else { + lower_bound + } + } + EditionRange::Range { lower_bound, upper_bound } => { + if requested >= lower_bound && requested < upper_bound { + requested + } else { + lower_bound + } + } + } + } +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 16cf76be9a5..93621192d4b 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -4,10 +4,11 @@ use camino::Utf8Path; use semver::Version; use super::{ - DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives, - parse_normalize_rule, + DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version, + extract_version_range, iter_directives, parse_normalize_rule, }; use crate::common::{Config, Debugger, TestMode}; +use crate::directives::parse_edition; use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description<R: Read>( @@ -73,6 +74,7 @@ fn test_parse_normalize_rule() { struct ConfigBuilder { mode: Option<String>, channel: Option<String>, + edition: Option<Edition>, host: Option<String>, target: Option<String>, stage: Option<u32>, @@ -96,6 +98,11 @@ impl ConfigBuilder { self } + fn edition(&mut self, e: Edition) -> &mut Self { + self.edition = Some(e); + self + } + fn host(&mut self, s: &str) -> &mut Self { self.host = Some(s.to_owned()); self @@ -183,6 +190,10 @@ impl ConfigBuilder { ]; let mut args: Vec<String> = args.iter().map(ToString::to_string).collect(); + if let Some(edition) = &self.edition { + args.push(format!("--edition={edition}")); + } + if let Some(ref llvm_version) = self.llvm_version { args.push("--llvm-version".to_owned()); args.push(llvm_version.clone()); @@ -941,3 +952,130 @@ fn test_needs_target_std() { let config = cfg().target("x86_64-unknown-linux-gnu").build(); assert!(!check_ignore(&config, "//@ needs-target-std")); } + +fn parse_edition_range(line: &str) -> Option<EditionRange> { + let config = cfg().build(); + let line = super::DirectiveLine { line_number: 0, revision: None, raw_directive: line }; + + super::parse_edition_range(&config, &line, "tmp.rs".into()) +} + +#[test] +fn test_parse_edition_range() { + assert_eq!(None, parse_edition_range("hello-world")); + assert_eq!(None, parse_edition_range("edition")); + + assert_eq!(Some(EditionRange::Exact(2018.into())), parse_edition_range("edition: 2018")); + assert_eq!(Some(EditionRange::Exact(2021.into())), parse_edition_range("edition:2021")); + assert_eq!(Some(EditionRange::Exact(2024.into())), parse_edition_range("edition: 2024 ")); + assert_eq!(Some(EditionRange::Exact(Edition::Future)), parse_edition_range("edition: future")); + + assert_eq!(Some(EditionRange::RangeFrom(2018.into())), parse_edition_range("edition: 2018..")); + assert_eq!(Some(EditionRange::RangeFrom(2021.into())), parse_edition_range("edition:2021 ..")); + assert_eq!( + Some(EditionRange::RangeFrom(2024.into())), + parse_edition_range("edition: 2024 .. ") + ); + assert_eq!( + Some(EditionRange::RangeFrom(Edition::Future)), + parse_edition_range("edition: future.. ") + ); + + assert_eq!( + Some(EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }), + parse_edition_range("edition: 2018..2024") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2015.into(), upper_bound: 2021.into() }), + parse_edition_range("edition:2015 .. 2021 ") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: 2027.into() }), + parse_edition_range("edition: 2021 .. 2027 ") + ); + assert_eq!( + Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: Edition::Future }), + parse_edition_range("edition: 2021..future") + ); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_empty() { + parse_edition_range("edition:"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_invalid_edition() { + parse_edition_range("edition: hello"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_double_dots() { + parse_edition_range("edition: .."); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_inverted_range() { + parse_edition_range("edition: 2021..2015"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_inverted_range_future() { + parse_edition_range("edition: future..2015"); +} + +#[test] +#[should_panic] +fn test_parse_edition_range_empty_range() { + parse_edition_range("edition: 2021..2021"); +} + +#[track_caller] +fn assert_edition_to_test( + expected: impl Into<Edition>, + range: EditionRange, + default: Option<Edition>, +) { + let mut cfg = cfg(); + if let Some(default) = default { + cfg.edition(default); + } + assert_eq!(expected.into(), range.edition_to_test(cfg.build().edition)); +} + +#[test] +fn test_edition_range_edition_to_test() { + let e2015 = parse_edition("2015"); + let e2018 = parse_edition("2018"); + let e2021 = parse_edition("2021"); + let e2024 = parse_edition("2024"); + let efuture = parse_edition("future"); + + let exact = EditionRange::Exact(2021.into()); + assert_edition_to_test(2021, exact, None); + assert_edition_to_test(2021, exact, Some(e2018)); + assert_edition_to_test(2021, exact, Some(efuture)); + + assert_edition_to_test(Edition::Future, EditionRange::Exact(Edition::Future), None); + + let greater_equal_than = EditionRange::RangeFrom(2021.into()); + assert_edition_to_test(2021, greater_equal_than, None); + assert_edition_to_test(2021, greater_equal_than, Some(e2015)); + assert_edition_to_test(2021, greater_equal_than, Some(e2018)); + assert_edition_to_test(2021, greater_equal_than, Some(e2021)); + assert_edition_to_test(2024, greater_equal_than, Some(e2024)); + assert_edition_to_test(Edition::Future, greater_equal_than, Some(efuture)); + + let range = EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }; + assert_edition_to_test(2018, range, None); + assert_edition_to_test(2018, range, Some(e2015)); + assert_edition_to_test(2018, range, Some(e2018)); + assert_edition_to_test(2021, range, Some(e2021)); + assert_edition_to_test(2018, range, Some(e2024)); + assert_edition_to_test(2018, range, Some(efuture)); +} diff --git a/src/tools/compiletest/src/edition.rs b/src/tools/compiletest/src/edition.rs new file mode 100644 index 00000000000..36550cf5b2b --- /dev/null +++ b/src/tools/compiletest/src/edition.rs @@ -0,0 +1,35 @@ +use crate::fatal; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Edition { + // Note that the ordering here is load-bearing, as we want the future edition to be greater than + // any year-based edition. + Year(u32), + Future, +} + +impl std::fmt::Display for Edition { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Edition::Year(year) => write!(f, "{year}"), + Edition::Future => f.write_str("future"), + } + } +} + +impl From<u32> for Edition { + fn from(value: u32) -> Self { + Edition::Year(value) + } +} + +pub fn parse_edition(mut input: &str) -> Edition { + input = input.trim(); + if input == "future" { + Edition::Future + } else { + Edition::Year(input.parse().unwrap_or_else(|_| { + fatal!("`{input}` doesn't look like an edition"); + })) + } +} diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 15e31dadf97..2d759279f34 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -7,6 +7,7 @@ pub mod common; mod debuggers; pub mod diagnostics; pub mod directives; +pub mod edition; pub mod errors; mod executor; mod json; @@ -39,6 +40,7 @@ use crate::common::{ expected_output_path, output_base_dir, output_relative_path, }; use crate::directives::DirectivesCache; +use crate::edition::parse_edition; use crate::executor::{CollectedTest, ColorConfig}; /// Creates the `Config` instance for this invocation of compiletest. @@ -449,7 +451,7 @@ pub fn parse_config(args: Vec<String>) -> Config { has_enzyme, channel: matches.opt_str("channel").unwrap(), git_hash: matches.opt_present("git-hash"), - edition: matches.opt_str("edition"), + edition: matches.opt_str("edition").as_deref().map(parse_edition), cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), diff --git a/src/tools/miri/tests/pass/static_align.rs b/src/tools/miri/tests/pass/static_align.rs index f292f028568..bc6a9bf8af7 100644 --- a/src/tools/miri/tests/pass/static_align.rs +++ b/src/tools/miri/tests/pass/static_align.rs @@ -1,4 +1,7 @@ #![feature(static_align)] +#![deny(non_upper_case_globals)] + +use std::cell::Cell; // When a static uses `align(N)`, its address should be a multiple of `N`. @@ -8,7 +11,64 @@ static FOO: u64 = 0; #[rustc_align_static(512)] static BAR: u64 = 0; +struct HasDrop(*const HasDrop); + +impl Drop for HasDrop { + fn drop(&mut self) { + assert_eq!(core::ptr::from_mut(self).cast_const(), self.0); + } +} + +thread_local! { + #[rustc_align_static(4096)] + static LOCAL: u64 = 0; + + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(true, rustc_align_static(4096))] + static CONST_LOCAL: u64 = const { 0 }; + + #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))] + #[allow(unused_mut, reason = "test attribute handling")] + static HASDROP_LOCAL: Cell<HasDrop> = Cell::new(HasDrop(core::ptr::null())); + + /// I love doc comments. + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(all(), + cfg_attr(any(true), + cfg_attr(true, rustc_align_static(4096))))] + #[allow(unused_mut, reason = "test attribute handling")] + /// I love doc comments. + static HASDROP_CONST_LOCAL: Cell<HasDrop> = const { Cell::new(HasDrop(core::ptr::null())) }; + + #[cfg_attr(true,)] + #[cfg_attr(false,)] + #[cfg_attr( + true, + rustc_align_static(32), + cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")), + cfg_attr(false,) + )] + #[cfg_attr(false, rustc_align_static(0))] + static more_attr_testing: u64 = 0; +} + +fn thread_local_ptr<T>(key: &'static std::thread::LocalKey<T>) -> *const T { + key.with(|local| core::ptr::from_ref::<T>(local)) +} + fn main() { assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256)); assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512)); + + assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32)); + + // Test that address (and therefore alignment) is maintained during drop + let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL); + core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast()))); + let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL); + core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast()))); } diff --git a/src/tools/miri/tests/pass/thread_local-panic.rs b/src/tools/miri/tests/pass/thread_local-panic.rs new file mode 100644 index 00000000000..549acd23987 --- /dev/null +++ b/src/tools/miri/tests/pass/thread_local-panic.rs @@ -0,0 +1,8 @@ +thread_local! { + static LOCAL: u64 = panic!(); + +} + +fn main() { + let _ = std::panic::catch_unwind(|| LOCAL.with(|_| {})); +} diff --git a/src/tools/miri/tests/pass/thread_local-panic.stderr b/src/tools/miri/tests/pass/thread_local-panic.stderr new file mode 100644 index 00000000000..e69340a8102 --- /dev/null +++ b/src/tools/miri/tests/pass/thread_local-panic.stderr @@ -0,0 +1,5 @@ + +thread 'main' ($TID) panicked at tests/pass/thread_local-panic.rs:LL:CC: +explicit panic +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs index 894d1327da7..c0181d96053 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs @@ -1,7 +1,7 @@ #[unsafe(unsafe(no_mangle))] //~^ ERROR expected identifier, found keyword `unsafe` //~| ERROR cannot find attribute `r#unsafe` in this scope -//~| ERROR `r#unsafe` is not an unsafe attribute +//~| ERROR unnecessary `unsafe` fn a() {} fn main() {} diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index 0825cf79408..846800daa54 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -9,13 +9,11 @@ help: escape `unsafe` to use it as an identifier LL | #[unsafe(r#unsafe(no_mangle))] | ++ -error: `r#unsafe` is not an unsafe attribute +error: unnecessary `unsafe` on safe attribute --> $DIR/double-unsafe-attributes.rs:1:3 | LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes + | ^^^^^^ error: cannot find attribute `r#unsafe` in this scope --> $DIR/double-unsafe-attributes.rs:1:10 diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs index 0f241cc439f..d9054248a29 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs @@ -1,4 +1,4 @@ -#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute +#[unsafe(diagnostic::on_unimplemented( //~ ERROR: unnecessary `unsafe` message = "testing", ))] trait Foo {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr index 3bc291db5ac..a7662f5ee6c 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr @@ -1,10 +1,8 @@ -error: `diagnostic::on_unimplemented` is not an unsafe attribute +error: unnecessary `unsafe` on safe attribute --> $DIR/unsafe-safe-attribute_diagnostic.rs:1:3 | LL | #[unsafe(diagnostic::on_unimplemented( - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/compiletest-self-test/compile-flags-incremental.rs b/tests/ui/compiletest-self-test/compile-flags-incremental.rs new file mode 100644 index 00000000000..62a1ad84d8f --- /dev/null +++ b/tests/ui/compiletest-self-test/compile-flags-incremental.rs @@ -0,0 +1,17 @@ +//@ revisions: good bad bad-space +//@ check-pass + +//@[bad] compile-flags: -Cincremental=true +//@[bad] should-fail + +//@[bad-space] compile-flags: -C incremental=dir +//@[bad-space] should-fail + +fn main() {} + +// Tests should not try to manually enable incremental compilation with +// `-Cincremental`, because that typically results in stray directories being +// created in the repository root. +// +// Instead, use the `//@ incremental` directive, which instructs compiletest +// to handle the details of passing `-Cincremental` with a fresh directory. diff --git a/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs new file mode 100644 index 00000000000..29d4facffce --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs @@ -0,0 +1,11 @@ +// The feature gate error may be emitted twice, but only on certain targets +//@ dont-require-annotations: ERROR +//@ dont-check-compiler-stderr + +#![crate_type = "lib"] + +thread_local! { + //~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature + #[rustc_align_static(16)] + static THREAD_LOCAL: u16 = 0; +} diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs new file mode 100644 index 00000000000..61a8d8f0054 --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs @@ -0,0 +1,16 @@ +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +macro_rules! globbing{ + () => { + pub use same_res_ambigious_extern_macro::*; + } +} + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +globbing! {} // this imports the same `RustEmbed` macro with `pub` visibility + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs new file mode 100644 index 00000000000..4e9b8427092 --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs @@ -0,0 +1,8 @@ +//@ edition: 2018 +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_derive(RustEmbed)] +pub fn rust_embed_derive(_input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs new file mode 100644 index 00000000000..5269dcd0b17 --- /dev/null +++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs @@ -0,0 +1,11 @@ +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +// this imports the same `RustEmbed` macro with `pub` visibility +pub use same_res_ambigious_extern_macro::*; + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; diff --git a/tests/ui/imports/same-res-ambigious.fail.stderr b/tests/ui/imports/same-res-ambigious.fail.stderr new file mode 100644 index 00000000000..dfd7c5a5f94 --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.fail.stderr @@ -0,0 +1,20 @@ +error[E0603]: derive macro `Embed` is private + --> $DIR/same-res-ambigious.rs:8:28 + | +LL | #[derive(ambigious_extern::Embed)] + | ^^^^^ private derive macro + | +note: the derive macro `Embed` is defined here + --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ +help: import `Embed` directly + | +LL - #[derive(ambigious_extern::Embed)] +LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/same-res-ambigious.nightly-fail.stderr b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr new file mode 100644 index 00000000000..dfd7c5a5f94 --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr @@ -0,0 +1,20 @@ +error[E0603]: derive macro `Embed` is private + --> $DIR/same-res-ambigious.rs:8:28 + | +LL | #[derive(ambigious_extern::Embed)] + | ^^^^^ private derive macro + | +note: the derive macro `Embed` is defined here + --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ +help: import `Embed` directly + | +LL - #[derive(ambigious_extern::Embed)] +LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)] + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/same-res-ambigious.rs b/tests/ui/imports/same-res-ambigious.rs new file mode 100644 index 00000000000..b5c13a15b7c --- /dev/null +++ b/tests/ui/imports/same-res-ambigious.rs @@ -0,0 +1,11 @@ +//@ edition: 2018 +//@ revisions: fail pass +//@[pass] check-pass +//@[pass] aux-crate: ambigious_extern=same-res-ambigious-extern.rs +//@[fail] aux-crate: ambigious_extern=same-res-ambigious-extern-fail.rs +// see https://github.com/rust-lang/rust/pull/147196 + +#[derive(ambigious_extern::Embed)] //[fail]~ ERROR: derive macro `Embed` is private +struct Foo{} + +fn main(){} diff --git a/tests/ui/indexing/index_message.stderr b/tests/ui/indexing/index_message.stderr index 6affb1ed962..b6f61379f2a 100644 --- a/tests/ui/indexing/index_message.stderr +++ b/tests/ui/indexing/index_message.stderr @@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/index_message.rs:3:14 | LL | let _ = z[0]; - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr index b18fe1512b5..f388fdf85cd 100644 --- a/tests/ui/issues/issue-27842.stderr +++ b/tests/ui/issues/issue-27842.stderr @@ -2,17 +2,17 @@ error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer --> $DIR/issue-27842.rs:4:16 | LL | let _ = tup[0]; - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})` --> $DIR/issue-27842.rs:9:16 | LL | let _ = tup[i]; - | ^-^ - | | - | cannot access tuple elements at a variable index + | ^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/issue-27842.rs:14:16 @@ -20,7 +20,7 @@ error[E0608]: cannot index into a value of type `({integer},)` LL | let _ = tup[3]; | ^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-local-data-key-priv.stderr b/tests/ui/macros/macro-local-data-key-priv.stderr index e93bd11046d..8df1aec140d 100644 --- a/tests/ui/macros/macro-local-data-key-priv.stderr +++ b/tests/ui/macros/macro-local-data-key-priv.stderr @@ -9,7 +9,7 @@ note: the constant `baz` is defined here | LL | thread_local!(static baz: f64 = 0.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs index 81eadb6692f..60290b883cb 100644 --- a/tests/ui/macros/macro-rules-attr-error.rs +++ b/tests/ui/macros/macro-rules-attr-error.rs @@ -50,3 +50,22 @@ macro_rules! forward_referenced_attr { macro_rules! cyclic_attr { attr() {} => {} } + +macro_rules! attr_with_safety { + unsafe attr() { struct RequiresUnsafe; } => {}; + attr() { struct SafeInvocation; } => {}; +} + +#[attr_with_safety] +struct SafeInvocation; + +//~v ERROR: unnecessary `unsafe` on safe attribute invocation +#[unsafe(attr_with_safety)] +struct SafeInvocation; + +//~v ERROR: unsafe attribute invocation requires `unsafe` +#[attr_with_safety] +struct RequiresUnsafe; + +#[unsafe(attr_with_safety)] +struct RequiresUnsafe; diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr index 674d35091b6..27527a2da7e 100644 --- a/tests/ui/macros/macro-rules-attr-error.stderr +++ b/tests/ui/macros/macro-rules-attr-error.stderr @@ -9,6 +9,18 @@ LL | #[local_attr] | = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info) +error: unnecessary `unsafe` on safe attribute invocation + --> $DIR/macro-rules-attr-error.rs:63:3 + | +LL | #[unsafe(attr_with_safety)] + | ^^^^^^ + +error: unsafe attribute invocation requires `unsafe` + --> $DIR/macro-rules-attr-error.rs:67:1 + | +LL | #[attr_with_safety] + | ^^^^^^^^^^^^^^^^^^^ + error: cannot find macro `local_attr` in this scope --> $DIR/macro-rules-attr-error.rs:27:5 | @@ -59,5 +71,5 @@ note: a macro with the same name exists, but it appears later LL | macro_rules! cyclic_attr { | ^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs index d081c06044f..e1ea38f2795 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs @@ -37,10 +37,9 @@ fn g1() { //~| HELP: maybe write a path separator here _ => {} } - if let Foo:Bar = f() { //~ WARN: irrefutable `if let` pattern + if let Foo:Bar = f() { //~^ ERROR: expected one of //~| HELP: maybe write a path separator here - //~| HELP: consider replacing the `if let` with a `let` } } diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr index a9bad96f9af..061586882e0 100644 --- a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr +++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr @@ -64,7 +64,7 @@ LL | if let Foo::Bar = f() { | + error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:49:16 + --> $DIR/issue-87086-colon-path-sep.rs:48:16 | LL | ref qux: Foo::Baz => {} | ^ -------- specifying the type of a pattern isn't supported @@ -77,7 +77,7 @@ LL | ref qux::Foo::Baz => {} | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:58:16 + --> $DIR/issue-87086-colon-path-sep.rs:57:16 | LL | mut qux: Foo::Baz => {} | ^ -------- specifying the type of a pattern isn't supported @@ -90,7 +90,7 @@ LL | mut qux::Foo::Baz => {} | ~~ error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:69:12 + --> $DIR/issue-87086-colon-path-sep.rs:68:12 | LL | Foo:Bar::Baz => {} | ^-------- specifying the type of a pattern isn't supported @@ -103,7 +103,7 @@ LL | Foo::Bar::Baz => {} | + error: expected one of `@` or `|`, found `:` - --> $DIR/issue-87086-colon-path-sep.rs:75:12 + --> $DIR/issue-87086-colon-path-sep.rs:74:12 | LL | Foo:Bar => {} | ^--- specifying the type of a pattern isn't supported @@ -115,15 +115,5 @@ help: maybe write a path separator here LL | Foo::Bar => {} | + -warning: irrefutable `if let` pattern - --> $DIR/issue-87086-colon-path-sep.rs:40:8 - | -LL | if let Foo:Bar = f() { - | ^^^^^^^^^^^^^^^^^ - | - = note: this pattern will always match, so the `if let` is useless - = help: consider replacing the `if let` with a `let` - = note: `#[warn(irrefutable_let_patterns)]` on by default - -error: aborting due to 9 previous errors; 1 warning emitted +error: aborting due to 9 previous errors diff --git a/tests/ui/parser/macro/bad-macro-definition.rs b/tests/ui/parser/macro/bad-macro-definition.rs index 3c5c93ea3b3..12df6e64bd2 100644 --- a/tests/ui/parser/macro/bad-macro-definition.rs +++ b/tests/ui/parser/macro/bad-macro-definition.rs @@ -20,3 +20,6 @@ macro_rules! e { {} } macro_rules! f {} //~^ ERROR: macros must contain at least one rule + +macro_rules! g { unsafe {} => {} } +//~^ ERROR: `unsafe` is only supported on `attr` rules diff --git a/tests/ui/parser/macro/bad-macro-definition.stderr b/tests/ui/parser/macro/bad-macro-definition.stderr index de6d9d6a38b..d15f33f708d 100644 --- a/tests/ui/parser/macro/bad-macro-definition.stderr +++ b/tests/ui/parser/macro/bad-macro-definition.stderr @@ -52,5 +52,11 @@ error: macros must contain at least one rule LL | macro_rules! f {} | ^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: `unsafe` is only supported on `attr` rules + --> $DIR/bad-macro-definition.rs:24:18 + | +LL | macro_rules! g { unsafe {} => {} } + | ^^^^^^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/parser/macro/macro-attr-bad.rs b/tests/ui/parser/macro/macro-attr-bad.rs index 9f50b057a7a..0ac46c8b768 100644 --- a/tests/ui/parser/macro/macro-attr-bad.rs +++ b/tests/ui/parser/macro/macro-attr-bad.rs @@ -13,6 +13,12 @@ macro_rules! attr_incomplete_3 { attr() {} } macro_rules! attr_incomplete_4 { attr() {} => } //~^ ERROR macro definition ended unexpectedly +macro_rules! attr_incomplete_5 { unsafe } +//~^ ERROR macro definition ended unexpectedly + +macro_rules! attr_incomplete_6 { unsafe attr } +//~^ ERROR macro definition ended unexpectedly + macro_rules! attr_noparens_1 { attr{} {} => {} } //~^ ERROR `attr` rule argument matchers require parentheses diff --git a/tests/ui/parser/macro/macro-attr-bad.stderr b/tests/ui/parser/macro/macro-attr-bad.stderr index bf0ed13cd55..481ef8118ae 100644 --- a/tests/ui/parser/macro/macro-attr-bad.stderr +++ b/tests/ui/parser/macro/macro-attr-bad.stderr @@ -22,8 +22,20 @@ error: macro definition ended unexpectedly LL | macro_rules! attr_incomplete_4 { attr() {} => } | ^ expected right-hand side of macro rule +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:16:40 + | +LL | macro_rules! attr_incomplete_5 { unsafe } + | ^ expected `attr` + +error: macro definition ended unexpectedly + --> $DIR/macro-attr-bad.rs:19:45 + | +LL | macro_rules! attr_incomplete_6 { unsafe attr } + | ^ expected macro attr args + error: `attr` rule argument matchers require parentheses - --> $DIR/macro-attr-bad.rs:16:36 + --> $DIR/macro-attr-bad.rs:22:36 | LL | macro_rules! attr_noparens_1 { attr{} {} => {} } | ^^ @@ -35,7 +47,7 @@ LL + macro_rules! attr_noparens_1 { attr() {} => {} } | error: `attr` rule argument matchers require parentheses - --> $DIR/macro-attr-bad.rs:19:36 + --> $DIR/macro-attr-bad.rs:25:36 | LL | macro_rules! attr_noparens_2 { attr[] {} => {} } | ^^ @@ -47,13 +59,13 @@ LL + macro_rules! attr_noparens_2 { attr() {} => {} } | error: invalid macro matcher; matchers must be contained in balanced delimiters - --> $DIR/macro-attr-bad.rs:22:37 + --> $DIR/macro-attr-bad.rs:28:37 | LL | macro_rules! attr_noparens_3 { attr _ {} => {} } | ^ error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:25:52 + --> $DIR/macro-attr-bad.rs:31:52 | LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } | -------- ^^^^^^^^ duplicate binding @@ -61,7 +73,7 @@ LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} } | previous binding error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:28:49 + --> $DIR/macro-attr-bad.rs:34:49 | LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } | -------- ^^^^^^^^ duplicate binding @@ -69,12 +81,12 @@ LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} } | previous binding error: duplicate matcher binding - --> $DIR/macro-attr-bad.rs:31:51 + --> $DIR/macro-attr-bad.rs:37:51 | LL | macro_rules! attr_dup_matcher_3 { attr($x:ident) {$x:ident} => {} } | -------- ^^^^^^^^ duplicate binding | | | previous binding -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/parser/macro/macro-derive-bad.rs b/tests/ui/parser/macro/macro-derive-bad.rs index 79b9eb8c113..74e7d9acdaf 100644 --- a/tests/ui/parser/macro/macro-derive-bad.rs +++ b/tests/ui/parser/macro/macro-derive-bad.rs @@ -41,3 +41,6 @@ macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} } //~^ ERROR duplicate matcher binding //~| NOTE duplicate binding //~| NOTE previous binding + +macro_rules! derive_unsafe { unsafe derive() {} => {} } +//~^ ERROR `unsafe` is only supported on `attr` rules diff --git a/tests/ui/parser/macro/macro-derive-bad.stderr b/tests/ui/parser/macro/macro-derive-bad.stderr index ec750c9ac82..c98535f4031 100644 --- a/tests/ui/parser/macro/macro-derive-bad.stderr +++ b/tests/ui/parser/macro/macro-derive-bad.stderr @@ -86,5 +86,11 @@ LL | macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} } | | | previous binding -error: aborting due to 12 previous errors +error: `unsafe` is only supported on `attr` rules + --> $DIR/macro-derive-bad.rs:45:30 + | +LL | macro_rules! derive_unsafe { unsafe derive() {} => {} } + | ^^^^^^ + +error: aborting due to 13 previous errors diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs index 18d7061d69c..75059d33db6 100644 --- a/tests/ui/parser/type-ascription-in-pattern.rs +++ b/tests/ui/parser/type-ascription-in-pattern.rs @@ -1,15 +1,16 @@ fn foo(x: bool) -> i32 { - match x { //~ ERROR struct literals are not allowed here - x: i32 => x, //~ ERROR expected - true => 42., //~ ERROR expected identifier - false => 0.333, //~ ERROR expected identifier + match x { + x: i32 => x, //~ ERROR: expected + //~^ ERROR: mismatched types + true => 42., + false => 0.333, } -} //~ ERROR expected one of +} fn main() { match foo(true) { - 42: i32 => (), //~ ERROR expected - _: f64 => (), //~ ERROR expected - x: i32 => (), //~ ERROR expected + 42: i32 => (), //~ ERROR: expected + _: f64 => (), //~ ERROR: expected + x: i32 => (), //~ ERROR: expected } } diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr index 135879f208b..09190754993 100644 --- a/tests/ui/parser/type-ascription-in-pattern.stderr +++ b/tests/ui/parser/type-ascription-in-pattern.stderr @@ -1,64 +1,18 @@ -error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>` - --> $DIR/type-ascription-in-pattern.rs:3:16 - | -LL | match x { - | - while parsing this struct -LL | x: i32 => x, - | -^^ expected one of 8 possible tokens - | | - | help: try adding a comma: `,` - -error: expected identifier, found keyword `true` - --> $DIR/type-ascription-in-pattern.rs:4:9 - | -LL | match x { - | - while parsing this struct -LL | x: i32 => x, -LL | true => 42., - | ^^^^ expected identifier, found keyword - -error: expected identifier, found keyword `false` - --> $DIR/type-ascription-in-pattern.rs:5:9 - | -LL | match x { - | - while parsing this struct -... -LL | false => 0.333, - | ^^^^^ expected identifier, found keyword - -error: struct literals are not allowed here - --> $DIR/type-ascription-in-pattern.rs:2:11 - | -LL | match x { - | ___________^ -LL | | x: i32 => x, -LL | | true => 42., -LL | | false => 0.333, -LL | | } - | |_____^ - | -help: surround the struct literal with parentheses +error: expected one of `@` or `|`, found `:` + --> $DIR/type-ascription-in-pattern.rs:3:10 | -LL ~ match (x { LL | x: i32 => x, -LL | true => 42., -LL | false => 0.333, -LL ~ }) + | ^ --- specifying the type of a pattern isn't supported + | | + | expected one of `@` or `|` | - -error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/type-ascription-in-pattern.rs:7:1 +help: maybe write a path separator here | -LL | match x { - | ----- while parsing this `match` expression -... -LL | } - | - expected one of `.`, `?`, `{`, or an operator -LL | } - | ^ unexpected token +LL | x::i32 => x, + | ~~ error: expected one of `...`, `..=`, `..`, or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:11:11 + --> $DIR/type-ascription-in-pattern.rs:12:11 | LL | 42: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -66,7 +20,7 @@ LL | 42: i32 => (), | expected one of `...`, `..=`, `..`, or `|` error: expected `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:12:10 + --> $DIR/type-ascription-in-pattern.rs:13:10 | LL | _: f64 => (), | ^ --- specifying the type of a pattern isn't supported @@ -74,7 +28,7 @@ LL | _: f64 => (), | expected `|` error: expected one of `@` or `|`, found `:` - --> $DIR/type-ascription-in-pattern.rs:13:10 + --> $DIR/type-ascription-in-pattern.rs:14:10 | LL | x: i32 => (), | ^ --- specifying the type of a pattern isn't supported @@ -86,5 +40,15 @@ help: maybe write a path separator here LL | x::i32 => (), | ~~ -error: aborting due to 8 previous errors +error[E0308]: mismatched types + --> $DIR/type-ascription-in-pattern.rs:3:19 + | +LL | fn foo(x: bool) -> i32 { + | --- expected `i32` because of return type +LL | match x { +LL | x: i32 => x, + | ^ expected `i32`, found `bool` + +error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/span/suggestion-non-ascii.stderr b/tests/ui/span/suggestion-non-ascii.stderr index 6e6e31a5698..361f744ee8e 100644 --- a/tests/ui/span/suggestion-non-ascii.stderr +++ b/tests/ui/span/suggestion-non-ascii.stderr @@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:3:24 | LL | println!("☃{}", tup[0]); - | ^^^ help: to access tuple elements, use: `.0` + | ^^^ help: to access tuple element `0`, use: `.0` + | + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs index 93241db09f9..e2db7c01adf 100644 --- a/tests/ui/static/static-align.rs +++ b/tests/ui/static/static-align.rs @@ -1,10 +1,14 @@ //@ run-pass +//@ compile-flags: --cfg FOURTY_TWO="42" --cfg TRUE --check-cfg=cfg(FOURTY_TWO,values("42")) --check-cfg=cfg(TRUE) #![feature(static_align)] +#![deny(non_upper_case_globals)] + +use std::cell::Cell; #[rustc_align_static(64)] static A: u8 = 0; -#[rustc_align_static(64)] +#[rustc_align_static(4096)] static B: u8 = 0; #[rustc_align_static(128)] @@ -17,10 +21,86 @@ unsafe extern "C" { static C: u64; } +struct HasDrop(*const HasDrop); + +impl Drop for HasDrop { + fn drop(&mut self) { + assert_eq!(core::ptr::from_mut(self).cast_const(), self.0); + } +} + +thread_local! { + #[rustc_align_static(4096)] + static LOCAL: u64 = 0; + + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(true, rustc_align_static(4096))] + static CONST_LOCAL: u64 = const { 0 }; + + #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))] + #[allow(unused_mut, reason = "test attribute handling")] + static HASDROP_LOCAL: Cell<HasDrop> = Cell::new(HasDrop(core::ptr::null())); + + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + #[allow(unused_mut, reason = "test attribute handling")] + #[cfg_attr(TRUE, + cfg_attr(FOURTY_TWO = "42", + cfg_attr(all(), + cfg_attr(any(true), + cfg_attr(true, rustc_align_static(4096))))))] + #[allow(unused_mut, reason = "test attribute handling")] + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + static HASDROP_CONST_LOCAL: Cell<HasDrop> = const { Cell::new(HasDrop(core::ptr::null())) }; + + #[cfg_attr(TRUE,)] + #[cfg_attr(true,)] + #[cfg_attr(false,)] + #[cfg_attr( + TRUE, + rustc_align_static(32), + cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")), + cfg_attr(false,) + )] + #[cfg_attr(false, rustc_align_static(0))] + static more_attr_testing: u64 = 0; +} + +fn thread_local_ptr<T>(key: &'static std::thread::LocalKey<T>) -> *const T { + key.with(|local| core::ptr::from_ref::<T>(local)) +} + fn main() { assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64)); - assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64)); + assert!(core::ptr::from_ref(&B).addr().is_multiple_of(4096)); assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128)); unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) }; + + assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096)); + assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32)); + + // Test that address (and therefore alignment) is maintained during drop + let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL); + core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast()))); + let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL); + core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast()))); } diff --git a/tests/ui/thread-local/long-docs.rs b/tests/ui/thread-local/long-docs.rs new file mode 100644 index 00000000000..0577d0b27c2 --- /dev/null +++ b/tests/ui/thread-local/long-docs.rs @@ -0,0 +1,266 @@ +//@ check-pass + +thread_local! { + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + pub static LONG_DOCS: () = (); + + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + /// I love doc comments. + #[allow(unused_mut, reason = "testing")] + pub static LONG_DOCS_2: () = (); +} + +fn main() {} diff --git a/tests/ui/thread-local/no-unstable.rs b/tests/ui/thread-local/no-unstable.rs new file mode 100644 index 00000000000..3de7985e62d --- /dev/null +++ b/tests/ui/thread-local/no-unstable.rs @@ -0,0 +1,17 @@ +thread_local! { + //~^ ERROR: use of an internal attribute [E0658] + //~| ERROR: use of an internal attribute [E0658] + //~| ERROR: `#[used(linker)]` is currently unstable [E0658] + //~| ERROR: `#[used]` attribute cannot be used on constants + + #[rustc_dummy = 17] + pub static FOO: () = (); + + #[cfg_attr(true, rustc_dummy = 17)] + pub static BAR: () = (); + + #[used(linker)] + pub static BAZ: () = (); +} + +fn main() {} diff --git a/tests/ui/thread-local/no-unstable.stderr b/tests/ui/thread-local/no-unstable.stderr new file mode 100644 index 00000000000..fbcd804d917 --- /dev/null +++ b/tests/ui/thread-local/no-unstable.stderr @@ -0,0 +1,57 @@ +error[E0658]: use of an internal attribute + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: use of an internal attribute + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: `#[used(linker)]` is currently unstable + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information + = help: add `#![feature(used_with_arg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `#[used]` attribute cannot be used on constants + --> $DIR/no-unstable.rs:1:1 + | +LL | / thread_local! { +... | +LL | | pub static BAZ: () = (); +LL | | } + | |_^ + | + = help: `#[used]` can only be applied to statics + = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr index 13bc0cd94f3..ef5f1786801 100644 --- a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr +++ b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr @@ -4,7 +4,7 @@ error[E0608]: cannot index into a value of type `()` LL | ()[f(&[1.0])]; | ^^^^^^^^^^^ | - = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) + = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc. error: aborting due to 1 previous error diff --git a/triagebot.toml b/triagebot.toml index a04f8d28072..79b5c2d1b72 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -61,10 +61,6 @@ required-issue-label = "regression-from-stable-to-beta" # if the above conditions matches, the PR will receive these labels add-labels = ["beta-nominated"] -[backport.t-compiler-stable-backport] -required-pr-labels = ["T-compiler"] -required-issue-label = "regression-from-stable-to-stable" -add-labels = ["stable-nominated"] # ------------------------------------------------------------------------------ # Ping groups |
