diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index ba4589bd81025..ddc2b88191bd0 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -144,7 +144,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): set link section. } - if attrs.flags.contains(CodegenFnAttrFlags::USED) { + if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { self.add_used_global(global.to_rvalue()); } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index d43c7c6065179..6707de933522b 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -522,6 +522,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { } if attrs.flags.contains(CodegenFnAttrFlags::USED) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + // The semantics of #[used] in Rust only require the symbol to make it into the // object file. It is explicitly allowed for the linker to strip the symbol if it // is dead. As such, use llvm.compiler.used instead of llvm.used. @@ -530,6 +533,12 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // in some versions of the gold linker. self.add_compiler_used_global(g); } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED)); + + self.add_used_global(g); + } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1266b540aaeb1..da997dd98792f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -21,6 +21,7 @@ use crate::value::Value; use cstr::cstr; use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; +use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -276,6 +277,12 @@ impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { ) -> String { format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) } + + /// Gets the `UniqueTypeId` for the type of a vtable. + fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId { + let interner_key = self.unique_id_interner.intern(vtable_type_name); + interner_key + } } /// A description of some recursive type. It can either be already finished (as @@ -351,14 +358,15 @@ impl<'ll, 'tcx> RecursiveTypeDescription<'ll, 'tcx> { // ... then create the member descriptions ... let member_descriptions = member_description_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, unfinished_type); // ... and attach them to the stub to complete it. set_members_of_composite_type( cx, - unfinished_type, member_holding_stub, member_descriptions, None, + type_params, ); MetadataCreationResult::new(metadata_stub, true) } @@ -983,7 +991,17 @@ fn foreign_type_metadata<'ll, 'tcx>( debug!("foreign_type_metadata: {:?}", t); let name = compute_debuginfo_type_name(cx.tcx, t, false); - create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) + let (size, align) = cx.size_and_align_of(t); + create_struct_stub( + cx, + size, + align, + &name, + unique_type_id, + NO_SCOPE_METADATA, + DIFlags::FlagZero, + None, + ) } fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { @@ -1299,14 +1317,17 @@ fn prepare_struct_metadata<'ll, 'tcx>( }; let containing_scope = get_namespace_for_item(cx, struct_def_id); + let (size, align) = cx.size_and_align_of(struct_type); let struct_metadata_stub = create_struct_stub( cx, - struct_type, + size, + align, &struct_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, + None, ); create_and_register_recursive_type_forward_declaration( @@ -1398,15 +1419,18 @@ fn prepare_tuple_metadata<'ll, 'tcx>( unique_type_id: UniqueTypeId, containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { + let (size, align) = cx.size_and_align_of(tuple_type); let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); let struct_stub = create_struct_stub( cx, - tuple_type, + size, + align, &tuple_name[..], unique_type_id, containing_scope, DIFlags::FlagZero, + None, ); create_and_register_recursive_type_forward_declaration( @@ -1581,13 +1605,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { describe_enum_variant(cx, self.layout, variant_info, self_metadata); let member_descriptions = member_description_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); vec![MemberDescription { name: variant_info.variant_name(), @@ -1648,13 +1673,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); MemberDescription { @@ -1777,13 +1803,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { ); let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); let (size, align) = @@ -1823,13 +1850,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); let niche_value = calculate_niche_value(i); @@ -1965,13 +1993,18 @@ fn describe_enum_variant<'ll, 'tcx>( .type_map .borrow_mut() .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name); + + let (size, align) = cx.size_and_align_of(layout.ty); + create_struct_stub( cx, - layout.ty, + size, + align, variant_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, + None, ) }); @@ -2308,22 +2341,27 @@ fn composite_type_metadata<'ll, 'tcx>( member_descriptions: Vec>, containing_scope: Option<&'ll DIScope>, ) -> &'ll DICompositeType { + let (size, align) = cx.size_and_align_of(composite_type); + // Create the (empty) struct metadata node ... let composite_type_metadata = create_struct_stub( cx, - composite_type, + size, + align, composite_type_name, composite_type_unique_id, containing_scope, DIFlags::FlagZero, + None, ); + // ... and immediately create and add the member descriptions. set_members_of_composite_type( cx, - composite_type, composite_type_metadata, member_descriptions, None, + compute_type_parameters(cx, composite_type), ); composite_type_metadata @@ -2331,10 +2369,10 @@ fn composite_type_metadata<'ll, 'tcx>( fn set_members_of_composite_type<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - composite_type: Ty<'tcx>, composite_type_metadata: &'ll DICompositeType, member_descriptions: Vec>, common_members: Option<&Vec>>, + type_params: &'ll DIArray, ) { // In some rare cases LLVM metadata uniquing would lead to an existing type // description being used instead of a new one created in @@ -2361,13 +2399,12 @@ fn set_members_of_composite_type<'ll, 'tcx>( member_metadata.extend(other_members.iter()); } - let type_params = compute_type_parameters(cx, composite_type); unsafe { - let type_array = create_DIArray(DIB(cx), &member_metadata); + let field_array = create_DIArray(DIB(cx), &member_metadata); llvm::LLVMRustDICompositeTypeReplaceArrays( DIB(cx), composite_type_metadata, - Some(type_array), + Some(field_array), Some(type_params), ); } @@ -2420,14 +2457,14 @@ fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) - /// with `set_members_of_composite_type()`. fn create_struct_stub<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - struct_type: Ty<'tcx>, - struct_type_name: &str, + size: Size, + align: Align, + type_name: &str, unique_type_id: UniqueTypeId, containing_scope: Option<&'ll DIScope>, flags: DIFlags, + vtable_holder: Option<&'ll DIType>, ) -> &'ll DICompositeType { - let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - let type_map = debug_context(cx).type_map.borrow(); let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); @@ -2440,17 +2477,17 @@ fn create_struct_stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - struct_type_name.as_ptr().cast(), - struct_type_name.len(), + type_name.as_ptr().cast(), + type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, - struct_size.bits(), - struct_align.bits() as u32, + size.bits(), + align.bits() as u32, flags, None, empty_array, 0, - None, + vtable_holder, unique_type_id.as_ptr().cast(), unique_type_id.len(), ) @@ -2556,6 +2593,14 @@ pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, g } /// Generates LLVM debuginfo for a vtable. +/// +/// The vtable type looks like a struct with a field for each function pointer and super-trait +/// pointer it contains (plus the `size` and `align` fields). +/// +/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror +/// the name of the method they implement. This can be implemented in the future once there +/// is a proper disambiguation scheme for dealing with methods from different traits that have +/// the same name. fn vtable_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, @@ -2572,16 +2617,81 @@ fn vtable_type_metadata<'ll, 'tcx>( COMMON_VTABLE_ENTRIES }; - // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is - // correct - but we could create a more accurate description, e.g. by describing it - // as a struct where each field has a name that corresponds to the name of the method - // it points to. - // However, this is not entirely straightforward because there might be multiple - // methods with the same name if the vtable is for multiple traits. So for now we keep - // things simple instead of adding some ad-hoc disambiguation scheme. - let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64); + // All function pointers are described as opaque pointers. This could be improved in the future + // by describing them as actual function pointers. + let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit); + let void_pointer_type_debuginfo = type_metadata(cx, void_pointer_ty); + let usize_debuginfo = type_metadata(cx, tcx.types.usize); + let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty); + // If `usize` is not pointer-sized and -aligned then the size and alignment computations + // for the vtable as a whole would be wrong. Let's make sure this holds even on weird + // platforms. + assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align)); + + let vtable_type_name = + compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type); + let unique_type_id = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_of_vtable_type(&vtable_type_name); + let size = pointer_size * vtable_entries.len() as u64; + + // This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate + // the vtable to the type it is for. + let vtable_holder = type_metadata(cx, ty); + + let vtable_type_metadata = create_struct_stub( + cx, + size, + pointer_align, + &vtable_type_name, + unique_type_id, + NO_SCOPE_METADATA, + DIFlags::FlagArtificial, + Some(vtable_holder), + ); + + // Create a field for each entry in the vtable. + let fields: Vec<_> = vtable_entries + .iter() + .enumerate() + .filter_map(|(index, vtable_entry)| { + let (field_name, field_type) = match vtable_entry { + ty::VtblEntry::MetadataDropInPlace => { + ("drop_in_place".to_string(), void_pointer_type_debuginfo) + } + ty::VtblEntry::Method(_) => { + // Note: This code does not try to give a proper name to each method + // because there might be multiple methods with the same name + // (coming from different traits). + (format!("__method{}", index), void_pointer_type_debuginfo) + } + ty::VtblEntry::TraitVPtr(_) => { + // Note: In the future we could try to set the type of this pointer + // to the type that we generate for the corresponding vtable. + (format!("__super_trait_ptr{}", index), void_pointer_type_debuginfo) + } + ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_debuginfo), + ty::VtblEntry::MetadataSize => ("size".to_string(), usize_debuginfo), + ty::VtblEntry::Vacant => return None, + }; + + Some(MemberDescription { + name: field_name, + type_metadata: field_type, + offset: pointer_size * index as u64, + size: pointer_size, + align: pointer_align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }) + }) + .collect(); - type_metadata(cx, vtable_type) + let type_params = create_DIArray(DIB(cx), &[]); + set_members_of_composite_type(cx, vtable_type_metadata, fields, None, type_params); + vtable_type_metadata } /// Creates debug information for the given vtable, which is for the @@ -2603,11 +2713,12 @@ pub fn create_vtable_metadata<'ll, 'tcx>( return; } - let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref); + let vtable_name = + compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref); + let linkage_name = ""; unsafe { - let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 831c34d8f1f60..3cb19c0eec624 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -469,7 +469,14 @@ fn push_debuginfo_type_name<'tcx>( } } -/// Computes a name for the global variable storing a vtable. +pub enum VTableNameKind { + // Is the name for the const/static holding the vtable? + GlobalVariable, + // Is the name for the type of the vtable? + Type, +} + +/// Computes a name for the global variable storing a vtable (or the type of that global variable). /// /// The name is of the form: /// @@ -478,10 +485,15 @@ fn push_debuginfo_type_name<'tcx>( /// or, when generating C++-like names: /// /// `impl$::vtable$` +/// +/// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just +/// `{vtable}`, so that the type and the corresponding global variable get assigned different +/// names. pub fn compute_debuginfo_vtable_name<'tcx>( tcx: TyCtxt<'tcx>, t: Ty<'tcx>, trait_ref: Option>, + kind: VTableNameKind, ) -> String { let cpp_like_debuginfo = cpp_like_debuginfo(tcx); @@ -514,7 +526,12 @@ pub fn compute_debuginfo_vtable_name<'tcx>( push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name); - let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" }; + let suffix = match (cpp_like_debuginfo, kind) { + (true, VTableNameKind::GlobalVariable) => "::vtable$", + (false, VTableNameKind::GlobalVariable) => "::{vtable}", + (true, VTableNameKind::Type) => "::vtable_type$", + (false, VTableNameKind::Type) => "::{vtable_type}", + }; vtable_name.reserve_exact(suffix.len()); vtable_name.push_str(suffix); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e5232bf3dd019..0248d3235dfe3 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -531,6 +531,8 @@ declare_features! ( /// /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0. (active, untagged_unions, "1.13.0", Some(55149), None), + /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. + (active, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` (active, wasm_abi, "1.53.0", Some(83788), None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index cb2562d09a525..599ac7f33104c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -324,7 +324,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(no_mangle, Normal, template!(Word), WarnFollowing), - ungated!(used, Normal, template!(Word), WarnFollowing), + ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing), // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), @@ -339,7 +339,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Entry point: - ungated!(main, Normal, template!(Word), WarnFollowing), ungated!(start, Normal, template!(Word), WarnFollowing), ungated!(no_start, CrateLevel, template!(Word), WarnFollowing), ungated!(no_main, CrateLevel, template!(Word), WarnFollowing), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index b054d21adaa13..54eb2dc9e2890 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -89,6 +89,8 @@ bitflags! { /// the MIR `InstrumentCoverage` pass and not added to the coverage map /// during codegen. const NO_COVERAGE = 1 << 15; + /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function. + const USED_LINKER = 1 << 16; } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 129efc2b52379..991d10a8547ff 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -43,7 +43,8 @@ mod add_retag; mod check_const_item_mutation; mod check_packed_ref; pub mod check_unsafety; -mod cleanup_post_borrowck; +// This pass is public to allow external drivers to perform MIR cleanup +pub mod cleanup_post_borrowck; mod const_debuginfo; mod const_goto; mod const_prop; @@ -65,7 +66,8 @@ mod match_branches; mod multiple_return_terminators; mod normalize_array_len; mod nrvo; -mod remove_false_edges; +// This pass is public to allow external drivers to perform MIR cleanup +pub mod remove_false_edges; mod remove_noop_landing_pads; mod remove_storage_markers; mod remove_uninit_drops; @@ -75,7 +77,8 @@ mod required_consts; mod reveal_all; mod separate_const_switch; mod shim; -mod simplify; +// This pass is public to allow external drivers to perform MIR cleanup +pub mod simplify; mod simplify_branches; mod simplify_comparison_integral; mod simplify_try; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ca511f7b814be..479a08e43c01a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1741,12 +1741,46 @@ impl CheckAttrVisitor<'_> { } fn check_used(&self, attrs: &[Attribute], target: Target) { + let mut used_linker_span = None; + let mut used_compiler_span = None; for attr in attrs { if attr.has_name(sym::used) && target != Target::Static { self.tcx .sess .span_err(attr.span, "attribute must be applied to a `static` variable"); } + let inner = attr.meta_item_list(); + match inner.as_deref() { + Some([item]) if item.has_name(sym::linker) => { + if used_linker_span.is_none() { + used_linker_span = Some(attr.span); + } + } + Some([item]) if item.has_name(sym::compiler) => { + if used_compiler_span.is_none() { + used_compiler_span = Some(attr.span); + } + } + Some(_) => { + // This error case is handled in rustc_typeck::collect. + } + None => { + // Default case (compiler) when arg isn't defined. + if used_compiler_span.is_none() { + used_compiler_span = Some(attr.span); + } + } + } + } + if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) { + let spans = vec![linker_span, compiler_span]; + self.tcx + .sess + .struct_span_err( + spans, + "`used(compiler)` and `used(linker)` can't be used together", + ) + .emit(); } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e7e56711b33c5..dc3ce1afa3361 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -466,7 +466,10 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // #[used], #[no_mangle], #[export_name], etc also keeps the item alive // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) { + if cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { return true; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 70fad4911f9c7..6a9c260f1c0ae 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -449,6 +449,7 @@ symbols! { compare_exchange_weak, compile_error, compile_error_macro, + compiler, compiler_builtins, compiler_fence, concat, @@ -668,6 +669,7 @@ symbols! { fill, finish, flags, + float, float_to_int_unchecked, floorf32, floorf64, @@ -771,6 +773,8 @@ symbols! { inline_const_pat, inout, instruction_set, + integer_: "integer", + integral, intel, into_future, into_iter, @@ -815,6 +819,7 @@ symbols! { link_ordinal, link_section, linkage, + linker, lint_reasons, literal, load, @@ -1463,6 +1468,7 @@ symbols! { use_extern_macros, use_nested_groups, used, + used_with_arg, usize, v1, va_arg, diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 6b20476b95594..bdf677a63b632 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -62,6 +62,10 @@ impl<'tcx> OnUnimplementedDirective { let mut errored = false; let mut item_iter = items.iter(); + let parse_value = |value_str| { + OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) + }; + let condition = if is_root { None } else { @@ -86,7 +90,14 @@ impl<'tcx> OnUnimplementedDirective { None, ) })?; - attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true); + attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| { + if let Some(symbol) = item.value_str() { + if parse_value(symbol).is_err() { + errored = true; + } + } + true + }); Some(cond.clone()) }; @@ -97,10 +108,6 @@ impl<'tcx> OnUnimplementedDirective { let mut subcommands = vec![]; let mut append_const_msg = None; - let parse_value = |value_str| { - OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) - }; - for item in item_iter { if item.has_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { @@ -221,6 +228,9 @@ impl<'tcx> OnUnimplementedDirective { let mut append_const_msg = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); + let options_map: FxHashMap = + options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); + for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { if !attr::eval_condition( @@ -229,7 +239,11 @@ impl<'tcx> OnUnimplementedDirective { Some(tcx.features()), &mut |c| { c.ident().map_or(false, |ident| { - options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) + let value = c.value_str().map(|s| { + OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map) + }); + + options.contains(&(ident.name, value)) }) }, ) { @@ -257,13 +271,11 @@ impl<'tcx> OnUnimplementedDirective { append_const_msg = command.append_const_msg.clone(); } - let options: FxHashMap = - options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); OnUnimplementedNote { - label: label.map(|l| l.format(tcx, trait_ref, &options)), - message: message.map(|m| m.format(tcx, trait_ref, &options)), - note: note.map(|n| n.format(tcx, trait_ref, &options)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), + label: label.map(|l| l.format(tcx, trait_ref, &options_map)), + message: message.map(|m| m.format(tcx, trait_ref, &options_map)), + note: note.map(|n| n.format(tcx, trait_ref, &options_map)), + enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), append_const_msg, } } @@ -306,6 +318,12 @@ impl<'tcx> OnUnimplementedFormatString { Position::ArgumentNamed(s) if s == sym::from_desugaring => (), // `{ItemContext}` is allowed Position::ArgumentNamed(s) if s == sym::ItemContext => (), + // `{integral}` and `{integer}` and `{float}` are allowed + Position::ArgumentNamed(s) + if s == sym::integral || s == sym::integer_ || s == sym::float => + { + () + } // So is `{A}` if A is a type parameter Position::ArgumentNamed(s) => { match generics.params.iter().find(|param| param.name == s) { @@ -385,6 +403,12 @@ impl<'tcx> OnUnimplementedFormatString { &empty_string } else if s == sym::ItemContext { &item_context + } else if s == sym::integral { + "{integral}" + } else if s == sym::integer_ { + "{integer}" + } else if s == sym::float { + "{float}" } else { bug!( "broken on_unimplemented {:?} for {:?}: \ diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 7c8a47d5d6524..7b9f1afe271c2 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -2856,7 +2857,42 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } else if attr.has_name(sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if attr.has_name(sym::used) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + let inner = attr.meta_item_list(); + match inner.as_deref() { + Some([item]) if item.has_name(sym::linker) => { + if !tcx.features().used_with_arg { + feature_err( + &tcx.sess.parse_sess, + sym::used_with_arg, + attr.span, + "`#[used(linker)]` is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER; + } + Some([item]) if item.has_name(sym::compiler) => { + if !tcx.features().used_with_arg { + feature_err( + &tcx.sess.parse_sess, + sym::used_with_arg, + attr.span, + "`#[used(compiler)]` is currently unstable", + ) + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + } + Some(_) => { + tcx.sess + .struct_span_err( + attr.span, + "expected `used`, `used(compiler)` or `used(linker)`", + ) + .emit(); + } + None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED, + } } else if attr.has_name(sym::cmse_nonsecure_entry) { if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) { struct_span_err!( diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index b4d16d74db488..aeb7554f8e914 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -74,7 +74,7 @@ //! identifier '=' expression //! ``` //! -//! For example, the following [`format!`] expressions all use named argument: +//! For example, the following [`format!`] expressions all use named arguments: //! //! ``` //! format!("{argument}", argument = "test"); // => "test" diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index fc14620a2df84..637d7bc44885e 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -81,6 +81,32 @@ /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( + on( + _Self = "[{A}]", + message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size", + label = "try explicitly collecting into a `Vec<{A}>`", + ), + on( + all( + A = "{integer}", + any( + _Self = "[i8]", + _Self = "[i16]", + _Self = "[i32]", + _Self = "[i64]", + _Self = "[i128]", + _Self = "[isize]", + _Self = "[u8]", + _Self = "[u16]", + _Self = "[u32]", + _Self = "[u64]", + _Self = "[u128]", + _Self = "[usize]" + ) + ), + message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size", + label = "try explicitly collecting into a `Vec<{A}>`", + ), message = "a value of type `{Self}` cannot be built from an iterator \ over elements of type `{A}`", label = "value of type `{Self}` cannot be built from `std::iter::Iterator`" diff --git a/src/test/codegen/debug-vtable.rs b/src/test/codegen/debug-vtable.rs index 35fd275fd2897..b9cb4f93d07d8 100644 --- a/src/test/codegen/debug-vtable.rs +++ b/src/test/codegen/debug-vtable.rs @@ -9,19 +9,41 @@ // compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0 // ignore-tidy-linelength +// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize" +// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize" +// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()" +// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >" + // NONMSVC: !DIGlobalVariable(name: "::{vtable}" // MSVC: !DIGlobalVariable(name: "impl$::vtable$" -// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()", -// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$ >", -// CHECK: !DISubrange(count: 5 + +// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], +// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}}) +// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", // NONMSVC: !DIGlobalVariable(name: ">::{vtable}" // MSVC: !DIGlobalVariable(name: "impl$ >::vtable$" -// CHECK: !DISubrange(count: 4 + +// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: ">::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$ >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}}) // NONMSVC: !DIGlobalVariable(name: "::{vtable}" // MSVC: !DIGlobalVariable(name: "impl$::vtable$" -// CHECK: !DISubrange(count: 3 + +// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]], +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}}) +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}}) // NONMSVC: !DIGlobalVariable(name: ">)>>::{vtable}" // MSVC: !DIGlobalVariable(name: "impl$,assoc$ > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$" @@ -34,6 +56,9 @@ #![crate_type = "lib"] +// Force emission for debuginfo for usize and *const() early.. +pub static mut XYZ: Option<(usize, *const ())> = None; + pub struct Foo; pub trait SomeTrait { diff --git a/src/test/codegen/debuginfo-generic-closure-env-names.rs b/src/test/codegen/debuginfo-generic-closure-env-names.rs index 6e5ac95126130..ad59f740b567f 100644 --- a/src/test/codegen/debuginfo-generic-closure-env-names.rs +++ b/src/test/codegen/debuginfo-generic-closure-env-names.rs @@ -17,35 +17,34 @@ // compile-flags: -Cdebuginfo=2 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0 - -// CHECK: [[non_generic_closure_NAMESPACE:!.*]] = !DINamespace(name: "non_generic_closure" -// CHECK: [[function_containing_closure_NAMESPACE:!.*]] = !DINamespace(name: "function_containing_closure" -// CHECK: [[generic_async_function_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_function" -// CHECK: [[generic_async_block_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_block" - // non_generic_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[non_generic_closure_NAMESPACE]] -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[non_generic_closure_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]], +// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure" + +// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure" +// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function" +// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block" // function_containing_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[function_containing_closure_NAMESPACE]] -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[function_containing_closure_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] // generic_async_function() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[generic_async_function_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] // generic_async_function() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[generic_async_function_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: ![[generic_async_function_NAMESPACE]] // generic_async_block() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: [[generic_async_block_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] // generic_async_block() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: [[generic_async_block_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}", scope: ![[generic_async_block_NAMESPACE]] // function_containing_closure() -// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[function_containing_closure_NAMESPACE]] -// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[function_containing_closure_NAMESPACE]] +// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[function_containing_closure_NAMESPACE]] +// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[function_containing_closure_NAMESPACE]] #![crate_type = "lib"] @@ -54,15 +53,14 @@ use std::future::Future; pub struct Foo; pub fn non_generic_closure(x: Foo) -> Box Foo> { - // This static only exists to trigger generating the namespace debuginfo for - // `function_containing_closure` at a predictable, early point, which makes - // writing the FileCheck tests above simpler. - static _X: u8 = 0; return Box::new(move || x); } fn function_containing_closure(x: T) -> impl FnOnce() -> T { - static _X: u8 = 0; // Same as above + // This static only exists to trigger generating the namespace debuginfo for + // `function_containing_closure` at a predictable, early point, which makes + // writing the FileCheck tests above simpler. + static _X: u8 = 0; return move || x; } diff --git a/src/test/codegen/used_with_arg.rs b/src/test/codegen/used_with_arg.rs new file mode 100644 index 0000000000000..5bff50a40d4e8 --- /dev/null +++ b/src/test/codegen/used_with_arg.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] +#![feature(used_with_arg)] + +// CHECK: @llvm.used = appending global [1 x i8*]{{.*}}USED_LINKER +#[used(linker)] +static mut USED_LINKER: [usize; 1] = [0]; + +// CHECK-NEXT: @llvm.compiler.used = appending global [1 x i8*]{{.*}}USED_COMPILER +#[used(compiler)] +static mut USED_COMPILER: [usize; 1] = [0]; diff --git a/src/test/ui/attributes/main-removed-1.rs b/src/test/ui/attributes/main-removed-1.rs new file mode 100644 index 0000000000000..0e887469d4466 --- /dev/null +++ b/src/test/ui/attributes/main-removed-1.rs @@ -0,0 +1,2 @@ +#[main] //~ ERROR cannot find attribute `main` in this scope +fn main() {} diff --git a/src/test/ui/attributes/main-removed-1.stderr b/src/test/ui/attributes/main-removed-1.stderr new file mode 100644 index 0000000000000..2422c5c3b6239 --- /dev/null +++ b/src/test/ui/attributes/main-removed-1.stderr @@ -0,0 +1,10 @@ +error: cannot find attribute `main` in this scope + --> $DIR/main-removed-1.rs:1:3 + | +LL | #[main] + | ^^^^ + | + = note: `main` is in scope, but it is a function, not an attribute + +error: aborting due to previous error + diff --git a/src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs b/src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs new file mode 100644 index 0000000000000..196b5be2dd086 --- /dev/null +++ b/src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn main(_: TokenStream, input: TokenStream) -> TokenStream { + "fn main() { println!(\"Hello Tokyo!\"); }".parse().unwrap() +} diff --git a/src/test/ui/attributes/main-removed-2/main.rs b/src/test/ui/attributes/main-removed-2/main.rs new file mode 100644 index 0000000000000..e8fecf825fa83 --- /dev/null +++ b/src/test/ui/attributes/main-removed-2/main.rs @@ -0,0 +1,11 @@ +// run-pass +// aux-build:tokyo.rs +// compile-flags:--extern tokyo +// edition:2021 + +use tokyo::main; + +#[main] +fn main() { + panic!("the #[main] macro should replace this with non-panicking code") +} diff --git a/src/test/ui/attributes/used_with_arg.rs b/src/test/ui/attributes/used_with_arg.rs new file mode 100644 index 0000000000000..ad80ff53f0ef0 --- /dev/null +++ b/src/test/ui/attributes/used_with_arg.rs @@ -0,0 +1,19 @@ +#![feature(used_with_arg)] + +#[used(linker)] +static mut USED_LINKER: [usize; 1] = [0]; + +#[used(compiler)] +static mut USED_COMPILER: [usize; 1] = [0]; + +#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together +#[used(linker)] +static mut USED_COMPILER_LINKER2: [usize; 1] = [0]; + +#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together +#[used(linker)] +#[used(compiler)] +#[used(linker)] +static mut USED_COMPILER_LINKER3: [usize; 1] = [0]; + +fn main() {} diff --git a/src/test/ui/attributes/used_with_arg.stderr b/src/test/ui/attributes/used_with_arg.stderr new file mode 100644 index 0000000000000..440e5c4a5a020 --- /dev/null +++ b/src/test/ui/attributes/used_with_arg.stderr @@ -0,0 +1,18 @@ +error: `used(compiler)` and `used(linker)` can't be used together + --> $DIR/used_with_arg.rs:9:1 + | +LL | #[used(compiler)] + | ^^^^^^^^^^^^^^^^^ +LL | #[used(linker)] + | ^^^^^^^^^^^^^^^ + +error: `used(compiler)` and `used(linker)` can't be used together + --> $DIR/used_with_arg.rs:13:1 + | +LL | #[used(compiler)] + | ^^^^^^^^^^^^^^^^^ +LL | #[used(linker)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/attributes/used_with_multi_args.rs b/src/test/ui/attributes/used_with_multi_args.rs new file mode 100644 index 0000000000000..2e17fcfd7a493 --- /dev/null +++ b/src/test/ui/attributes/used_with_multi_args.rs @@ -0,0 +1,6 @@ +#![feature(used_with_arg)] + +#[used(compiler, linker)] //~ expected `used`, `used(compiler)` or `used(linker)` +static mut USED_COMPILER_LINKER: [usize; 1] = [0]; + +fn main() {} diff --git a/src/test/ui/attributes/used_with_multi_args.stderr b/src/test/ui/attributes/used_with_multi_args.stderr new file mode 100644 index 0000000000000..c93aafcfc7cce --- /dev/null +++ b/src/test/ui/attributes/used_with_multi_args.stderr @@ -0,0 +1,8 @@ +error: expected `used`, `used(compiler)` or `used(linker)` + --> $DIR/used_with_multi_args.rs:3:1 + | +LL | #[used(compiler, linker)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gates/feature-gate-used_with_arg.rs b/src/test/ui/feature-gates/feature-gate-used_with_arg.rs new file mode 100644 index 0000000000000..1c8f01bdef116 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-used_with_arg.rs @@ -0,0 +1,7 @@ +#[used(linker)] //~ ERROR `#[used(linker)]` is currently unstable +static mut USED_LINKER: [usize; 1] = [0]; + +#[used(compiler)] //~ ERROR `#[used(compiler)]` is currently unstable +static mut USED_COMPILER: [usize; 1] = [0]; + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-used_with_arg.stderr b/src/test/ui/feature-gates/feature-gate-used_with_arg.stderr new file mode 100644 index 0000000000000..d115bf4e365a7 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-used_with_arg.stderr @@ -0,0 +1,21 @@ +error[E0658]: `#[used(linker)]` is currently unstable + --> $DIR/feature-gate-used_with_arg.rs:1:1 + | +LL | #[used(linker)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #93798 for more information + = help: add `#![feature(used_with_arg)]` to the crate attributes to enable + +error[E0658]: `#[used(compiler)]` is currently unstable + --> $DIR/feature-gate-used_with_arg.rs:4:1 + | +LL | #[used(compiler)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #93798 for more information + = help: add `#![feature(used_with_arg)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/iterators/collect-into-slice.rs b/src/test/ui/iterators/collect-into-slice.rs new file mode 100644 index 0000000000000..905752dec7478 --- /dev/null +++ b/src/test/ui/iterators/collect-into-slice.rs @@ -0,0 +1,15 @@ +fn process_slice(data: &[i32]) { + //~^ NOTE required by a bound in this + todo!() +} + +fn main() { + let some_generated_vec = (0..10).collect(); + //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time + //~| ERROR a value of type `[i32]` cannot be built since `[i32]` has no definite size + //~| NOTE try explicitly collecting into a `Vec<{integer}>` + //~| NOTE required by a bound in `collect` + //~| NOTE all local variables must have a statically known size + //~| NOTE doesn't have a size known at compile-time + process_slice(&some_generated_vec); +} diff --git a/src/test/ui/iterators/collect-into-slice.stderr b/src/test/ui/iterators/collect-into-slice.stderr new file mode 100644 index 0000000000000..521f239451d2f --- /dev/null +++ b/src/test/ui/iterators/collect-into-slice.stderr @@ -0,0 +1,26 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/collect-into-slice.rs:7:9 + | +LL | let some_generated_vec = (0..10).collect(); + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error[E0277]: a value of type `[i32]` cannot be built since `[i32]` has no definite size + --> $DIR/collect-into-slice.rs:7:38 + | +LL | let some_generated_vec = (0..10).collect(); + | ^^^^^^^ try explicitly collecting into a `Vec<{integer}>` + | + = help: the trait `FromIterator<{integer}>` is not implemented for `[i32]` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + | +LL | fn collect>(self) -> B + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.