diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1c14c645d474c..630c65ea0a450 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -230,7 +230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b5e28d21a2613..256da9d6c7d5b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -215,6 +215,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), + Some(i), &extra_hir_attributes, ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a27dc47bf27c3..a5896f495847d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1182,7 +1182,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target: Target, ) -> &'hir [hir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[]) } fn lower_attrs_with_extra( @@ -1191,13 +1191,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + target_item: Option<&ast::Item>, extra_hir_attributes: &[hir::Attribute], ) -> &'hir [hir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { let mut lowered_attrs = - self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target); + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, target_item); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id); @@ -1224,12 +1225,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, + target_item: Option<&ast::Item>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, + target_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2685,7 +2688,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match (body, kind) { (body, ConstItemKind::Body) => { let is_direct = |body| { - if self.tcx.features().macroless_generic_const_args() { + if self.tcx.features().macroless_const_item_generic_const_args() { self.can_lower_expr_to_const_arg_direct( body, DirectConstArgContext::MacrolessMinGenericConstArgs, diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 6cce64d700a63..7aeedc1493027 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -705,16 +705,7 @@ impl DocParser { fn accept_single_doc_attr(&mut self, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) { match args { - ArgParser::NoArgs => { - let suggestions = cx.adcx().suggestions(); - let span = cx.inner_span; - cx.emit_lint( - INVALID_DOC_ATTRIBUTES, - IllFormedAttributeInput::new(&suggestions, None, None), - span, - ); - } - ArgParser::List(items) => { + ArgParser::List(items) if !items.is_empty() => { for i in items.mixed() { match i { MetaItemOrLitParser::MetaItemParser(mip) => { @@ -739,6 +730,15 @@ impl DocParser { ); } } + _ => { + let suggestions = cx.adcx().suggestions(); + let span = cx.inner_span; + cx.emit_lint( + INVALID_DOC_ATTRIBUTES, + IllFormedAttributeInput::new(&suggestions, None, None), + span, + ); + } } } } @@ -749,7 +749,6 @@ impl AttributeParser for DocParser { template!( List: &[ "alias", - "attribute", "hidden", "html_favicon_url", "html_logo_url", @@ -762,19 +761,10 @@ impl AttributeParser for DocParser { "masked", "cfg", "notable_trait", - "keyword", - "fake_variadic", - "search_unbox", - "rust_logo", "auto_cfg", "test", - "spotlight", - "include", - "no_default_passes", - "passes", - "plugins", ], - NameValueStr: "string" + NameValueStr: "doc comment" ), AttributeStability::Stable, // Some parts of the attribute are unstable, manually checked in parser |this, cx, args| { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 48e97784a2286..30fdadf95e4ce 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,11 +1,8 @@ -use rustc_attr_ir::AttributeKind; -use rustc_attr_ir::target::Target; +use rustc_ast::{ItemKind, VariantData}; use rustc_feature::AttributeStability; -use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::target_checking::AllowedTargets; -use crate::target_checking::Policy::{Allow, Warn}; +use super::prelude::*; +use crate::diagnostics::NonExhaustiveWithDefaultFieldValues; pub(crate) struct NonExhaustiveParser; @@ -23,4 +20,23 @@ impl NoArgsAttributeParser for NonExhaustiveParser { ]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; + + fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + if cx.target != Target::Struct { + return; + } + + let item = cx.target_item.expect("missing AST target item for Target::Struct"); + let ItemKind::Struct(_, _, data) = &item.kind else { + panic!("expected struct AST target item for Target::Struct"); + }; + if let VariantData::Struct { fields, .. } = data + && fields.iter().any(|f| f.default_value().is_some()) + { + cx.emit_err(NonExhaustiveWithDefaultFieldValues { + attr_span, + defn_span: cx.target_span, + }); + } + } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cf99311cc0cfc..8d03c441acf16 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -833,6 +833,10 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// /// Unlike [`all_attrs`](Self::all_attrs), this contains the fully parsed attributes. pub(crate) parsed_attrs: &'p [Attribute], + + /// The AST item these attributes were applied to, when the target is an item. + /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. + pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 663915e39dccd..aeaada0e61409 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1169,6 +1169,15 @@ pub(crate) struct DeprecatedAnnotationHasNoEffect { pub span: Span, } +#[derive(Diagnostic)] +#[diag("`#[non_exhaustive]` can't be used to annotate items with default field values")] +pub(crate) struct NonExhaustiveWithDefaultFieldValues { + #[primary_span] + pub attr_span: Span, + #[label("this struct has default field values")] + pub defn_span: Span, +} + #[derive(Diagnostic)] #[diag("expected single version literal")] pub(crate) struct ExpectedSingleVersionLiteral { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 240f437828259..1cecce8fd43ef 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -161,6 +161,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, + None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -315,6 +316,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, + target_item: Option<&ast::Item>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -521,6 +523,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, + target_item, }, attr_span, ); diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs deleted file mode 100644 index 48fdb4dd39ce2..0000000000000 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ /dev/null @@ -1,56 +0,0 @@ -use rustc_ast::{MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::Span; - -use crate::deriving::generic::*; -use crate::deriving::path_std; - -pub(crate) fn expand_deriving_copy( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::Copy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: SmallVec::new(), - supports_unions: true, - methods: SmallVec::new(), - associated_types: SmallVec::new(), - is_const, - safety: Safety::Default, - document: true, - }; - - trait_def.expand(cx, mitem, item, push); -} - -pub(crate) fn expand_deriving_const_param_ty( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::ConstParamTy_), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::Eq))], - supports_unions: false, - methods: SmallVec::new(), - associated_types: SmallVec::new(), - is_const, - safety: Safety::Default, - document: true, - }; - - trait_def.expand(cx, mitem, item, push); -} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index b4374e32f6051..f072b4b9e5cd1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,6 +1,6 @@ use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData}; use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -12,8 +12,8 @@ pub(crate) fn expand_deriving_clone( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { // The simple form is `fn clone(&self) -> Self { *self }`, possibly with @@ -32,35 +32,30 @@ pub(crate) fn expand_deriving_clone( let bounds; let substructure; let is_simple; - match item { - Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, Generics { params, .. }, _) - | ItemKind::Enum(_, Generics { params, .. }, _) => { - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let has_derive_copy = cx.resolver.has_derive_copy(container_id); - bounds = smallvec![]; - if has_derive_copy - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - { - is_simple = true; - substructure = - combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, false)); - } else { - is_simple = false; - substructure = combine_substructure(cs_clone); - } - } - ItemKind::Union(..) => { - bounds = smallvec![Path(path_std!(marker::Copy))]; + match &item.kind { + ItemKind::Struct(_, Generics { params, .. }, _) + | ItemKind::Enum(_, Generics { params, .. }, _) => { + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); + let has_derive_copy = cx.resolver.has_derive_copy(container_id); + bounds = smallvec![]; + if has_derive_copy + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + { is_simple = true; - substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); + substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, false)); + } else { + is_simple = false; + substructure = combine_substructure(cs_clone); } - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), - }, - - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), + } + ItemKind::Union(..) => { + bounds = smallvec![Path(path_std!(marker::Copy))]; + is_simple = true; + substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); + } + _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), } // If the clone method is just copying the value, also mark the type as @@ -82,7 +77,7 @@ pub(crate) fn expand_deriving_clone( document: false, }; - trivial_def.expand_ext(cx, mitem, item, push, true); + trivial_def.expand(cx, mitem, item, push); } let trait_def = TraitDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 80296a43ee490..58b4734b132c3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -1,13 +1,13 @@ use ast::HasAttrs; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::visit::BoundKind; +use rustc_ast::visit::{BoundKind, Visitor}; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::E0802; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -22,15 +22,13 @@ pub(crate) fn expand_deriving_coerce_pointee( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), _is_const: bool, ) { - item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); + DetectNonGenericPointeeAttr { cx }.visit_item(item); - let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(ident, g, struct_data) = &aitem.kind - { + let (name_ident, generics) = if let ItemKind::Struct(ident, g, struct_data) = &item.kind { if !matches!( struct_data, VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) @@ -104,7 +102,7 @@ pub(crate) fn expand_deriving_coerce_pointee( let trait_path = cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); let trait_ref = cx.trait_ref(trait_path); - push(Annotatable::Item( + push( cx.item( span, attrs.clone(), @@ -144,7 +142,7 @@ pub(crate) fn expand_deriving_coerce_pointee( items: ThinVec::new(), }), ), - )); + ); } let mut add_impl_block = |generics, trait_symbol, trait_args| { let mut parts = path!(span, core::ops); @@ -167,7 +165,7 @@ pub(crate) fn expand_deriving_coerce_pointee( items: ThinVec::new(), }), ); - push(Annotatable::Item(item)); + push(item); }; // Create unsized `self`, that is, one where the `#[pointee]` type arg is replaced with `__S`. For diff --git a/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs new file mode 100644 index 0000000000000..18a9df86b547e --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs @@ -0,0 +1,31 @@ +use rustc_ast::{MetaItem, Safety}; +use rustc_expand::base::ExtCtxt; +use rustc_span::Span; + +use crate::deriving::generic::*; +use crate::deriving::path_std; + +pub(crate) fn expand_deriving_const_param_ty( + cx: &ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &ast::Item, + push: &mut dyn FnMut(Box), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::ConstParamTy_), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: smallvec![ty::Ty::Path(path_std!(cmp::Eq))], + supports_unions: false, + methods: SmallVec::new(), + associated_types: SmallVec::new(), + is_const, + safety: Safety::Default, + document: true, + }; + + trait_def.expand(cx, mitem, item, push); +} diff --git a/compiler/rustc_builtin_macros/src/deriving/copy.rs b/compiler/rustc_builtin_macros/src/deriving/copy.rs new file mode 100644 index 0000000000000..5743d27cf7458 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/copy.rs @@ -0,0 +1,31 @@ +use rustc_ast::{MetaItem, Safety}; +use rustc_expand::base::ExtCtxt; +use rustc_span::Span; + +use crate::deriving::generic::*; +use crate::deriving::path_std; + +pub(crate) fn expand_deriving_copy( + cx: &ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &ast::Item, + push: &mut dyn FnMut(Box), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::Copy), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: SmallVec::new(), + supports_unions: true, + methods: SmallVec::new(), + associated_types: SmallVec::new(), + is_const, + safety: Safety::Default, + document: true, + }; + + trait_def.expand(cx, mitem, item, push); +} diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 94e0b704e6c08..3c80c01aa32b0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,5 +1,5 @@ use rustc_ast::{self as ast, EnumDef, MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_session::config::FmtDebug; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -12,8 +12,8 @@ pub(crate) fn expand_deriving_debug( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { // &mut ::std::fmt::Formatter diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 3e4c5f1dcfa53..9e65ae0b75cab 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,8 +1,8 @@ use core::ops::ControlFlow; -use rustc_ast::visit::visit_opt; +use rustc_ast::visit::{Visitor, visit_opt}; use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr}; -use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_expand::base::{DummyResult, ExtCtxt}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use smallvec::SmallVec; use thin_vec::{ThinVec, thin_vec}; @@ -15,11 +15,11 @@ pub(crate) fn expand_deriving_default( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { - item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); + DetectNonVariantDefaultAttr { cx }.visit_item(item); let trait_def = TraitDef { span, @@ -38,11 +38,11 @@ pub(crate) fn expand_deriving_default( fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(|cx, trait_span, substr| { match substr.fields { - StaticStruct(_, fields) => { - default_struct_substructure(cx, trait_span, substr, fields) + StaticStruct(variant_data) => { + default_struct_substructure(cx, trait_span, substr, variant_data) } StaticEnum(enum_def) => { - default_enum_substructure(cx, trait_span, enum_def, item.span()) + default_enum_substructure(cx, trait_span, enum_def, item.span) } _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), } @@ -66,27 +66,35 @@ fn default_struct_substructure( cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, - summary: &StaticFields<'_>, + variant_data: &VariantData, ) -> BlockOrExpr { - let expr = match summary { - Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), - Unnamed(fields, IsTuple::Yes) => { - let exprs = fields.iter().map(|sp| default_call(cx, *sp)).collect(); + let expr = match variant_data { + VariantData::Unit(_) => cx.expr_ident(trait_span, substr.type_ident), + VariantData::Tuple(fields, _) => { + let exprs = fields + .iter() + .map(|field| default_call(cx, field.span.with_ctxt(trait_span.ctxt()))) + .collect(); cx.expr_call_ident(trait_span, substr.type_ident, exprs) } - Named(fields) => { + VariantData::Struct { fields, .. } => { let default_fields = fields .iter() - .map(|&(ident, span, default_val)| { - let value = match default_val { - // We use `Default::default()`. - None => default_call(cx, span), + .map(|field| { + let span = field.span.with_ctxt(trait_span.ctxt()); + let value = if let Some(extras) = &field.extras + && let Some(default_val) = &extras.default + { // We use the field default const expression. - Some(val) => { - cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone())) - } + cx.expr( + default_val.value.span, + ast::ExprKind::ConstBlock(default_val.clone()), + ) + } else { + // We use `Default::default()`. + default_call(cx, span) }; - cx.field_imm(span, ident, value) + cx.field_imm(span, field.ident.unwrap(), value) }) .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) @@ -308,7 +316,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' } } -fn has_a_default_variant(item: &Annotatable) -> bool { +fn has_a_default_variant(item: &ast::Item) -> bool { struct HasDefaultAttrOnVariant; impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { @@ -323,5 +331,5 @@ fn has_a_default_variant(item: &Annotatable) -> bool { } } - item.visit_with(&mut HasDefaultAttrOnVariant).is_break() + HasDefaultAttrOnVariant.visit_item(item).is_break() } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/eq.rs similarity index 96% rename from compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs rename to compiler/rustc_builtin_macros/src/deriving/eq.rs index 440360ca85d7d..8c160cb9868bf 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/eq.rs @@ -1,6 +1,6 @@ use rustc_ast::{self as ast, MetaItem, Safety}; use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -12,8 +12,8 @@ pub(crate) fn expand_deriving_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { let span = cx.with_def_site_ctxt(span); diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 9824ab5a225b7..eb8ddd10d4306 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::{ItemKind, Safety, VariantData}; use rustc_errors::MultiSpan; -use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_expand::base::{DummyResult, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; use thin_vec::thin_vec; @@ -16,14 +16,10 @@ pub(crate) fn expand_deriving_from( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, - annotatable: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { - let Annotatable::Item(item) = &annotatable else { - cx.dcx().bug("derive(From) used on something else than an item"); - }; - let err_span = || { let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span); MultiSpan::from_spans(vec![span, item_span]) @@ -79,7 +75,7 @@ pub(crate) fn expand_deriving_from( supports_unions: false, methods: smallvec![MethodDef { name: sym::from, - generics: Bounds { bounds: vec![] }, + generics: Bounds::empty(), explicit_self: false, nonself_args: smallvec![(from_type, sym::value)], ret_ty: Ty::Self_, @@ -95,7 +91,7 @@ pub(crate) fn expand_deriving_from( let self_kw = Ident::new(kw::SelfUpper, span); let expr: Box = match substructure.fields { - SubstructureFields::StaticStruct(variant, _) => match variant { + SubstructureFields::StaticStruct(variant) => match variant { // Self { field: value } VariantData::Struct { .. } => cx.expr_struct_ident( span, @@ -127,5 +123,5 @@ pub(crate) fn expand_deriving_from( document: true, }; - from_trait_def.expand(cx, mitem, annotatable, push); + from_trait_def.expand(cx, mitem, item, push); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6a53dafd396df..3298b4a583ff8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -177,17 +177,17 @@ use std::ops::Not; use std::{iter, vec}; -pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; +pub(crate) use rustc_ast as ast; use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, - GenericParamKind, Generics, Mutability, PatKind, Safety, SelfKind, VariantData, + AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, Safety, SelfKind, VariantData, }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan, sym}; pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; @@ -293,20 +293,6 @@ pub(crate) struct FieldInfo { pub maybe_scalar: bool, } -#[derive(Copy, Clone)] -pub(crate) enum IsTuple { - No, - Yes, -} - -/// Fields for a static method -pub(crate) enum StaticFields<'a> { - /// Tuple and unit structs/enum variants like this. - Unnamed(Vec, IsTuple), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span, Option<&'a AnonConst>)>), -} - /// A summary of the possible sets of fields. pub(crate) enum SubstructureFields<'a> { /// A non-static method where `Self` is a struct. @@ -328,7 +314,7 @@ pub(crate) enum SubstructureFields<'a> { EnumDiscr(FieldInfo, Option>), /// A static method where `Self` is a struct. - StaticStruct(&'a ast::VariantData, StaticFields<'a>), + StaticStruct(&'a ast::VariantData), /// A static method where `Self` is an enum. StaticEnum(&'a ast::EnumDef), @@ -473,8 +459,8 @@ impl<'a> TraitDef<'a> { self, cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &'a ast::Item, + push: &mut dyn FnMut(Box), ) { self.expand_ext(cx, mitem, item, push, false); } @@ -483,72 +469,62 @@ impl<'a> TraitDef<'a> { self, cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, - item: &'a Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &'a ast::Item, + push: &mut dyn FnMut(Box), from_scratch: bool, ) { - match item { - Annotatable::Item(item) => { - let is_packed = matches!( - AttributeParser::parse_limited_sym(cx.sess, &item.attrs, &[sym::repr]), - Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) - ); + let is_packed = matches!( + AttributeParser::parse_limited_sym(cx.sess, &item.attrs, &[sym::repr]), + Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) + ); - let mut newitem = match &item.kind { - ast::ItemKind::Struct(ident, generics, struct_def) => self.expand_struct_def( + let mut newitem = match &item.kind { + ast::ItemKind::Struct(ident, generics, struct_def) => { + self.expand_struct_def(cx, struct_def, *ident, generics, from_scratch, is_packed) + } + ast::ItemKind::Enum(ident, generics, enum_def) => { + // We ignore `is_packed` here, because `repr(packed)` + // enums cause an error later on. + // + // This can only cause further compilation errors + // downstream in blatantly illegal code, so it is fine. + self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) + } + ast::ItemKind::Union(ident, generics, struct_def) => { + if self.supports_unions { + self.expand_struct_def( cx, struct_def, *ident, generics, from_scratch, is_packed, - ), - ast::ItemKind::Enum(ident, generics, enum_def) => { - // We ignore `is_packed` here, because `repr(packed)` - // enums cause an error later on. - // - // This can only cause further compilation errors - // downstream in blatantly illegal code, so it is fine. - self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) - } - ast::ItemKind::Union(ident, generics, struct_def) => { - if self.supports_unions { - self.expand_struct_def( - cx, - struct_def, - *ident, - generics, - from_scratch, - is_packed, - ) - } else { - cx.dcx().emit_err(diagnostics::DeriveUnion { span: mitem.span }); - return; - } - } - _ => unreachable!(), - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - newitem.attrs.extend( - item.attrs - .iter() - .filter(|a| { - a.has_any_name(&[ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::stable, - sym::unstable, - ]) - }) - .cloned(), - ); - push(Annotatable::Item(newitem)) + ) + } else { + cx.dcx().emit_err(diagnostics::DeriveUnion { span: mitem.span }); + return; + } } _ => unreachable!(), - } + }; + // Keep the lint attributes of the previous item to control how the + // generated implementations are linted + newitem.attrs.extend( + item.attrs + .iter() + .filter(|a| { + a.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::stable, + sym::unstable, + ]) + }) + .cloned(), + ); + push(newitem); } /// Given that we are deriving a trait `DerivedTrait` for a type like: @@ -869,12 +845,12 @@ impl<'a> TraitDef<'a> { method_def.extract_arg_details(cx, self, type_ident, generics); let body = if from_scratch || method_def.is_static() { - method_def.expand_static_struct_method_body( + method_def.call_substructure_method( cx, self, - struct_def, type_ident, &nonselflike_args, + &StaticStruct(struct_def), ) } else { method_def.expand_struct_method_body( @@ -1142,25 +1118,6 @@ impl<'a> MethodDef<'a> { ) } - fn expand_static_struct_method_body( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'a>, - struct_def: &'a VariantData, - type_ident: Ident, - nonselflike_args: &[Box], - ) -> BlockOrExpr { - let summary = trait_.summarise_struct(cx, struct_def); - - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &StaticStruct(struct_def, summary), - ) - } - /// ``` /// #[derive(PartialEq)] /// # struct Dummy; @@ -1459,34 +1416,6 @@ impl<'a> MethodDef<'a> { // general helper methods. impl<'a> TraitDef<'a> { - fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &'a VariantData) -> StaticFields<'a> { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields() { - let sp = field.span.with_ctxt(self.span.ctxt()); - match field.ident { - Some(ident) => named_idents.push((ident, sp, field.default_value())), - _ => just_spans.push(sp), - } - } - - let is_tuple = match struct_def { - ast::VariantData::Tuple(..) => IsTuple::Yes, - _ => IsTuple::No, - }; - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx - .dcx() - .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"), - // named fields - (_, false) => Named(named_idents), - // unnamed fields - (false, _) => Unnamed(just_spans, is_tuple), - // empty - _ => Named(Vec::new()), - } - } - fn create_struct_patterns( &self, cx: &ExtCtxt<'_>, diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f1931aa90a435..6864b05ae08cd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,5 +1,5 @@ use rustc_ast::{MetaItem, Mutability, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -11,8 +11,8 @@ pub(crate) fn expand_deriving_hash( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { let path = path_std!(hash::Hash); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 602af919bd4f2..404991903c424 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -14,28 +14,24 @@ macro path_std($($x:tt)*) { generic::ty::Path::new( pathvec!( $($x)* ) ) } -pub(crate) mod bounds; pub(crate) mod clone; pub(crate) mod coerce_pointee; +pub(crate) mod const_param_ty; +pub(crate) mod copy; pub(crate) mod debug; pub(crate) mod default; +pub(crate) mod eq; pub(crate) mod from; pub(crate) mod hash; -pub(crate) mod reborrow; - -#[path = "cmp/eq.rs"] -pub(crate) mod eq; -#[path = "cmp/ord.rs"] pub(crate) mod ord; -#[path = "cmp/partial_eq.rs"] pub(crate) mod partial_eq; -#[path = "cmp/partial_ord.rs"] pub(crate) mod partial_ord; +pub(crate) mod reborrow; pub(crate) mod generic; pub(crate) type BuiltinDeriveFn = - fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); + fn(&ExtCtxt<'_>, Span, &MetaItem, &ast::Item, &mut dyn FnMut(Box), bool); pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); @@ -59,25 +55,23 @@ impl MultiItemModifier for BuiltinDerive { ecx, span, meta_item, - &Annotatable::Item(item), - &mut |a| { - // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' - // to the function - items.push(Annotatable::Stmt(Box::new(ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(a.expect_item()), - span, - }))); - }, + &item, + &mut |a| items.push(Annotatable::Stmt(Box::new(ecx.stmt_item(span, a)))), is_derive_const, ); } else { unreachable!("should have already errored on non-item statement") } } - _ => { - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const); - } + Annotatable::Item(item) => (self.0)( + ecx, + span, + meta_item, + &item, + &mut |a| items.push(Annotatable::Item(a)), + is_derive_const, + ), + _ => unreachable!(), } ExpandResult::Ready(items) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/ord.rs similarity index 96% rename from compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs rename to compiler/rustc_builtin_macros/src/deriving/ord.rs index a1b38ceadb228..fb8d425841722 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/ord.rs @@ -1,5 +1,5 @@ use rustc_ast::{MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -11,8 +11,8 @@ pub(crate) fn expand_deriving_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { let trait_def = TraitDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs similarity index 95% rename from compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs rename to compiler/rustc_builtin_macros/src/deriving/partial_eq.rs index b852e29b03ca4..a65962bfc9731 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs @@ -1,5 +1,5 @@ use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -13,8 +13,8 @@ pub(crate) fn expand_deriving_partial_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { let structural_trait_def = TraitDef { @@ -47,9 +47,7 @@ pub(crate) fn expand_deriving_partial_eq( ret_ty: Path(generic::ty::Path::new_local(sym::bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(|a, b, c| { - BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) - }), + combine_substructure: combine_substructure(get_substructure_equality_expr), }]; let trait_def = TraitDef { @@ -123,10 +121,10 @@ fn get_substructure_equality_expr( cx: &ExtCtxt<'_>, span: Span, substructure: &Substructure<'_>, -) -> Box { +) -> BlockOrExpr { use SubstructureFields::*; - match substructure.fields { + BlockOrExpr::new_expr(match substructure.fields { EnumMatching(.., fields) | Struct(.., fields) => { let combine = move |acc, field| { let rhs = get_field_equality_expr(cx, field); @@ -151,7 +149,7 @@ fn get_substructure_equality_expr( EnumDiscr(disc, match_expr) => { let lhs = get_field_equality_expr(cx, disc); let Some(match_expr) = match_expr else { - return lhs; + return BlockOrExpr::new_expr(lhs); }; // Compare the discriminant first (cheaper), then the rest of the // fields. @@ -169,7 +167,7 @@ fn get_substructure_equality_expr( span, "unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion", ), - } + }) } /// Generates an equality comparison expression for a single struct or enum diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs similarity index 84% rename from compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs rename to compiler/rustc_builtin_macros/src/deriving/partial_ord.rs index 88141224fddc2..0e547d441a74b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs @@ -1,5 +1,5 @@ use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety, ast}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -11,8 +11,8 @@ pub(crate) fn expand_deriving_partial_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), is_const: bool, ) { let ordering_ty = Path(path_std!(cmp::Ordering)); @@ -20,9 +20,7 @@ pub(crate) fn expand_deriving_partial_ord( Path(Path::new_(pathvec!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching - let discr_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(_, _, def) = &item.kind - { + let discr_then_data = if let ItemKind::Enum(_, _, def) = &item.kind { let dataful: Vec = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { // No data, placing the discriminant check first makes codegen simpler @@ -49,29 +47,26 @@ pub(crate) fn expand_deriving_partial_ord( let simple_substructure = combine_substructure(|cx, span, _| { cs_partial_cmp_simple(cx, span, cx.expr_ident(span, Ident::new(sym::other, span))) }); - let is_simple = match item { - Annotatable::Item(annitem) => match &annitem.kind { - // For unit structs/zero-variant enums, the default generated code is better. - ItemKind::Struct(.., ast::VariantData::Unit(..)) => false, - // Also for single fieldless variant enum - ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => false, - ItemKind::Enum(.., enum_def) - if enum_def.variants.len() == 1 - && matches!(enum_def.variants[0].data, ast::VariantData::Unit(..)) => - { - false - } - ItemKind::Struct(_, ast::Generics { params, .. }, _) - | ItemKind::Enum(_, ast::Generics { params, .. }, _) - if has_derive_ord - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) => - { - true - } - _ => false, - }, + let is_simple = match &item.kind { + // For unit structs/zero-variant enums, the default generated code is better. + ItemKind::Struct(.., ast::VariantData::Unit(..)) => false, + // Also for single fieldless variant enum + ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => false, + ItemKind::Enum(.., enum_def) + if enum_def.variants.len() == 1 + && matches!(enum_def.variants[0].data, ast::VariantData::Unit(..)) => + { + false + } + ItemKind::Struct(_, ast::Generics { params, .. }, _) + | ItemKind::Enum(_, ast::Generics { params, .. }, _) + if has_derive_ord + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) => + { + true + } _ => false, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs index 9dc1ccf4fd8e6..43d24417acc00 100644 --- a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -2,7 +2,7 @@ use rustc_ast::{ self as ast, AttrArgs, GenericArg, GenericParamKind, Generics, ItemKind, MetaItem, token, }; use rustc_errors::E0802; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::ThinVec; @@ -15,8 +15,8 @@ pub(crate) fn expand_deriving_reborrow( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), _is_const: bool, ) { let Some((ident, generics)) = struct_def(cx, span, item, sym::Reborrow) else { @@ -30,8 +30,8 @@ pub(crate) fn expand_deriving_coerce_shared( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), + item: &ast::Item, + push: &mut dyn FnMut(Box), _is_const: bool, ) { let Some((ident, generics)) = struct_def(cx, span, item, sym::CoerceShared) else { @@ -55,25 +55,19 @@ pub(crate) fn expand_deriving_coerce_shared( fn struct_def<'a>( cx: &ExtCtxt<'_>, span: Span, - item: &'a Annotatable, + item: &'a ast::Item, trait_name: Symbol, ) -> Option<(Ident, &'a Generics)> { - match item { - Annotatable::Item(item) => match &item.kind { - ItemKind::Struct(ident, generics, _) => Some((*ident, generics)), - ItemKind::Enum(..) => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" }); - None - } - ItemKind::Union(..) => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" }); - None - } - _ => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); - None - } - }, + match &item.kind { + ItemKind::Struct(ident, generics, _) => Some((*ident, generics)), + ItemKind::Enum(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" }); + None + } + ItemKind::Union(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" }); + None + } _ => { cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); None @@ -81,12 +75,7 @@ fn struct_def<'a>( } } -fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &Annotatable) -> Option> { - let Annotatable::Item(item) = item else { - cx.dcx().emit_err(MissingTarget { span }); - return None; - }; - +fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &ast::Item) -> Option> { let mut attrs = item.attrs.iter().filter(|attr| attr.has_name(sym::coerce_shared)); let Some(attr) = attrs.next() else { cx.dcx().emit_err(MissingTarget { span }); @@ -130,7 +119,7 @@ fn push_marker_impl( generics: &Generics, trait_name: Symbol, trait_args: Vec, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), ) { let mut trait_parts = path!(span, core::marker); trait_parts.push(Ident::new(trait_name, span)); @@ -154,7 +143,7 @@ fn push_marker_impl( .collect(); let self_ty = cx.ty_path(cx.path_all(span, false, vec![ident], self_params)); - push(Annotatable::Item(cx.item( + push(cx.item( span, thin_vec::thin_vec![cx.attr_word(sym::automatically_derived, span)], ast::ItemKind::Impl(ast::Impl { @@ -169,7 +158,7 @@ fn push_marker_impl( self_ty, items: ThinVec::new(), }), - ))); + )); } fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index db92413e1b162..57759bb113401 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -133,8 +133,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_derive! { Clone: clone::expand_deriving_clone, CoerceShared: reborrow::expand_deriving_coerce_shared, - Copy: bounds::expand_deriving_copy, - ConstParamTy: bounds::expand_deriving_const_param_ty, + Copy: copy::expand_deriving_copy, + ConstParamTy: const_param_ty::expand_deriving_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 88049d67964b1..83f2bcdd3959c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -18,7 +18,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, - LayoutTypeCodegenMethods, OverflowOp, StaticBuilderMethods, + LayoutTypeCodegenMethods, OverflowOp, ReturnSlot, StaticBuilderMethods, }; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -608,6 +608,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, @@ -618,7 +619,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let current_block = self.block; self.block = try_block; - let call = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); // FIXME(antoyo): use funclet here? + // FIXME(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, fn_abi, func, return_slot, args, None, instance); self.block = current_block; let return_value = @@ -646,13 +648,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>, instance: Option>, ) -> RValue<'gcc> { - let call_site = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); + let call_site = self.call(typ, fn_attrs, fn_abi, func, return_slot, args, None, instance); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { @@ -1779,19 +1782,30 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], funclet: Option<&Funclet>, _instance: Option>, ) -> RValue<'gcc> { + // FIXME: change this in the `rustc_codegen_gcc` repo after the sync, to use the `libgccjit` indirect return suppport. + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { + let mut args = args.to_vec(); + // Prepend the indirect return pointer + args.insert(0, sret_ptr); + args + } + }; // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute::, Function<'gcc>>(func) }; let call = if self.functions.borrow().values().any(|value| *value == gcc_func) { // FIXME(antoyo): remove when the API supports a different type for functions. let func: Function<'gcc> = self.cx.rvalue_as_function(func); - self.function_call(func, args, funclet) + self.function_call(func, &args, funclet) } else { // If it's a not function that was defined, it's a function pointer. - self.function_ptr_call(typ, fn_abi, func, args, funclet) + self.function_ptr_call(typ, fn_abi, func, &args, funclet) }; if let Some(_fn_abi) = fn_abi { // FIXME(bjorn3): Apply function attributes @@ -1805,6 +1819,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: Self::Value, + _return_slot: ReturnSlot, _args: &[Self::Value], _funclet: Option<&Self::Funclet>, _instance: Option>, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 5550d22b33aa3..06713016cedbe 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -16,7 +16,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::MiscCodegenMethods; use rustc_codegen_ssa::traits::{ ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, - IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, + IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, ReturnSlot, }; use rustc_codegen_ssa::{MemFlags, RetagInfo}; use rustc_data_structures::fx::FxHashSet; @@ -655,7 +655,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } // FIXME directly use the llvm intrinsic adjustment functions here - let llret = self.call(fn_ty, None, None, fn_ptr, &call_args, None, None); + let llret = + self.call(fn_ty, None, None, fn_ptr, ReturnSlot::Direct, &call_args, None, None); if is_cleanup { self.apply_attrs_to_cleanup_callsite(llret); } @@ -666,7 +667,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call(self.type_void(), None, None, func, &[], None, None); + self.call(self.type_void(), None, None, func, ReturnSlot::Direct, &[], None, None); } fn assume(&mut self, value: Self::Value) { @@ -1347,7 +1348,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( let param_type = bx.u8_type.make_pointer(); let fn_type = bx.context.new_function_pointer_type(None, bx.type_void(), &[param_type], false); - bx.call(fn_type, None, None, try_func, &[data], None, None); + bx.call(fn_type, None, None, try_func, ReturnSlot::Direct, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. OperandValue::Immediate(bx.const_bool(false)).store(bx, dest); @@ -1420,21 +1421,41 @@ fn codegen_gnu_try<'gcc, 'tcx>( let zero = bx.cx.context.new_rvalue_zero(bx.int_type); let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, ReturnSlot::Direct, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not // generate a try/catch. // FIXME(antoyo): add a check in the libgccjit API to prevent this. bx.switch_to_block(current_block); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + ReturnSlot::Direct, + &[data], + then, + catch, + None, + None, + ); }); let func = unsafe { std::mem::transmute::, RValue<'gcc>>(func) }; // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None); + let ret = bx.call( + llty, + None, + None, + func, + ReturnSlot::Direct, + &[try_func, data, catch_func], + None, + None, + ); OperandValue::Immediate(ret).store(bx, dest); } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index c22318c0ec8a7..8e5750a2998bc 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -586,9 +586,20 @@ pub(crate) fn inline_asm_call<'ll>( assert!(catch_funclet.is_none()); bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + bx.invoke( + fty, + None, + None, + v, + ReturnSlot::Direct, + inputs, + dest.unwrap(), + catch, + funclet, + None, + ) } else { - bx.call(fty, None, None, v, inputs, None, None) + bx.call(fty, None, None, v, ReturnSlot::Direct, inputs, None, None) }; // Store mark in a metadata node so we can map LLVM errors diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dae8b2d17e0e1..9d4602e49968d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -454,15 +454,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, + return_slot: ReturnSlot<&'ll Value>, args: &[&'ll Value], then: &'ll BasicBlock, catch: &'ll BasicBlock, funclet: Option<&Funclet<'ll>>, instance: Option>, ) -> &'ll Value { + // If this function returns indirectly (`PassMode::Indirect`), + // the `return_slot` should be the first argument. + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { + let mut args = args.to_vec(); + args.insert(0, sret_ptr); + args + } + }; debug!("invoke {:?} with args ({:?})", llfn, args); - - let args = self.check_call("invoke", llty, llfn, args); + let args = self.check_call("invoke", llty, llfn, &args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { @@ -1463,13 +1473,23 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, + return_slot: ReturnSlot<&'ll Value>, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, callee_instance: Option>, ) -> &'ll Value { + // If this function returns indirectly (`PassMode::Indirect`), + // the `return_slot` should be the first argument. + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { + let mut args = args.to_vec(); + args.insert(0, sret_ptr); + args + } + }; debug!("call {:?} with args ({:?})", llfn, args); - - let args = self.check_call("call", llty, llfn, args); + let args = self.check_call("call", llty, llfn, &args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { @@ -1530,12 +1550,21 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, ) { - let call = - self.call(llty, caller_attrs, Some(fn_abi), llfn, args, funclet, callee_instance); + let call = self.call( + llty, + caller_attrs, + Some(fn_abi), + llfn, + return_slot, + args, + funclet, + callee_instance, + ); llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail); match &fn_abi.ret.mode { @@ -1875,7 +1904,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { args: &[&'ll Value], ) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); - self.call(ty, None, None, f, args, None, None) + // No LLVM intrinsic returns its data indirectly (via `sret`). + self.call(ty, None, None, f, ReturnSlot::Direct, args, None, None) } fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { @@ -2091,6 +2121,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { None, None, ubsan_handler, + ReturnSlot::Direct, &[diag_data, function_address, self.const_usize(0)], None, None, diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 8cefd8dc489a9..3831f3b0912fd 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::IntrinsicResult; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceValue; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ReturnSlot}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::RustcAutodiff; use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; @@ -372,7 +372,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( crate::typetree::add_tt(&bx, fn_to_diff, fnc_tree); } - let call = bx.call(enzyme_ty, None, None, ad_fn, &args, None, None); + let call = bx.call(enzyme_ty, None, None, ad_fn, ReturnSlot::Direct, &args, None, None); let fn_ret_ty = bx.cx.val_ty(call); if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[], false) { diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index e2ec20226e3ce..a84ca02cc3b18 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -6,7 +6,7 @@ use rustc_abi::Align; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ReturnSlot}; use rustc_middle::bug; use rustc_middle::ty::offload_meta::{MappingFlags, OffloadMetadata, OffloadSize}; @@ -681,7 +681,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let num_args = cx.get_const_i32(num_args); let args = vec![s_ident_t, i64_max, num_args, geps[0], geps[1], geps[2], o_type, nullptr, nullptr]; - builder.call(fn_ty, None, None, fn_to_call, &args, None, None); + builder.call(fn_ty, None, None, fn_to_call, ReturnSlot::Direct, &args, None, None); } // Step 2) @@ -718,7 +718,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let device_id = builder.sext(device_id, cx.type_i64()); let args = vec![s_ident_t, device_id, num_workgroups, threads_per_block, region_id, a5]; - builder.call(tgt_target_kernel_ty, None, None, tgt_decl, &args, None, None); + builder.call(tgt_target_kernel_ty, None, None, tgt_decl, ReturnSlot::Direct, &args, None, None); // %41 = call i32 @__tgt_target_kernel(ptr @1, i64 -1, i32 2097152, i32 256, ptr @.kernel_1.region_id, ptr %kernel_args) // Step 4) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 743145a0e5baf..f3740ed7504fe 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -245,7 +245,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::offload_get_num_devices => { let (fn_decl, fn_ty) = declare_omp_get_num_devices(self.cx); - let llval = self.call(fn_ty, None, None, fn_decl, &[], None, None); + let llval = + self.call(fn_ty, None, None, fn_decl, ReturnSlot::Direct, &[], None, None); return IntrinsicResult::Operand(OperandValue::Immediate(llval)); } @@ -1354,7 +1355,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( ) -> &'ll Value { if !bx.sess().panic_strategy().unwinds() { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.call(try_func_ty, None, None, try_func, &[data], None, None); + bx.call(try_func_ty, None, None, try_func, ReturnSlot::Direct, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. bx.const_bool(false) @@ -1452,7 +1453,18 @@ fn codegen_msvc_try<'ll, 'tcx>( let ptr_align = bx.tcx().data_layout.pointer_align().abi; let slot = bx.alloca(ptr_size, ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + ReturnSlot::Direct, + &[data], + normal, + catchswitch, + None, + None, + ); bx.switch_to_block(normal); bx.ret(bx.const_bool(false)); @@ -1500,7 +1512,16 @@ fn codegen_msvc_try<'ll, 'tcx>( let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]); let ptr = bx.load(bx.type_ptr(), slot, ptr_align); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + ReturnSlot::Direct, + &[data, ptr], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); // The flag value of 64 indicates a "catch-all". @@ -1508,7 +1529,16 @@ fn codegen_msvc_try<'ll, 'tcx>( let flags = bx.const_i32(64); let null = bx.const_null(bx.type_ptr()); let funclet = bx.catch_pad(cs, &[null, flags, null]); - bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + ReturnSlot::Direct, + &[data, null], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -1517,7 +1547,16 @@ fn codegen_msvc_try<'ll, 'tcx>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); + let ret = bx.call( + llty, + None, + None, + llfn, + ReturnSlot::Direct, + &[try_func, data, catch_func], + None, + None, + ); ret } @@ -1564,7 +1603,18 @@ fn codegen_wasm_try<'ll, 'tcx>( // } // let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + ReturnSlot::Direct, + &[data], + normal, + catchswitch, + None, + None, + ); bx.switch_to_block(normal); bx.ret(bx.const_bool(false)); @@ -1580,7 +1630,16 @@ fn codegen_wasm_try<'ll, 'tcx>( let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + ReturnSlot::Direct, + &[data, ptr], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -1589,7 +1648,16 @@ fn codegen_wasm_try<'ll, 'tcx>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); + let ret = bx.call( + llty, + None, + None, + llfn, + ReturnSlot::Direct, + &[try_func, data, catch_func], + None, + None, + ); ret } @@ -1630,7 +1698,18 @@ fn codegen_gnu_try<'ll, 'tcx>( let data = llvm::get_param(bx.llfn(), 1); let catch_func = llvm::get_param(bx.llfn(), 2); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + ReturnSlot::Direct, + &[data], + then, + catch, + None, + None, + ); bx.switch_to_block(then); bx.ret(bx.const_bool(false)); @@ -1648,13 +1727,22 @@ fn codegen_gnu_try<'ll, 'tcx>( bx.add_clause(vals, tydesc); let ptr = bx.extract_value(vals, 0); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, ReturnSlot::Direct, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); }); // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); + let ret = bx.call( + llty, + None, + None, + llfn, + ReturnSlot::Direct, + &[try_func, data, catch_func], + None, + None, + ); ret } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index d67156c6cfa39..e0b1df0bb632c 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -198,12 +198,21 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { args.push(llvm::get_param(alias_lldecl, index)); } + // For an indirect return, the alias's own first parameter is the + // caller-provided return slot: forward it to the aliasee as such. + let (return_slot, args) = if fn_abi.ret.is_indirect() { + let (sret_ptr, rest) = args.split_first().unwrap(); + (ReturnSlot::Indirect(*sret_ptr), rest) + } else { + (ReturnSlot::Direct, &args[..]) + }; let call = start_bx.call( fn_ty, Some(attrs), Some(fn_abi), aliasee, - &args, + return_slot, + args, None, Some(aliasee_instance), ); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8dd129f45cc5a..d909316194566 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -593,7 +593,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) }; - let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); + let result = + bx.call(start_ty, None, None, start_fn, ReturnSlot::Direct, &args, None, instance); if cx.sess().target.os == Os::Uefi { bx.ret(result); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index afd9a88784c2f..c3d66b6df2b81 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -165,12 +165,16 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional /// return destination `destination` and the unwind action `unwind`. + /// The `return_slot` is [`ReturnSlot::Indirect`] for functions returning + /// via `PassMode::Indirect`, and points to a buffer where the return value + /// shall be stored. fn do_call>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, bx: &mut Bx, fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, fn_ptr: Bx::Value, + return_slot: ReturnSlot, llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, mut unwind: mir::UnwindAction, @@ -244,8 +248,23 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } }; + debug_assert_eq!( + return_slot.is_indirect(), + fn_abi.ret.is_indirect(), + "a return slot must be provided if and only if the return is `PassMode::Indirect`", + ); + if kind == CallKind::Tail { - bx.tail_call(fn_ty, caller_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance); + bx.tail_call( + fn_ty, + caller_attrs, + fn_abi, + fn_ptr, + return_slot, + llargs, + self.funclet(fx), + instance, + ); return MergingSucc::False; } @@ -260,6 +279,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, + return_slot, llargs, ret_llbb, unwind_block, @@ -291,6 +311,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, + return_slot, llargs, self.funclet(fx), instance, @@ -718,6 +739,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, drop_fn, + ReturnSlot::Direct, args, Some((ReturnDest::Nothing, target)), unwind, @@ -822,6 +844,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + ReturnSlot::Direct, &args, None, unwind, @@ -853,6 +876,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + ReturnSlot::Direct, &[], None, mir::UnwindAction::Unreachable, @@ -922,6 +946,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + ReturnSlot::Direct, &[msg.0, msg.1], target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), unwind, @@ -1202,21 +1227,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // We still need to call `make_return_dest` even if there's no `target`, since // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // and `make_return_dest` adds the return-place indirect pointer to `llargs`. - let destination = match kind { + let (destination, return_slot) = match kind { CallKind::Normal => { - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); - target.map(|target| (return_dest, target)) + let (return_dest, return_slot) = + self.make_return_dest(bx, destination, &fn_abi.ret); + (target.map(|target| (return_dest, target)), return_slot) } CallKind::Tail => { - if fn_abi.ret.is_indirect() { - match self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs) { - ReturnDest::Nothing => {} + let return_slot = if fn_abi.ret.is_indirect() { + match self.make_return_dest(bx, destination, &fn_abi.ret) { + (ReturnDest::Nothing, return_slot) => return_slot, _ => bug!( "tail calls to functions with indirect returns cannot store into a destination" ), } - } - None + } else { + ReturnSlot::Direct + }; + (None, return_slot) } }; @@ -1441,6 +1469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, fn_ptr, + return_slot, &llargs, destination, unwind, @@ -2360,7 +2389,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { let fn_ty = bx.fn_decl_backend_type(fn_abi); - let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None); + let llret = bx.call( + fn_ty, + None, + Some(fn_abi), + fn_ptr, + ReturnSlot::Direct, + &[], + funclet.as_ref(), + None, + ); bx.apply_attrs_to_cleanup_callsite(llret); } @@ -2396,11 +2434,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, dest: mir::Place<'tcx>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, - llargs: &mut Vec, - ) -> ReturnDest<'tcx, Bx::Value> { + ) -> (ReturnDest<'tcx, Bx::Value>, ReturnSlot) { // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { - return ReturnDest::Nothing; + return (ReturnDest::Nothing, ReturnSlot::Direct); } let dest = if let Some(index) = dest.as_local() { match self.locals[index] { @@ -2414,10 +2451,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but the calling convention has an indirect return. let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); - llargs.push(tmp.val.llval); - ReturnDest::IndirectOperand(tmp, index) + ( + ReturnDest::IndirectOperand(tmp, index), + ReturnSlot::Indirect(tmp.val.llval), + ) } else { - ReturnDest::DirectOperand(index) + (ReturnDest::DirectOperand(index), ReturnSlot::Direct) }; } LocalRef::Operand(_) => { @@ -2437,10 +2476,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to create a temporary. span_bug!(self.mir.span, "can't directly store to unaligned value"); } - llargs.push(dest.val.llval); - ReturnDest::Nothing + (ReturnDest::Nothing, ReturnSlot::Indirect(dest.val.llval)) } else { - ReturnDest::Store(dest) + (ReturnDest::Store(dest), ReturnSlot::Direct) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 344a4834862e4..6278020eabecd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -779,6 +779,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_attrs.as_deref(), Some(fn_abi), fn_ptr, + ReturnSlot::Direct, &[], None, Some(instance), diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 0ef0179eac6c4..e286681c293ee 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -78,6 +78,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /* fn_attrs */ None, Some(fn_abi), llfn, + ReturnSlot::Direct, // we know the ABI here &[msg.0, msg.1], None, None, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index cb0209a0ae369..b7b694922bcfa 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -34,6 +34,20 @@ pub enum OverflowOp { Mul, } +/// The location of the return value for the call. +#[derive(Copy, Clone, Debug)] +pub enum ReturnSlot { + Direct, + /// The return value will be passed via sret (e.g. `PassMode::Indirect`). + Indirect(V), +} + +impl ReturnSlot { + pub fn is_indirect(&self) -> bool { + matches!(self, ReturnSlot::Indirect(_)) + } +} + pub trait BuilderMethods<'a, 'tcx>: Sized + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> @@ -135,6 +149,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], then: Self::BasicBlock, catch: Self::BasicBlock, @@ -638,16 +653,20 @@ pub trait BuilderMethods<'a, 'tcx>: /// The typical case that they are None is during the codegen of intrinsics and lang-items, /// as those are "fake functions" with only a trivial ABI if any, et cetera. /// + /// `return_slot` must be `ReturnSlot::Indirect` if an argument uses `PassMode::Indirect`. + /// /// ## Return /// - /// Must return the value the function will return so it can be written to the destination, - /// assuming the function does not explicitly pass the destination as a pointer in `args`. + /// Must return the value the function will return so it can be written to the destination. + /// For calls with an indirect return, the returned value is meaningless and must not be + /// used: the return value lives in the return slot. fn call( &mut self, llty: Self::FunctionSignature, caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, fn_val: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, @@ -659,6 +678,7 @@ pub trait BuilderMethods<'a, 'tcx>: caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index f46d07ea5008e..1f013cb122070 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -36,7 +36,7 @@ pub use self::asm::{ AsmBuilderMethods, AsmCodegenMethods, GlobalAsmOperandRef, InlineAsmOperandRef, }; pub use self::backend::{BackendTypes, CodegenBackend, ExtraBackendMethods}; -pub use self::builder::{BuilderMethods, OverflowOp}; +pub use self::builder::{BuilderMethods, OverflowOp, ReturnSlot}; pub use self::consts::ConstCodegenMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 7efa784bd8622..c72a89ccdee76 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -605,6 +605,9 @@ declare_features! ( (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)), + /// Allows directly represented generic_const_args as the rhs of const items without the + /// `direct_const_arg!` macro. + (incomplete, macroless_const_item_generic_const_args, "CURRENT_RUSTC_VERSION", Some(162540)), /// Allows directly represented generic_const_args without the `direct_const_arg!` macro. (incomplete, macroless_generic_const_args, "1.99.0", Some(159006)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. @@ -856,5 +859,6 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[ pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[ (sym::generic_const_args, &[sym::min_generic_const_args]), (sym::macroless_generic_const_args, &[sym::min_generic_const_args]), + (sym::macroless_const_item_generic_const_args, &[sym::min_generic_const_args]), (sym::unsized_const_params, &[sym::adt_const_params]), ]; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1ff2a2cb1a404..7452e3e08ade9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -135,6 +135,88 @@ trait UnusedDelimLint { is_kw: bool, ); + /// Returns whether the outer braces of a single-expression function/method + /// argument block can be removed. + /// + /// In Rust 2024, `{ expr }` can drop tail-expression temporaries before the + /// call starts. Removing the block may extend those temporaries, so lint only + /// expression forms that are harmless here. + fn expr_allows_remove_arg_block(expr: &ast::Expr) -> bool { + use ast::ExprKind::*; + + match &expr.peel_parens().kind { + Lit(_) | IncludedBytes(_) | Path(..) => true, + Unary(_, expr) + | Cast(expr, _) + | Type(expr, _) + | Use(expr, _) + | Await(expr, _) + | Try(expr) + | Move(expr, _) + | AddrOf(_, _, expr) + | UnsafeBinderCast(_, expr, _) => Self::expr_allows_remove_arg_block(expr), + Array(exprs) | Tup(exprs) => { + exprs.iter().all(|expr| Self::expr_allows_remove_arg_block(expr)) + } + Binary(_, lhs, rhs) | Assign(lhs, rhs, _) | AssignOp(_, lhs, rhs) => { + Self::expr_allows_remove_arg_block(lhs) && Self::expr_allows_remove_arg_block(rhs) + } + Index(base, index, _) => { + Self::expr_allows_remove_arg_block(base) + && Self::expr_allows_remove_arg_block(index) + } + Range(start, end, _) => { + start.as_ref().is_none_or(|expr| Self::expr_allows_remove_arg_block(expr)) + && end.as_ref().is_none_or(|expr| Self::expr_allows_remove_arg_block(expr)) + } + Struct(expr) => { + expr.fields.iter().all(|field| Self::expr_allows_remove_arg_block(&field.expr)) + && match &expr.rest { + ast::StructRest::Base(expr) => Self::expr_allows_remove_arg_block(expr), + ast::StructRest::Rest(_) | ast::StructRest::None => true, + ast::StructRest::NoneWithError(_) => false, + } + } + Repeat(expr, _) => Self::expr_allows_remove_arg_block(expr), + ConstBlock(_) + | If(..) + | While(..) + | ForLoop { .. } + | Loop(..) + | Match(..) + | Closure(_) + | Block(..) + | Gen(..) + | TryBlock(..) + | Break(..) + | Continue(_) + | Ret(_) + | InlineAsm(_) + | OffsetOf(..) + | Yield(_) + | Yeet(_) + | Paren(_) + | Become(_) => true, + Call(..) | MethodCall(_) | Let(..) | Field(..) | MacCall(_) | FormatArgs(_) => false, + // `direct_const_arg!()` is invalid in function/method argument position. + DirectConstArg(_) => false, + // don't lint for placeholder/error-recovery + Underscore | Err(_) | Dummy => false, + } + } + + /// Returns whether `{ expr }` must be kept in function/method argument + /// position to avoid changing temporary lifetime semantics. + fn needs_arg_block_to_preserve_temporaries( + ctx: UnusedDelimsCtx, + arg_block: &ast::Expr, + expr: &ast::Expr, + ) -> bool { + matches!(ctx, UnusedDelimsCtx::FunctionArg | UnusedDelimsCtx::MethodArg) + && arg_block.span.edition().at_least_rust_2024() + && !Self::expr_allows_remove_arg_block(expr) + } + fn is_expr_delims_necessary( inner: &ast::Expr, ctx: UnusedDelimsCtx, @@ -1098,6 +1180,7 @@ impl UnusedDelimLint for UnusedBraces { // lock guard, before the loop starts. && !(ctx == UnusedDelimsCtx::ForIterExpr && value.span.edition().at_least_rust_2024()) + && !Self::needs_arg_block_to_preserve_temporaries(ctx, value, expr) && (ctx != UnusedDelimsCtx::AnonConst || (matches!(expr.kind, ast::ExprKind::Lit(_)) && !expr.span.from_expansion())) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dc4a41ace6b88..9a2e86577fa62 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,8 +1,10 @@ use std::borrow::Borrow; +use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fs::File; use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; +use std::rc::Rc; use std::sync::Arc; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -29,7 +31,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::mitigation_coverage::DeniedPartialMitigation; use rustc_session::config::{OptLevel, TargetModifier}; use rustc_span::def_id::CRATE_MOD_ID; -use rustc_span::hygiene::HygieneEncodeContext; +use rustc_span::hygiene::{HygieneEncodeContext, raw_encode_syntax_context}; use rustc_span::{ ByteSymbol, ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, Symbol, SyntaxContext, sym, @@ -66,7 +68,7 @@ pub(super) struct EncodeContext<'a, 'tcx> { // order of `SourceFiles`, and encoded inside `Span`s. required_source_files: Option>, is_proc_macro: bool, - hygiene_ctxt: &'a HygieneEncodeContext, + hygiene_ctxt: Rc>, // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, } @@ -156,7 +158,7 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { - rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_ctxt, self); + raw_encode_syntax_context(syntax_context, Rc::clone(&self.hygiene_ctxt), self) } fn encode_expn_id(&mut self, expn_id: ExpnId) { @@ -165,7 +167,7 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { // data from the corresponding crate's metadata. // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external // metadata from proc-macro crates. - self.hygiene_ctxt.schedule_expn_data_for_encoding(expn_id); + self.hygiene_ctxt.borrow_mut().schedule_expn_data_for_encoding(expn_id); } expn_id.krate.encode(self); expn_id.local_id.encode(self); @@ -1966,14 +1968,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let mut expn_data_table: TableBuilder<_, _> = Default::default(); let mut expn_hash_table: TableBuilder<_, _> = Default::default(); - self.hygiene_ctxt.encode( + HygieneEncodeContext::encode( + &Rc::clone(&self.hygiene_ctxt), &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), |(this, syntax_contexts, _, _), index, ctxt_data| { syntax_contexts.set_some(index, this.lazy(ctxt_data)); }, |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { if let Some(index) = index.as_local() { - expn_data_table.set_some(index.as_raw(), this.lazy(expn_data)); + expn_data_table + .set_some(index.as_raw(), this.lazy(expn_data.expect("local expn"))); + expn_hash_table.set_some(index.as_raw(), this.lazy(hash)); } }, @@ -2559,8 +2564,6 @@ fn with_encode_metadata_header( let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); - let hygiene_ctxt = HygieneEncodeContext::default(); - let mut ecx = EncodeContext { opaque: encoder, tcx, @@ -2574,7 +2577,7 @@ fn with_encode_metadata_header( interpret_allocs: Default::default(), required_source_files, is_proc_macro: tcx.crate_types().contains(&CrateType::ProcMacro), - hygiene_ctxt: &hygiene_ctxt, + hygiene_ctxt: Default::default(), symbol_index_table: Default::default(), }; diff --git a/compiler/rustc_middle/src/hooks.rs b/compiler/rustc_middle/src/hooks.rs index 7a69f58d52fae..df95bd6149e47 100644 --- a/compiler/rustc_middle/src/hooks.rs +++ b/compiler/rustc_middle/src/hooks.rs @@ -106,7 +106,7 @@ declare_hooks! { hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>; /// Serializes all eligible query return values into the on-disk cache. - hook encode_query_values(encoder: &mut CacheEncoder<'_, 'tcx>) -> (); + hook encode_query_values(encoder: &mut CacheEncoder<'tcx>) -> (); } #[cold] diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index d743c5dcc7e43..1fa0aa421d584 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -1,4 +1,6 @@ +use std::cell::RefCell; use std::collections::hash_map::Entry; +use std::rc::Rc; use std::sync::Arc; use std::{fmt, mem}; @@ -16,6 +18,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, + raw_encode_syntax_context, }; use rustc_span::{ BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, RelativeBytePos, @@ -223,8 +226,6 @@ impl OnDiskCache { (file_to_file_index, file_index_to_stable_id) }; - let hygiene_encode_context = HygieneEncodeContext::default(); - let mut encoder = CacheEncoder { tcx, encoder, @@ -233,7 +234,7 @@ impl OnDiskCache { interpret_allocs: Default::default(), caching_source_map_view: CachingSourceMapView::new(tcx.sess.source_map()), file_to_file_index, - hygiene_context: &hygiene_encode_context, + hygiene_context: Default::default(), symbol_index_table: Default::default(), query_values_index: Default::default(), side_effects_index: Default::default(), @@ -278,7 +279,8 @@ impl OnDiskCache { // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current // session. - hygiene_encode_context.encode( + HygieneEncodeContext::encode( + &Rc::clone(&encoder.hygiene_context), &mut encoder, |encoder, index, ctxt_data| { let pos = AbsoluteBytePos::new(encoder.position()); @@ -288,7 +290,7 @@ impl OnDiskCache { |encoder, expn_id, data, hash| { if expn_id.krate == LOCAL_CRATE { let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, data); + encoder.encode_tagged(TAG_EXPN_DATA, data.expect("local expn")); expn_data.insert(hash, pos); } else { foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); @@ -774,7 +776,7 @@ impl_ref_decoder! {<'tcx> //- ENCODING ------------------------------------------------------------------- /// An encoder that can write to the incremental compilation cache. -pub struct CacheEncoder<'a, 'tcx> { +pub struct CacheEncoder<'tcx> { tcx: TyCtxt<'tcx>, encoder: FileEncoder<'static>, type_shorthands: FxHashMap, usize>, @@ -782,7 +784,7 @@ pub struct CacheEncoder<'a, 'tcx> { interpret_allocs: FxIndexSet, caching_source_map_view: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, - hygiene_context: &'a HygieneEncodeContext, + hygiene_context: Rc>, // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, @@ -790,14 +792,14 @@ pub struct CacheEncoder<'a, 'tcx> { side_effects_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, } -impl<'a, 'tcx> fmt::Debug for CacheEncoder<'a, 'tcx> { +impl<'tcx> fmt::Debug for CacheEncoder<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Add more details here if/when necessary. f.write_str("CacheEncoder") } } -impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { +impl<'tcx> CacheEncoder<'tcx> { #[inline] fn source_file_index(&mut self, source_file: Arc) -> SourceFileIndex { self.file_to_file_index[&(&raw const *source_file)] @@ -866,13 +868,13 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { +impl<'tcx> SpanEncoder for CacheEncoder<'tcx> { fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { - rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_context, self); + raw_encode_syntax_context(syntax_context, Rc::clone(&self.hygiene_context), self); } fn encode_expn_id(&mut self, expn_id: ExpnId) { - self.hygiene_context.schedule_expn_data_for_encoding(expn_id); + self.hygiene_context.borrow_mut().schedule_expn_data_for_encoding(expn_id); expn_id.expn_hash().encode(self); } @@ -944,7 +946,7 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx> { +impl<'tcx> TyEncoder<'tcx> for CacheEncoder<'tcx> { const CLEAR_CROSS_CRATE: bool = false; #[inline] @@ -976,7 +978,7 @@ macro_rules! encoder_methods { } } -impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { +impl<'tcx> Encoder for CacheEncoder<'tcx> { encoder_methods! { emit_usize(usize); emit_u128(u128); @@ -999,8 +1001,8 @@ impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`. // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` // and the encoding traits currently work. -impl<'a, 'tcx> Encodable> for [u8] { - fn encode(&self, e: &mut CacheEncoder<'a, 'tcx>) { +impl<'tcx> Encodable> for [u8] { + fn encode(&self, e: &mut CacheEncoder<'tcx>) { self.encode(&mut e.encoder); } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 84203c5caefea..5454a7bef67a7 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -1,8 +1,10 @@ use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_hir::Safety; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::mir_cast_kind; use rustc_span::{Span, Spanned}; @@ -205,6 +207,97 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { ) } + fn parse_cast_fn_ptr_safety(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, _, "function pointer safety", + @variant(mir_cast_fn_ptr_safety, Safe) => { + Ok(Safety::Safe) + }, + @variant(mir_cast_fn_ptr_safety, Unsafe) => { + Ok(Safety::Unsafe) + }, + ) + } + + fn parse_cast_pointer_coercion(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, expr, "pointer coercion kind", + @variant(mir_cast_ptr_coercion, ReifyFnPointer) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(PointerCoercion::ReifyFnPointer( + self.parse_cast_fn_ptr_safety(fields[0].expr)?, + )) + }, + @variant(mir_cast_ptr_coercion, UnsafeFnPointer) => { + Ok(PointerCoercion::UnsafeFnPointer) + }, + @variant(mir_cast_ptr_coercion, ClosureFnPointer) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(PointerCoercion::ClosureFnPointer( + self.parse_cast_fn_ptr_safety(fields[0].expr)?, + )) + }, + @variant(mir_cast_ptr_coercion, MutToConstPointer) => { + Ok(PointerCoercion::MutToConstPointer) + }, + @variant(mir_cast_ptr_coercion, ArrayToPointer) => { + Ok(PointerCoercion::ArrayToPointer) + }, + @variant(mir_cast_ptr_coercion, UnsizePointee) => { + Ok(PointerCoercion::Unsize) + }, + ) + } + + fn parse_cast_kind(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, expr, "cast kind", + @variant(mir_cast_kind, PointerExposeProvenance) => { + Ok(CastKind::PointerExposeProvenance) + }, + @variant(mir_cast_kind, PointerWithExposedProvenance) => { + Ok(CastKind::PointerWithExposedProvenance) + }, + @variant(mir_cast_kind, IntToInt) => { + Ok(CastKind::IntToInt) + }, + @variant(mir_cast_kind, FloatToInt) => { + Ok(CastKind::FloatToInt) + }, + @variant(mir_cast_kind, FloatToFloat) => { + Ok(CastKind::FloatToFloat) + }, + @variant(mir_cast_kind, IntToFloat) => { + Ok(CastKind::IntToFloat) + }, + @variant(mir_cast_kind, PtrToPtr) => { + Ok(CastKind::PtrToPtr) + }, + @variant(mir_cast_kind, FnPtrToPtr) => { + Ok(CastKind::FnPtrToPtr) + }, + @variant(mir_cast_kind, Transmute) => { + Ok(CastKind::Transmute) + }, + @variant(mir_cast_kind, BoxDerefTransmute) => { + Ok(CastKind::BoxDerefTransmute) + }, + @variant(mir_cast_kind, Subtype) => { + Ok(CastKind::Subtype) + }, + @variant(mir_cast_kind, PointerCoercion) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(CastKind::PointerCoercion( + self.parse_cast_pointer_coercion(fields[0].expr)?, + CoercionSource::AsCast, + )) + }, + ) + } + fn parse_rvalue(&self, expr_id: ExprId) -> PResult> { parse_by_kind!(self, expr_id, expr, "rvalue", @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant), @@ -221,6 +314,10 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let kind = CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, CoercionSource::AsCast); Ok(Rvalue::Cast(kind, source, expr.ty)) }, + @call(mir_cast, args) => { + let source = self.parse_operand(args[0])?; + Ok(Rvalue::Cast(self.parse_cast_kind(args[1])?, source, expr.ty)) + }, @call(mir_checked, args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cd7f422fb72f3..7da24f5251239 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -208,9 +208,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } AttributeKind::Naked(..) => self.check_naked(hir_id, target), - AttributeKind::NonExhaustive(attr_span) => { - self.check_non_exhaustive(*attr_span, span, target, item) - } AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target), AttributeKind::MacroExport { span, .. } => { @@ -293,6 +290,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::NoMain => (), AttributeKind::NoMangle(..) => (), AttributeKind::NoStd { .. } => (), + AttributeKind::NonExhaustive(_) => (), AttributeKind::OnUnknown { .. } => (), AttributeKind::OnUnmatchedArgs { .. } => (), AttributeKind::Opaque => (), @@ -797,32 +795,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. - fn check_non_exhaustive( - &self, - attr_span: Span, - span: Span, - target: Target, - item: Option<&'tcx Item<'tcx>>, - ) { - match target { - Target::Struct => { - if let hir::Item { - kind: hir::ItemKind::Struct(_, _, hir::VariantData::Struct { fields, .. }), - .. - } = item.unwrap() - && fields.iter().any(|f| f.default.is_some()) - { - self.dcx().emit_err(diagnostics::NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: span, - }); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 5f99c4b133597..8b0ba0ab8f102 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -48,15 +48,6 @@ pub(crate) struct OuterCrateLevelAttrSuggestion { #[diag("crate-level attribute should be in the root module")] pub(crate) struct InnerCrateLevelAttr; -#[derive(Diagnostic)] -#[diag("`#[non_exhaustive]` can't be used to annotate items with default field values")] -pub(crate) struct NonExhaustiveWithDefaultFieldValues { - #[primary_span] - pub attr_span: Span, - #[label("this struct has default field values")] - pub defn_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[doc(alias = \"...\")]` isn't allowed on {$location}")] pub(crate) struct DocAliasBadLocation<'a> { diff --git a/compiler/rustc_query_impl/src/incremental.rs b/compiler/rustc_query_impl/src/incremental.rs index 341c9f5e5068d..1a007ac55a4ea 100644 --- a/compiler/rustc_query_impl/src/incremental.rs +++ b/compiler/rustc_query_impl/src/incremental.rs @@ -19,19 +19,19 @@ fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool { state.active.lock_shards().all(|shard| shard.is_empty()) } -pub(crate) fn encode_query_values<'tcx>(tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>) { +pub(crate) fn encode_query_values<'tcx>(tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'tcx>) { for_each_query_vtable!(CACHE_ON_DISK, tcx, |query| { encode_query_values_inner(tcx, query, encoder) }); } -fn encode_query_values_inner<'a, 'tcx, C, V>( +fn encode_query_values_inner<'tcx, C, V>( tcx: TyCtxt<'tcx>, query: &'tcx QueryVTable<'tcx, C>, - encoder: &mut CacheEncoder<'a, 'tcx>, + encoder: &mut CacheEncoder<'tcx>, ) where C: QueryCache>, - V: Erasable + Encodable>, + V: Erasable + Encodable>, { let _timer = tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 4c8000c28f065..1fab7a37a9941 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -188,6 +188,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, + None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index fa0133a3c7fd8..3ca3fd0940f7f 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -24,7 +24,9 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) +use std::cell::RefCell; use std::hash::Hash; +use std::rc::Rc; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -1294,74 +1296,97 @@ impl DesugaringKind { #[derive(Default)] pub struct HygieneEncodeContext { /// All `SyntaxContexts` for which we have written `SyntaxContextData` into crate metadata. - /// This is `None` after we finish encoding `SyntaxContexts`, to ensure - /// that we don't accidentally try to encode any more `SyntaxContexts` - serialized_ctxts: Lock>, + serialized_ctxts: FxHashSet, /// The `SyntaxContexts` that we have serialized (e.g. as a result of encoding `Spans`) /// in the most recent 'round' of serializing. Serializing `SyntaxContextData` /// may cause us to serialize more `SyntaxContext`s, so serialize in a loop /// until we reach a fixed point. - latest_ctxts: Lock>, + latest_ctxts: FxHashSet, - serialized_expns: Lock>, - - latest_expns: Lock>, + serialized_expns: FxHashSet, + latest_expns: FxHashSet, } impl HygieneEncodeContext { /// Record the fact that we need to serialize the corresponding `ExpnData`. - pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) { - if !self.serialized_expns.lock().contains(&expn) { - self.latest_expns.lock().insert(expn); - } + #[inline] + pub fn schedule_expn_data_for_encoding(&mut self, expn: ExpnId) { + self.latest_expns.insert(expn); } pub fn encode( - &self, + h_ctxt: &RefCell, encoder: &mut T, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), - mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), + mut encode_expn: impl FnMut(&mut T, ExpnId, Option<&ExpnData>, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing // a `SyntaxContext` that we haven't seen before - while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() { + + // Reuse the capacity between the loop iterations below. + let mut all_ctxt_data = vec![]; + let mut all_expn_data = vec![]; + + while { + let h_ctxt = h_ctxt.borrow(); + !h_ctxt.latest_ctxts.is_empty() || !h_ctxt.latest_expns.is_empty() + } { debug!( "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}", - self.latest_ctxts.lock().len(), - self.latest_ctxts + h_ctxt.borrow().latest_ctxts.len(), + h_ctxt.borrow().latest_ctxts ); + let mut mut_hctxt = h_ctxt.borrow_mut(); + // Consume the current round of syntax contexts. - // Drop the lock() temporary early. - // It's fine to iterate over a HashMap, because the serialization of the table + // It's fine to iterate over a HashSet, because the serialization of the table // that we insert data into doesn't depend on insertion order. #[allow(rustc::potential_query_instability)] - let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter(); - let all_ctxt_data: Vec<_> = HygieneData::with(|data| { - latest_ctxts - .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key())) - .collect() - }); - for (ctxt, ctxt_key) in all_ctxt_data { - if self.serialized_ctxts.lock().insert(ctxt) { - encode_ctxt(encoder, ctxt.0, &ctxt_key); + let latest_ctxts = { mem::take(&mut mut_hctxt.latest_ctxts) }.into_iter(); + + HygieneData::with(|data| { + for ctxt in latest_ctxts { + if !mut_hctxt.serialized_ctxts.insert(ctxt) { + continue; + } + + all_ctxt_data.push((ctxt.0, data.syntax_context_data[ctxt.0 as usize].key())); } + }); + + drop(mut_hctxt); + + for (idx, ctxt_key) in all_ctxt_data.drain(..) { + encode_ctxt(encoder, idx, &ctxt_key); } + let mut mut_hctxt = h_ctxt.borrow_mut(); + // Same as above, but for expansions instead of syntax contexts. #[allow(rustc::potential_query_instability)] - let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter(); - let all_expn_data: Vec<_> = HygieneData::with(|data| { - latest_expns - .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))) - .collect() - }); - for (expn, expn_data, expn_hash) in all_expn_data { - if self.serialized_expns.lock().insert(expn) { - encode_expn(encoder, expn, &expn_data, expn_hash); + let latest_expns = { mem::take(&mut mut_hctxt.latest_expns) }.into_iter(); + HygieneData::with(|data| { + for expn in latest_expns { + if !mut_hctxt.serialized_expns.insert(expn) { + continue; + } + + // We need `data` only for local expansions, so don't `data` for non-local + // expansions. + // FIXME: completely remove this clone + let expn_data = expn.as_local().map(|id| data.local_expn_data(id).clone()); + all_expn_data.push((expn, expn_data, data.expn_hash(expn))); } + }); + + drop(mut_hctxt); + + for (expn, expn_data, expn_hash) in all_expn_data.drain(..) { + encode_expn(encoder, expn, expn_data.as_ref(), expn_hash); } } + debug!("encode_hygiene: Done serializing SyntaxContextData"); } } @@ -1484,14 +1509,13 @@ impl Decodable for LocalExpnId { } } +#[inline] pub fn raw_encode_syntax_context( ctxt: SyntaxContext, - context: &HygieneEncodeContext, + context: Rc>, e: &mut impl Encoder, ) { - if !context.serialized_ctxts.lock().contains(&ctxt) { - context.latest_ctxts.lock().insert(ctxt); - } + context.borrow_mut().latest_ctxts.insert(ctxt); ctxt.0.encode(e); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 17ffb52f4b333..bb8b79dbb6fca 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -163,6 +163,7 @@ symbols! { Arc, ArcWeak, Array, + ArrayToPointer, AsMut, AsRef, AssertParamIsClone, @@ -176,6 +177,7 @@ symbols! { Bool, Borrow, BorrowMut, + BoxDerefTransmute, Break, BuildHasher, CStr, @@ -187,6 +189,7 @@ symbols! { Cleanup, Client, Clone, + ClosureFnPointer, CoercePointee, CoercePointeeValidated, CoerceShared, @@ -219,11 +222,14 @@ symbols! { ExternC, ExternRust, Float, + FloatToFloat, + FloatToInt, FmtArgumentsNew, Fn, FnMut, FnOnce, FnPtr, + FnPtrToPtr, Formatter, Forward, Found, @@ -239,6 +245,8 @@ symbols! { IndexOutput, Input, Int, + IntToFloat, + IntToInt, Into, IntoAsyncIterator, IntoFuture, @@ -255,6 +263,7 @@ symbols! { Lifetime, LintPass, LocalKey, + MutToConstPointer, Mutex, MutexGuard, Named, @@ -274,7 +283,11 @@ symbols! { PinDerefMutHelper, PinMacroHelper, Pointer, + PointerCoercion, + PointerExposeProvenance, + PointerWithExposedProvenance, Poll, + PtrToPtr, Range, RangeCopy, RangeFrom, @@ -294,6 +307,7 @@ symbols! { Reborrow, RefCell, Reference, + ReifyFnPointer, Relaxed, Release, Result, @@ -306,6 +320,8 @@ symbols! { RwLock, RwLockReadGuard, RwLockWriteGuard, + Safe, + Safety, SelfTy, Send, SeqCst, @@ -320,12 +336,14 @@ symbols! { String, Struct, StructuralPartialEq, + Subtype, SymbolIntern, Sync, SyncUnsafeCell, Target, This, TokenStream, + Transmute, TrivialClone, Try, TryCaptureGeneric, @@ -339,7 +357,10 @@ symbols! { Type, Union, Unresolved, + Unsafe, + UnsafeFnPointer, Unsize, + UnsizePointee, Vec, Wrapper, _DECLS, @@ -1253,6 +1274,7 @@ symbols! { macro_reexport, macro_use, macro_vis_matcher, + macroless_const_item_generic_const_args, macroless_generic_const_args, macros_in_extern, main, @@ -1321,6 +1343,10 @@ symbols! { mir_assume, mir_basic_block, mir_call, + mir_cast, + mir_cast_fn_ptr_safety, + mir_cast_kind, + mir_cast_ptr_coercion, mir_cast_ptr_to_ptr, mir_cast_transmute, mir_cast_unsize, diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs index 8f2746c461661..670cb5b5d10e6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { metadata: TargetMetadata { description: Some("32-bit MSVC (Windows 10+)".into()), tier: Some(1), - host_tools: Some(true), + host_tools: Some(false), std: Some(true), }, pointer_width: 32, diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index dce7bf681a7af..929e56872674d 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -508,6 +508,41 @@ define!( fn __debuginfo(name: &'static str, s: T) ); +#[rustc_diagnostic_item = "mir_cast_fn_ptr_safety"] +pub enum Safety { + Safe, + Unsafe, +} +#[rustc_diagnostic_item = "mir_cast_ptr_coercion"] +pub enum PointerCoercion { + ReifyFnPointer(Safety), + UnsafeFnPointer, + ClosureFnPointer(Safety), + MutToConstPointer, + ArrayToPointer, + UnsizePointee, +} +#[rustc_diagnostic_item = "mir_cast_kind"] +pub enum CastKind { + PointerExposeProvenance, + PointerWithExposedProvenance, + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, + BoxDerefTransmute, + Subtype, + PointerCoercion(PointerCoercion), +} +define!( + "mir_cast", + /// Emits a cast of the specified kind. + fn Cast(operand: T, kind: CastKind) -> U +); + /// Macro for generating custom MIR. /// /// See the module documentation for syntax details. This macro is not magic - it only transforms diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index b6bf18a155051..c91e6961f9123 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -25,7 +25,9 @@ are documented at our [Forge documentation site][forge]. Tier 1 targets can be thought of as "guaranteed to work". The Rust project builds official binary releases for each tier 1 target, and automated testing -ensures that each tier 1 target builds and passes tests after each change. +ensures that each tier 1 target builds and passes tests after each change. For +the full requirements, see [Tier 1 target +policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy. Tier 1 targets with host tools additionally support running tools like `rustc` and `cargo` natively on the target, and automated testing ensures that tests @@ -34,19 +36,17 @@ development platform, not just a compilation target. For the full requirements, see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in the Target Tier Policy. -All tier 1 targets with host tools support the full standard library. +All tier 1 (with host tools) targets support the full standard library. 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`](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+) [`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) - [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. [^win32-msvc-alignment]: Due to non-standard behavior of MSVC, native C code on this target can cause types with an alignment of more than 4 bytes to be incorrectly aligned to only 4 bytes (this affects, e.g., `u64` and `i64`). Rust applies some mitigations to reduce the impact of this issue, but this can still cause unsoundness due to unsafe code that (correctly) assumes that references are always properly aligned. See [issue #112480](https://github.com/rust-lang/rust/issues/112480). @@ -54,16 +54,13 @@ target | notes [77071]: https://github.com/rust-lang/rust/issues/77071 [x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567 -## Tier 1 +## Tier 1 without Host Tools -Tier 1 targets can be thought of as "guaranteed to work". The Rust project -builds official binary releases for each tier 1 target, and automated testing -ensures that each tier 1 target builds and passes tests after each change. For -the full requirements, see [Tier 1 target -policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy. +target | notes +-------|------- +[`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] -At this time, all Tier 1 targets are [Tier 1 with Host -Tools](#tier-1-with-host-tools). +All tier 1 (without host tools) targets support the full standard library. ## Tier 2 with Host Tools @@ -421,7 +418,7 @@ target | std | host | notes [`riscv64-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | RISC-V OpenEmbedded/Yocto Linux (GNU) [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `riscv64gc-unknown-freebsd` | ? | | RISC-V FreeBSD -`riscv64gc-unknown-fuchsia` | ? | | RISC-V Fuchsia +[`riscv64gc-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | | RISC-V Fuchsia [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit [`riscv64gc-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | RISC-V Managarm [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index e2befc5d9955b..2ce9916003393 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -7,8 +7,11 @@ updatable, and performant. ## Target maintainers -[@erickt](https://github.com/erickt) -[@Nashenas88](https://github.com/Nashenas88) +- [@Nashenas88](https://github.com/Nashenas88) +- [@PiJoules](https://github.com/PiJoules) +- [@erickt](https://github.com/erickt) +- [@ilovepi](https://github.com/ilovepi) +- [@petrhosek](https://github.com/petrhosek) The up-to-date list can be also found via the [fuchsia marker team](https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml). @@ -181,12 +184,12 @@ Before building Rust for Fuchsia, you'll need a clang toolchain that supports Fuchsia as well. A recent version (14+) of clang should be sufficient to compile Rust for Fuchsia. -x86-64 and AArch64 Fuchsia targets can be enabled using the following +x86-64, AArch64, and riscv64gc Fuchsia targets can be enabled using the following configuration in `bootstrap.toml`: ```toml [build] -target = ["", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia"] +target = ["", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia", "riscv64gc-unknown-fuchsia"] [rust] lld = true @@ -201,6 +204,10 @@ cxx = "clang++" [target.aarch64-unknown-fuchsia] cc = "clang" cxx = "clang++" + +[target.riscv64gc-unknown-fuchsia] +cc = "clang" +cxx = "clang++" ``` Though not strictly required, you may also want to use `clang` for your host @@ -237,6 +244,10 @@ export CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot= export CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include" export LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib" export CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib" +export CFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -I${SDK_PATH}/pkg/fdio/include" +export CXXFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -I${SDK_PATH}/pkg/fdio/include" +export LDFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -L${SDK_PATH}/arch/riscv64/lib" +export CARGO_TARGET_RISCV64GC_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/riscv64/sysroot -Lnative=${SDK_PATH}/arch/riscv64/sysroot/lib -Lnative=${SDK_PATH}/arch/riscv64/lib" ``` Finally, the Rust compiler can be built and installed: @@ -281,8 +292,9 @@ hello_fuchsia/ Using your freshly installed `rustc`, you can compile a binary for Fuchsia using the following options: -* `--target x86_64-unknown-fuchsia`/`--target aarch64-unknown-fuchsia`: Targets the Fuchsia - platform of your choice +* `--target x86_64-unknown-fuchsia` / `--target aarch64-unknown-fuchsia` / + `--target riscv64gc-unknown-fuchsia`: Targets the Fuchsia platform of your + choice * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from the SDK * `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot @@ -292,8 +304,8 @@ Putting it all together: ```sh # Configure these for the Fuchsia target of your choice -TARGET_ARCH="" -ARCH="" +TARGET_ARCH="" +ARCH="" rustc \ --target ${TARGET_ARCH} \ @@ -688,12 +700,12 @@ We can then use the script to start our test environment with: ```sh ( \ - source config-env.sh && \ - src/ci/docker/scripts/fuchsia-test-runner.py start \ - --rust-build ${RUST_SRC_PATH}/build \ - --sdk ${SDK_PATH} \ - --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ - --verbose \ + source config-env.sh && \ + src/ci/docker/scripts/fuchsia-test-runner.py start \ + --rust-build ${RUST_SRC_PATH}/build \ + --sdk ${SDK_PATH} \ + --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia|riscv64gc-unknown-fuchsia} \ + --verbose \ ) ``` @@ -707,7 +719,7 @@ run the full `tests/ui` test suite: ( \ source config-env.sh && \ ./x.py \ - --config bootstrap.toml \ + --config bootstrap.toml \ --stage=2 \ test tests/ui \ --target x86_64-unknown-fuchsia \ diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md index c4b56201e7968..266a427ae9618 100644 --- a/src/doc/rustc/src/platform-support/windows-msvc.md +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -5,9 +5,11 @@ Windows MSVC targets. **Tier 1 with host tools:** - `aarch64-pc-windows-msvc`: Windows on ARM64. -- `i686-pc-windows-msvc`: Windows on 32-bit x86. - `x86_64-pc-windows-msvc`: Windows on 64-bit x86. +**Tier 1 without host tools:** +- `i686-pc-windows-msvc`: Windows on 32-bit x86. + ## Target maintainers [@ChrisDenton](https://github.com/ChrisDenton) @@ -26,7 +28,9 @@ Windows 10 or higher is required for client installs, Windows Server 2016 or hig ### Host tooling The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI. -It is **highly** recommended to use the latest version of VS (currently VS 2022). +It is **highly** recommended to use the latest version of VS (currently VS 2026). + +Only 64-bit `*-pc-windows-msvc` targets support host tools. ### Platform details diff --git a/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md b/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md new file mode 100644 index 0000000000000..d208d3243229d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md @@ -0,0 +1,74 @@ +# macroless_generic_const_args + +Enables implementing const items under `#![feature(min_generic_const_args)]` and `#![feature(generic_const_args)]` without the `direct_const_arg!` macro. + +The tracking issue for this feature is: [#162540] + +[#162540]: https://github.com/rust-lang/rust/issues/162540 + +------------------------ + +Warning: This feature is incomplete; its design and syntax may change. + +Related features: +- [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables +support for directly represented const arguments as the rhs of const items without the macro. +- [macroless_generic_const_args]. For a version of this feature that works for const arguments in other +positions + +[min_generic_const_args]: min-generic-const-args.md +[macroless_generic_const_args]: macroless-generic-const-args.md + +## Examples + +Here is an example from [min_generic_const_args]: + +[min_generic_const_args]: min-generic-const-args.md + +```rust,ignore (needs new solver) +#![allow(incomplete_features)] +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = core::direct_const_arg!(N); +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; +} +``` + +Using `#![feature(macroless_const_item_generic_const_args)]` enables you to write the above without the macro: + +```rust,ignore (needs new solver) +#![allow(incomplete_features)] +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = N; +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; +} +``` diff --git a/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md b/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md index 18f4e5cd97a98..6b1205a006d0f 100644 --- a/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md +++ b/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md @@ -10,10 +10,14 @@ The tracking issue for this feature is: [#159006] Warning: This feature is incomplete; its design and syntax may change. -Related features: [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables +Related features: +- [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables support for directly represented const arguments without the macro. +- [macroless_const_item_generic_const_args]. For a version of this feature that works for const arguments +as the right hand side of a const item. [min_generic_const_args]: min-generic-const-args.md +[macroless_const_item_generic_const_args]: macroless-const-item-generic-const-args.md ## Examples diff --git a/tests/mir-opt/building/custom/arbitrary_cast.rs b/tests/mir-opt/building/custom/arbitrary_cast.rs new file mode 100644 index 0000000000000..56e6373756b53 --- /dev/null +++ b/tests/mir-opt/building/custom/arbitrary_cast.rs @@ -0,0 +1,80 @@ +//@ skip-filecheck +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +fn f(x: i32) -> i32 { + x +} + +#[custom_mir(dialect = "built")] +fn reify_fn_ptr() -> fn(i32) -> i32 { + mir! { + { + RET = Cast( + f, + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(Safety::Safe)), + ); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn fn_ptr_to_unsafe(f: fn()) -> unsafe fn() { + mir! { + { + RET = Cast( + f, + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), + ); + Return() + } + } +} + +#[custom_mir(dialect = "runtime")] +fn subtype_fn_ptr(f: fn(&i32)) -> fn(&'static i32) { + mir! { + { + RET = Cast::(f, CastKind::Subtype); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn expose_ptr(p: *const i32) -> usize { + mir! { + { + RET = Cast(p, CastKind::PointerExposeProvenance); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn ptr_from_exposed(p: usize) -> *const i32 { + mir! { + { + RET = Cast(p, CastKind::PointerWithExposedProvenance); + Return() + } + } +} + +fn main() { + assert_eq!(reify_fn_ptr(), f as fn(i32) -> i32); + + let fn_ptr: fn() = || {}; + assert_eq!(fn_ptr as unsafe fn(), fn_ptr_to_unsafe(fn_ptr)); + + let fn_ptr: fn(&i32) = |_| {}; + assert_eq!(fn_ptr as fn(&'static i32), subtype_fn_ptr(fn_ptr)); + + let p = &1; + assert_eq!(p as *const i32 as usize, expose_ptr(p)); + + assert_eq!(ptr_from_exposed(1), 1 as *const i32); +} diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr index 661b9eae9ce9b..0285af4108ef0 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/invalid-doc-attr-2.rs:6:4 | LL | #![doc] diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index d5f663020f3e0..36ad21a54bd51 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -40,6 +40,8 @@ //~^ ERROR malformed #[doc] //~^ ERROR +#[doc()] +//~^ ERROR #[rustc_macro_transparency] //~^ ERROR malformed //~| ERROR attribute cannot be used on @@ -76,8 +78,6 @@ #[crate_name] //~^ ERROR malformed //~| WARN crate-level attribute should be an inner attribute -#[doc] -//~^ ERROR #[target_feature] //~^ ERROR malformed #[export_stable = 1] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 213e017a6be4d..72e7776e09209 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -191,7 +191,7 @@ LL | #[deprecated = 5] | expected a string literal here error[E0539]: malformed `rustc_macro_transparency` attribute input - --> $DIR/malformed-attrs.rs:43:3 + --> $DIR/malformed-attrs.rs:45:3 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL | #[rustc_macro_transparency = "transparent"] | +++++++++++++++ error: the `rustc_macro_transparency` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:43:3 + --> $DIR/malformed-attrs.rs:45:3 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,7 +214,7 @@ LL | #[rustc_macro_transparency] = help: the `rustc_macro_transparency` attribute can only be applied to macro defs error[E0539]: malformed `repr` attribute input - --> $DIR/malformed-attrs.rs:46:3 + --> $DIR/malformed-attrs.rs:48:3 | LL | #[repr] | ^^^^ expected this to be a list @@ -222,7 +222,7 @@ LL | #[repr] = note: for more information, visit error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:48:3 + --> $DIR/malformed-attrs.rs:50:3 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^--- @@ -236,7 +236,7 @@ LL + #[rustc_as_ptr] | error[E0539]: malformed `rustc_align` attribute input - --> $DIR/malformed-attrs.rs:53:3 + --> $DIR/malformed-attrs.rs:55:3 | LL | #[rustc_align] | ^^^^^^^^^^^ expected this to be a list @@ -247,7 +247,7 @@ LL | #[rustc_align()] | ++++++++++++++++++++++ error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:55:3 + --> $DIR/malformed-attrs.rs:57:3 | LL | #[optimize] | ^^^^^^^^ expected this to be a list @@ -262,7 +262,7 @@ LL | #[optimize(speed)] | +++++++ error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:57:3 + --> $DIR/malformed-attrs.rs:59:3 | LL | #[optimize(none, none)] | ^^^^^^^^------------ @@ -282,7 +282,7 @@ LL + #[optimize(speed)] | error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:59:3 + --> $DIR/malformed-attrs.rs:61:3 | LL | #[optimize(none, speed)] | ^^^^^^^^------------- @@ -302,7 +302,7 @@ LL + #[optimize(speed)] | error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:61:3 + --> $DIR/malformed-attrs.rs:63:3 | LL | #[cold = 1] | ^^^^^--- @@ -316,7 +316,7 @@ LL + #[cold] | error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:63:3 + --> $DIR/malformed-attrs.rs:65:3 | LL | #[must_use()] | ^^^^^^^^-- @@ -334,7 +334,7 @@ LL + #[must_use = "reason"] | error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:65:3 + --> $DIR/malformed-attrs.rs:67:3 | LL | #[no_mangle = 1] | ^^^^^^^^^^--- @@ -348,7 +348,7 @@ LL + #[no_mangle] | error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:67:3 + --> $DIR/malformed-attrs.rs:69:3 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^--^ @@ -362,7 +362,7 @@ LL + #[unsafe(naked)] | error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:69:3 + --> $DIR/malformed-attrs.rs:71:3 | LL | #[track_caller()] | ^^^^^^^^^^^^-- @@ -376,7 +376,7 @@ LL + #[track_caller] | error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:71:3 + --> $DIR/malformed-attrs.rs:73:3 | LL | #[export_name()] | ^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + #[export_name = "name"] | error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:73:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^-- @@ -406,7 +406,7 @@ LL | #[used(linker)] | ++++++ error: the `used` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:73:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^ @@ -414,7 +414,7 @@ LL | #[used()] = help: the `used` attribute can only be applied to statics error[E0539]: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:76:3 + --> $DIR/malformed-attrs.rs:78:3 | LL | #[crate_name] | ^^^^^^^^^^ @@ -852,7 +852,7 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/malformed-attrs.rs:41:3 | LL | #[doc] @@ -864,8 +864,14 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` + --> $DIR/malformed-attrs.rs:43:3 + | +LL | #[doc()] + | ^^^^^ + error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:50:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ @@ -875,7 +881,7 @@ LL | #[inline = 5] = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/malformed-attrs.rs:76:1 + --> $DIR/malformed-attrs.rs:78:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ @@ -890,12 +896,6 @@ LL | | } | |_^ = note: requested on the command line with `-W unused-attributes` -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` - --> $DIR/malformed-attrs.rs:79:3 - | -LL | #[doc] - | ^^^ - warning: the `link` attribute cannot be used on functions --> $DIR/malformed-attrs.rs:85:3 | @@ -990,7 +990,7 @@ Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805 For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:50:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ diff --git a/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs new file mode 100644 index 0000000000000..4ae2079a58255 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs @@ -0,0 +1,15 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/156837 +//@ compile-flags: -Znext-solver=globally --crate-type=lib +//@ edition: 2018 + +#![warn(rust_2021_incompatible_closure_captures)] + +async fn get() {} + +fn check() { + let mut v = get(); + (|| match v { + (1, _) => (), + //~^ ERROR mismatched types + })() +} diff --git a/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr new file mode 100644 index 0000000000000..c40d44e1a6dbc --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/opaque-field-projection.rs:12:9 + | +LL | (|| match v { + | - this expression has type `impl Future` +LL | (1, _) => (), + | ^^^^^^ expected future, found `(_, _)` + | + = note: expected opaque type `impl Future` + found tuple `(_, _)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs index 9557c9da80702..181693c365255 100644 --- a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs +++ b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs @@ -2,6 +2,7 @@ #![allow(incomplete_features)] #![feature(macroless_generic_const_args)] +#![feature(macroless_const_item_generic_const_args)] #![feature(generic_const_args, min_generic_const_args)] #![feature(min_adt_const_params)] diff --git a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr index afa00eaeed7e7..9dd229cc46a34 100644 --- a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr +++ b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr @@ -1,5 +1,5 @@ error: the constant `"foo"` is not of type `()` - --> $DIR/const-pattern-field-type-mismatch-162394.rs:16:5 + --> $DIR/const-pattern-field-type-mismatch-162394.rs:17:5 | LL | const A2: Foo = Self::FooA("foo"); | ^^^^^^^^^^^^^ expected `()`, found `&'static str` diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs index 45dcef1f2dc00..ae7c069ea55f5 100644 --- a/tests/ui/const-generics/gca/non-type-equality-ok.rs +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -4,6 +4,7 @@ #![feature( min_generic_const_args, macroless_generic_const_args, + macroless_const_item_generic_const_args, generic_const_args, generic_const_items )] diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.rs b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs index 451806ca6e1db..59fdccf29b7b5 100644 --- a/tests/ui/const-generics/mgca/bad-direct-const-arg.rs +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs @@ -1,8 +1,15 @@ -//! Simple error message test, nothing special here +//@ edition: 2024 + +//! Reject direct const arguments in value/type positions without unrelated brace suggestions. #![feature(min_generic_const_args)] +#![deny(unused_braces)] fn main(x: core::direct_const_arg!(2)) { //~^ ERROR expected type, found `direct_const_arg!()` constant let _ = core::direct_const_arg!(2); //~^ ERROR expected expression, found `direct_const_arg!()` constant + consume({ core::direct_const_arg!(2) }); + //~^ ERROR expected expression, found `direct_const_arg!()` constant } + +fn consume(_: usize) {} diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr index b77791ad5b3ee..d54a2c4400ea7 100644 --- a/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr @@ -1,14 +1,20 @@ error: expected expression, found `direct_const_arg!()` constant - --> $DIR/bad-direct-const-arg.rs:6:13 + --> $DIR/bad-direct-const-arg.rs:9:13 | LL | let _ = core::direct_const_arg!(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: expected expression, found `direct_const_arg!()` constant + --> $DIR/bad-direct-const-arg.rs:11:15 + | +LL | consume({ core::direct_const_arg!(2) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: expected type, found `direct_const_arg!()` constant - --> $DIR/bad-direct-const-arg.rs:4:12 + --> $DIR/bad-direct-const-arg.rs:7:12 | LL | fn main(x: core::direct_const_arg!(2)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index 320c1b5861162..54b1976207236 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -46,7 +46,7 @@ impl ::core::fmt::Debug for Empty { #[automatically_derived] impl ::core::default::Default for Empty { #[inline] - fn default() -> Empty { Empty {} } + fn default() -> Empty { Empty } } #[automatically_derived] impl ::core::hash::Hash for Empty { diff --git a/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr new file mode 100644 index 0000000000000..d49f65acd5a0e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/feature-gate-macroless_const_item_generic_const_args.rs:24:11 + | +LL | let a: [(); <() as Trait>::ASSOC::] + | ------------------------------- expected due to this +LL | = [(); N]; + | ^^^^^^^ expected an array with a size of <() as Trait>::ASSOC::, found one with a size of N + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs new file mode 100644 index 0000000000000..a967dffcd39af --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs @@ -0,0 +1,28 @@ +//@ revisions: macroless macroful +//@[macroless] check-pass +//@ compile-flags: -Znext-solver + +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +#![cfg_attr(macroless, feature(macroless_const_item_generic_const_args))] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = N; +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; + //[macroful]~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout index 689453326c0b5..c75cc7b2179d3 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout @@ -15,8 +15,8 @@ macro lifetime_hygiene /* 0#0 */ { - ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>) - => + ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 + */>) => { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } } fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} diff --git a/tests/ui/lint/unused_braces-issue-154247.fixed b/tests/ui/lint/unused_braces-issue-154247.fixed new file mode 100644 index 0000000000000..08c8999611eb9 --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.fixed @@ -0,0 +1,167 @@ +//@ edition: 2024 +//@ check-pass +//@ run-rustfix + +#![feature(move_expr)] +#![warn(unused_braces)] + +use std::sync::Mutex; + +fn consume(lock: &Mutex>, _value: usize) { + let _guard = lock.lock().unwrap(); +} + +fn consume_int(_: T) {} + +fn make_int() -> usize { + 7 +} + +fn static_int_ref() -> &'static usize { + &7 +} + +struct Point { + _x: usize, +} + +struct Pair { + _x: usize, + _y: usize, +} + +fn make_pair() -> Pair { + Pair { _x: 1, _y: 2 } +} + +macro_rules! make_int_macro { + () => { + make_int() + }; +} + +struct Lockable(Mutex>); + +impl Lockable { + fn update(&self, _value: usize) { + let _guard = self.0.lock().unwrap(); + } + + fn run(&self) { + // These blocks shorten the lifetime of the temporary `MutexGuard`. + consume(&self.0, { self.0.lock().unwrap().len() }); + self.update({ self.0.lock().unwrap().len() }); + consume_int({ [self.0.lock().unwrap().len()] }); + } +} + +fn main() { + let x = 7; + + consume_int(7); + //~^ WARN unnecessary braces + + consume_int(x); + //~^ WARN unnecessary braces + + consume_int(x as usize); + //~^ WARN unnecessary braces + + consume_int((x, 7)); + //~^ WARN unnecessary braces + + consume_int([x, 7]); + //~^ WARN unnecessary braces + + consume_int(!false); + //~^ WARN unnecessary braces + + consume_int(x + 1); + //~^ WARN unnecessary braces + + consume_int([x, 7][0]); + //~^ WARN unnecessary braces + + consume_int(0..x); + //~^ WARN unnecessary braces + + consume_int(const { 7 }); + //~^ WARN unnecessary braces + + consume_int(if x > 0 { x } else { 0 }); + //~^ WARN unnecessary braces + + consume_int(while false {}); + //~^ WARN unnecessary braces + + consume_int(for _ in 0..0 {}); + //~^ WARN unnecessary braces + + consume_int(loop { break x; }); + //~^ WARN unnecessary braces + + consume_int(match x { 0 => 1, _ => x }); + //~^ WARN unnecessary braces + + consume_int(x); + //~^ WARN unnecessary braces + //~| WARN unnecessary braces + + consume_int(|| x); + //~^ WARN unnecessary braces + + let mut y = x; + + consume_int(y += 1); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int(y = x); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int(Point { _x: x }); + //~^ WARN unnecessary braces + + consume_int([x; 2]); + //~^ WARN unnecessary braces + + consume_int(&x); + //~^ WARN unnecessary braces + + let move_expr_closure = || { + consume_int(move(x)); + //~^ WARN unnecessary braces + + consume_int({ move(make_int()) }); + }; + move_expr_closure(); + + Lockable(Mutex::new(vec![1])).update(7); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).update(x as usize); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).run(); + + // These blocks contain calls, borrows, macros, or projections where removing + // the argument block may extend temporaries in Rust 2024. + consume_int({ make_int() }); + consume_int({ make_int() + 1 }); + consume_int({ String::from("abc").len() }); + consume_int({ [make_int(), x] }); + consume_int({ [x, make_int()][0] }); + consume_int({ 0..make_int() }); + consume_int({ Point { _x: make_int() } }); + consume_int({ Pair { _x: x, ..make_pair() } }); + consume_int({ [make_int(); 2] }); + consume_int({ make_int_macro!() }); + consume_int({ format_args!("value") }); + consume_int({ &*static_int_ref() }); + + let point = Point { _x: x }; + consume_int({ point._x }); +} diff --git a/tests/ui/lint/unused_braces-issue-154247.rs b/tests/ui/lint/unused_braces-issue-154247.rs new file mode 100644 index 0000000000000..6d2f28c4d5a2b --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.rs @@ -0,0 +1,167 @@ +//@ edition: 2024 +//@ check-pass +//@ run-rustfix + +#![feature(move_expr)] +#![warn(unused_braces)] + +use std::sync::Mutex; + +fn consume(lock: &Mutex>, _value: usize) { + let _guard = lock.lock().unwrap(); +} + +fn consume_int(_: T) {} + +fn make_int() -> usize { + 7 +} + +fn static_int_ref() -> &'static usize { + &7 +} + +struct Point { + _x: usize, +} + +struct Pair { + _x: usize, + _y: usize, +} + +fn make_pair() -> Pair { + Pair { _x: 1, _y: 2 } +} + +macro_rules! make_int_macro { + () => { + make_int() + }; +} + +struct Lockable(Mutex>); + +impl Lockable { + fn update(&self, _value: usize) { + let _guard = self.0.lock().unwrap(); + } + + fn run(&self) { + // These blocks shorten the lifetime of the temporary `MutexGuard`. + consume(&self.0, { self.0.lock().unwrap().len() }); + self.update({ self.0.lock().unwrap().len() }); + consume_int({ [self.0.lock().unwrap().len()] }); + } +} + +fn main() { + let x = 7; + + consume_int({ 7 }); + //~^ WARN unnecessary braces + + consume_int({ x }); + //~^ WARN unnecessary braces + + consume_int({ x as usize }); + //~^ WARN unnecessary braces + + consume_int({ (x, 7) }); + //~^ WARN unnecessary braces + + consume_int({ [x, 7] }); + //~^ WARN unnecessary braces + + consume_int({ !false }); + //~^ WARN unnecessary braces + + consume_int({ x + 1 }); + //~^ WARN unnecessary braces + + consume_int({ [x, 7][0] }); + //~^ WARN unnecessary braces + + consume_int({ 0..x }); + //~^ WARN unnecessary braces + + consume_int({ const { 7 } }); + //~^ WARN unnecessary braces + + consume_int({ if x > 0 { x } else { 0 } }); + //~^ WARN unnecessary braces + + consume_int({ while false {} }); + //~^ WARN unnecessary braces + + consume_int({ for _ in 0..0 {} }); + //~^ WARN unnecessary braces + + consume_int({ loop { break x; } }); + //~^ WARN unnecessary braces + + consume_int({ match x { 0 => 1, _ => x } }); + //~^ WARN unnecessary braces + + consume_int({ { x } }); + //~^ WARN unnecessary braces + //~| WARN unnecessary braces + + consume_int({ || x }); + //~^ WARN unnecessary braces + + let mut y = x; + + consume_int({ y += 1 }); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int({ y = x }); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int({ Point { _x: x } }); + //~^ WARN unnecessary braces + + consume_int({ [x; 2] }); + //~^ WARN unnecessary braces + + consume_int({ &x }); + //~^ WARN unnecessary braces + + let move_expr_closure = || { + consume_int({ move(x) }); + //~^ WARN unnecessary braces + + consume_int({ move(make_int()) }); + }; + move_expr_closure(); + + Lockable(Mutex::new(vec![1])).update({ 7 }); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).update({ x as usize }); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).run(); + + // These blocks contain calls, borrows, macros, or projections where removing + // the argument block may extend temporaries in Rust 2024. + consume_int({ make_int() }); + consume_int({ make_int() + 1 }); + consume_int({ String::from("abc").len() }); + consume_int({ [make_int(), x] }); + consume_int({ [x, make_int()][0] }); + consume_int({ 0..make_int() }); + consume_int({ Point { _x: make_int() } }); + consume_int({ Pair { _x: x, ..make_pair() } }); + consume_int({ [make_int(); 2] }); + consume_int({ make_int_macro!() }); + consume_int({ format_args!("value") }); + consume_int({ &*static_int_ref() }); + + let point = Point { _x: x }; + consume_int({ point._x }); +} diff --git a/tests/ui/lint/unused_braces-issue-154247.stderr b/tests/ui/lint/unused_braces-issue-154247.stderr new file mode 100644 index 0000000000000..5d5fd1c95513a --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.stderr @@ -0,0 +1,319 @@ +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:61:17 + | +LL | consume_int({ 7 }); + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/unused_braces-issue-154247.rs:6:9 + | +LL | #![warn(unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - consume_int({ 7 }); +LL + consume_int(7); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:64:17 + | +LL | consume_int({ x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x }); +LL + consume_int(x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:67:17 + | +LL | consume_int({ x as usize }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x as usize }); +LL + consume_int(x as usize); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:70:17 + | +LL | consume_int({ (x, 7) }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ (x, 7) }); +LL + consume_int((x, 7)); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:73:17 + | +LL | consume_int({ [x, 7] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x, 7] }); +LL + consume_int([x, 7]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:76:17 + | +LL | consume_int({ !false }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ !false }); +LL + consume_int(!false); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:79:17 + | +LL | consume_int({ x + 1 }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x + 1 }); +LL + consume_int(x + 1); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:82:17 + | +LL | consume_int({ [x, 7][0] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x, 7][0] }); +LL + consume_int([x, 7][0]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:85:17 + | +LL | consume_int({ 0..x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ 0..x }); +LL + consume_int(0..x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:88:17 + | +LL | consume_int({ const { 7 } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ const { 7 } }); +LL + consume_int(const { 7 }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:91:17 + | +LL | consume_int({ if x > 0 { x } else { 0 } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ if x > 0 { x } else { 0 } }); +LL + consume_int(if x > 0 { x } else { 0 }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:94:17 + | +LL | consume_int({ while false {} }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ while false {} }); +LL + consume_int(while false {}); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:97:17 + | +LL | consume_int({ for _ in 0..0 {} }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ for _ in 0..0 {} }); +LL + consume_int(for _ in 0..0 {}); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:100:17 + | +LL | consume_int({ loop { break x; } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ loop { break x; } }); +LL + consume_int(loop { break x; }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:103:17 + | +LL | consume_int({ match x { 0 => 1, _ => x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ match x { 0 => 1, _ => x } }); +LL + consume_int(match x { 0 => 1, _ => x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:106:17 + | +LL | consume_int({ { x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ { x } }); +LL + consume_int({ x }); + | + +warning: unnecessary braces around block return value + --> $DIR/unused_braces-issue-154247.rs:106:19 + | +LL | consume_int({ { x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ { x } }); +LL + consume_int({ x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:110:17 + | +LL | consume_int({ || x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ || x }); +LL + consume_int(|| x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:115:17 + | +LL | consume_int({ y += 1 }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ y += 1 }); +LL + consume_int(y += 1); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:120:17 + | +LL | consume_int({ y = x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ y = x }); +LL + consume_int(y = x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:125:17 + | +LL | consume_int({ Point { _x: x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ Point { _x: x } }); +LL + consume_int(Point { _x: x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:128:17 + | +LL | consume_int({ [x; 2] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x; 2] }); +LL + consume_int([x; 2]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:131:17 + | +LL | consume_int({ &x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ &x }); +LL + consume_int(&x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:135:21 + | +LL | consume_int({ move(x) }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ move(x) }); +LL + consume_int(move(x)); + | + +warning: unnecessary braces around method argument + --> $DIR/unused_braces-issue-154247.rs:142:42 + | +LL | Lockable(Mutex::new(vec![1])).update({ 7 }); + | ^^ ^^ + | +help: remove these braces + | +LL - Lockable(Mutex::new(vec![1])).update({ 7 }); +LL + Lockable(Mutex::new(vec![1])).update(7); + | + +warning: unnecessary braces around method argument + --> $DIR/unused_braces-issue-154247.rs:145:42 + | +LL | Lockable(Mutex::new(vec![1])).update({ x as usize }); + | ^^ ^^ + | +help: remove these braces + | +LL - Lockable(Mutex::new(vec![1])).update({ x as usize }); +LL + Lockable(Mutex::new(vec![1])).update(x as usize); + | + +warning: 26 warnings emitted + diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 693b16c610bb2..0dcdee9ccc990 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -16,7 +16,7 @@ LL | #[link = ""] | = note: for more information, visit -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/malformed-regressions.rs:3:3 | LL | #[doc]