diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1245d48975470..fb42cfea30b41 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -98,7 +98,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -232,10 +232,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), None => self.lower_expr_closure( + attrs, binder, *capture_clause, e.id, - expr_hir_id, *constness, *movability, fn_decl, @@ -1052,10 +1052,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, + attrs: &[rustc_hir::Attribute], binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - closure_hir_id: hir::HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -1067,15 +1067,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; + + let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); + // FIXME(contracts): Support contracts on closures? let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 189c82b614c2d..d097e3cbaa822 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -675,7 +675,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bodies = SortedMap::from_presorted_elements(bodies); // Don't hash unless necessary, because it's expensive. - let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) = + let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } = self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 35ff48cb5f24b..aa8046add7145 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -32,6 +32,11 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions -> *[other] valid forms for the attribute are {$suggestions} } +attr_parsing_invalid_macro_export_arguments = {$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + } + attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs new file mode 100644 index 0000000000000..ab9330216f6c6 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -0,0 +1,15 @@ +//! Attributes that can be found in function body. + +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Symbol, sym}; + +use super::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; + +pub(crate) struct CoroutineParser; + +impl NoArgsAttributeParser for CoroutineParser { + const PATH: &[Symbol] = &[sym::coroutine]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); +} diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 886f7a889d303..122d80cca046e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,10 +1,14 @@ use rustc_errors::DiagArgValue; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; +use rustc_hir::lints::AttributeLintKind; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; -use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate}; +use crate::attributes::{ + AcceptMapping, AttributeOrder, AttributeParser, NoArgsAttributeParser, OnDuplicate, + SingleAttributeParser, +}; use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; @@ -113,3 +117,58 @@ impl AttributeParser for MacroUseParser { Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) } } + +pub(crate) struct MacroExportParser; + +impl SingleAttributeParser for crate::attributes::macro_attrs::MacroExportParser { + const PATH: &[Symbol] = &[sym::macro_export]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word, List: "local_inner_macros"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let suggestions = + || >::TEMPLATE.suggestions(false, "macro_export"); + let local_inner_macros = match args { + ArgParser::NoArgs => false, + ArgParser::List(list) => { + let Some(l) = list.single() else { + let span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidMacroExportArguments { + suggestions: suggestions(), + }, + span, + ); + return None; + }; + match l.meta_item().and_then(|i| i.path().word_sym()) { + Some(sym::local_inner_macros) => true, + _ => { + let span = cx.attr_span; + cx.emit_lint( + AttributeLintKind::InvalidMacroExportArguments { + suggestions: suggestions(), + }, + span, + ); + return None; + } + } + } + ArgParser::NameValue(_) => { + let span = cx.attr_span; + let suggestions = suggestions(); + cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + span, + }); + return None; + } + }; + Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index c574ef78bdf79..f7946ade6d2b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -26,6 +26,7 @@ use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; +pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 767d19bd23406..5018bf5ca0d31 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -16,6 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; +use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, @@ -33,7 +34,7 @@ use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, }; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; -use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser}; +use crate::attributes::macro_attrs::{MacroEscapeParser, MacroExportParser, MacroUseParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::non_exhaustive::NonExhaustiveParser; @@ -165,6 +166,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, @@ -185,6 +187,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 22f5531bc8079..359b0ef0dd12c 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -34,5 +34,17 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi *first_span, session_diagnostics::EmptyAttributeList { attr_span: *first_span }, ), + AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter + .emit_node_span_lint( + rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS, + *id, + *span, + session_diagnostics::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + }, + ), } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 162fbf3d6e249..b69fbf61185d7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1011,11 +1011,12 @@ fn link_natively( (Strip::Debuginfo, _) => { strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"]) } - // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) + + // Per the manpage, --discard-all is the maximum safe strip level for dynamic libraries. (#93988) ( Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib, - ) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]), + ) => strip_with_external_utility(sess, stripcmd, out_filename, &["--discard-all"]), (Strip::Symbols, _) => { strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"]) } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7f54a47327af8..452311762a26f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -443,6 +443,35 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code if tcx.should_inherit_track_caller(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } + + // Foreign items by default use no mangling for their symbol name. + if tcx.is_foreign_item(did) { + // There's a few exceptions to this rule though: + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way + // both for exports and imports through foreign items. This is handled further, + // during symbol mangling logic/ + } else if codegen_fn_attrs.link_name.is_some() { + // * This can be overridden with the `#[link_name]` attribute + } else if tcx.sess.target.is_like_wasm + && tcx.wasm_import_module_map(LOCAL_CRATE).contains_key(&did.into()) + { + // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the + // same-named symbol when imported from different wasm modules will get + // hooked up incorrectly. As a result foreign symbols, on the wasm target, + // with a wasm import module, get mangled. Additionally our codegen will + // deduplicate symbols based purely on the symbol name, but for wasm this + // isn't quite right because the same-named symbol on wasm can come from + // different modules. For these reasons if `#[link(wasm_import_module)]` + // is present we mangle everything on wasm because the demangled form will + // show up in the `wasm-import-name` custom attribute in LLVM IR. + // + // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 + } else { + // if none of the exceptions apply; apply no_mangle + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + } + } } fn check_result( diff --git a/compiler/rustc_error_codes/src/error_codes/E0562.md b/compiler/rustc_error_codes/src/error_codes/E0562.md index 95f038df56d63..af7b219fb1207 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0562.md +++ b/compiler/rustc_error_codes/src/error_codes/E0562.md @@ -1,5 +1,4 @@ -Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function and inherent impl return types. +`impl Trait` is only allowed as a function return and argument type. Erroneous code example: @@ -14,7 +13,7 @@ fn main() { } ``` -Make sure `impl Trait` only appears in return-type position. +Make sure `impl Trait` appears in a function signature. ``` fn count_to_n(n: usize) -> impl Iterator { @@ -28,6 +27,6 @@ fn main() { } ``` -See [RFC 1522] for more details. +See the [reference] for more details on `impl Trait`. -[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md +[reference]: https://doc.rust-lang.org/stable/reference/types/impl-trait.html diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 1a9832b2fe26a..e1fd184533f6f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -910,9 +910,9 @@ impl SyntaxExtension { let allow_internal_unsafe = ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some(); - let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export) - .and_then(|macro_export| macro_export.meta_item_list()) - .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros)); + let local_inner_macros = + *find_attr!(attrs, AttributeKind::MacroExport {local_inner_macros: l, ..} => l) + .unwrap_or(&false); let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local); tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 80f5e6177f758..22338ad22f901 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -297,6 +297,9 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), + /// Represents `#[coroutine]`. + Coroutine(Span), + /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), @@ -360,6 +363,9 @@ pub enum AttributeKind { /// Represents `#[macro_escape]`. MacroEscape(Span), + /// Represents [`#[macro_export}`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path). + MacroExport { span: Span, local_inner_macros: bool }, + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index bbdecb2986e00..5408dfdde6557 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coroutine(..) => No, Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, @@ -46,6 +47,7 @@ impl AttributeKind { LinkSection { .. } => Yes, // Needed for rustdoc LoopMatch(..) => No, MacroEscape(..) => No, + MacroExport { .. } => Yes, MacroTransparency(..) => Yes, MacroUse { .. } => No, Marker(..) => No, diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index c55a41eb2b76b..b096c671edabe 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -31,7 +31,22 @@ pub struct AttributeLint { #[derive(Clone, Debug, HashStable_Generic)] pub enum AttributeLintKind { - UnusedDuplicate { this: Span, other: Span, warning: bool }, - IllFormedAttributeInput { suggestions: Vec }, - EmptyAttribute { first_span: Span }, + UnusedDuplicate { + this: Span, + other: Span, + warning: bool, + }, + IllFormedAttributeInput { + suggestions: Vec, + }, + EmptyAttribute { + first_span: Span, + }, + + /// Copy of `IllFormedAttributeInput` + /// specifically for the `invalid_macro_export_arguments` lint until that is removed, + /// see + InvalidMacroExportArguments { + suggestions: Vec, + }, } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 8d9f7eaf17746..5a182dabebb85 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that // something which derefs to `Self` actually implements the trait and the caller // wanted to make a static dispatch on it but forgot to import the trait. - // See test `tests/ui/issue-35976.rs`. + // See test `tests/ui/issues/issue-35976.rs`. // // In that case, we'll error anyway, but we'll also re-run the search with all traits // in scope, and if we find another method which can be used, we'll output an diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1f3969bd93c3c..3ca3b56b87e01 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2051,7 +2051,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// probe. This will result in a pending obligation so when more type-info is available we can /// make the final decision. /// - /// Example (`tests/ui/method-two-trait-defer-resolution-1.rs`): + /// Example (`tests/ui/methods/method-two-trait-defer-resolution-1.rs`): /// /// ```ignore (illustrative) /// trait Foo { ... } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 69fe7fe83ffda..4d0c0c94a8138 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped + .ret_ty = return type of the {$fn_kind} is `{$ret_ty}` + .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind} + .created_at = dangling pointer created here + .note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned + lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 9e19949c3b6ee..af4457f4314b9 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -1,13 +1,14 @@ use rustc_ast::visit::{visit_opt, walk_list}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::{Span, sym}; -use crate::lints::DanglingPointersFromTemporaries; +use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -42,6 +43,36 @@ declare_lint! { "detects getting a pointer from a temporary" } +declare_lint! { + /// The `dangling_pointers_from_locals` lint detects getting a pointer to data + /// of a local that will be dropped at the end of the function. + /// + /// ### Example + /// + /// ```rust + /// fn f() -> *const u8 { + /// let x = 0; + /// &x // returns a dangling ptr to `x` + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Returning a pointer from a local value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_LOCALS, + Warn, + "detects returning a pointer from a local variable" +} + /// FIXME: false negatives (i.e. the lint is not emitted when it should be) /// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` @@ -53,20 +84,123 @@ declare_lint! { #[derive(Clone, Copy, Default)] pub(crate) struct DanglingPointers; -impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]); // This skips over const blocks, but they cannot use or return a dangling pointer anyways. impl<'tcx> LateLintPass<'tcx> for DanglingPointers { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, _: Span, - _: LocalDefId, + def_id: LocalDefId, ) { - DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body); + + if let FnRetTy::Return(ret_ty) = &fn_decl.output + && let TyKind::Ptr(_) = ret_ty.kind + { + // get the return type of the function or closure + let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() { + ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(), + ty::Closure(_, args) => args.as_closure().sig(), + _ => return, + }; + let ty = ty.output(); + + // this type is only used for layout computation and pretty-printing, neither of them rely on regions + let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); + + // verify that we have a pointer type + let inner_ty = match ty.kind() { + ty::RawPtr(inner_ty, _) => *inner_ty, + _ => return, + }; + + if cx + .tcx + .layout_of(cx.typing_env().as_query_input(inner_ty)) + .is_ok_and(|layout| !layout.is_1zst()) + { + let dcx = &DanglingPointerLocalContext { + body: def_id, + fn_ret: ty, + fn_ret_span: ret_ty.span, + fn_ret_inner: inner_ty, + fn_kind: match fn_kind { + FnKind::ItemFn(..) => "function", + FnKind::Method(..) => "method", + FnKind::Closure => "closure", + }, + }; + + // look for `return`s + DanglingPointerReturnSearcher { cx, dcx }.visit_body(body); + + // analyze implicit return expression + if let ExprKind::Block(block, None) = &body.value.kind + && let innermost_block = block.innermost_block() + && let Some(expr) = innermost_block.expr + { + lint_addr_of_local(cx, dcx, expr); + } + } + } + } +} + +struct DanglingPointerLocalContext<'tcx> { + body: LocalDefId, + fn_ret: Ty<'tcx>, + fn_ret_span: Span, + fn_ret_inner: Ty<'tcx>, + fn_kind: &'static str, +} + +struct DanglingPointerReturnSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + dcx: &'lcx DanglingPointerLocalContext<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Ret(Some(expr)) = expr.kind { + lint_addr_of_local(self.cx, self.dcx, expr); + } + walk_expr(self, expr) + } +} + +/// Look for `&` pattern and emit lint for it +fn lint_addr_of_local<'a>( + cx: &LateContext<'a>, + dcx: &DanglingPointerLocalContext<'a>, + expr: &'a Expr<'a>, +) { + // peel casts as they do not interest us here, we want the inner expression. + let (inner, _) = super::utils::peel_casts(cx, expr); + + if let ExprKind::AddrOf(_, _, inner_of) = inner.kind + && let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind + && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) + && cx.tcx.hir_enclosing_body_owner(from) == dcx.body + { + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_LOCALS, + expr.hir_id, + expr.span, + DanglingPointersFromLocals { + ret_ty: dcx.fn_ret, + ret_ty_span: dcx.fn_ret_span, + fn_kind: dcx.fn_kind, + local_var: cx.tcx.hir_span(from), + local_var_name: cx.tcx.hir_ident(from), + local_var_ty: dcx.fn_ret_inner, + created_at: (expr.hir_id != inner.hir_id).then_some(inner.span), + }, + ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd8d0f832aa47..ef63c0dee8c2e 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub temporary_span: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_dangling_pointers_from_locals)] +#[note] +pub(crate) struct DanglingPointersFromLocals<'tcx> { + pub ret_ty: Ty<'tcx>, + #[label(lint_ret_ty)] + pub ret_ty_span: Span, + pub fn_kind: &'static str, + #[label(lint_local_var)] + pub local_var: Span, + pub local_var_name: Ident, + pub local_var_ty: Ty<'tcx>, + #[label(lint_created_at)] + pub created_at: Option, +} + // multiple_supertrait_upcastable.rs #[derive(LintDiagnostic)] #[diag(lint_multiple_supertrait_upcastable)] diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b877f909fc029..d0254eccb39ef 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,11 +1,12 @@ use rustc_errors::MultiSpan; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; -use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind}; +use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind, find_attr}; use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::{ExpnKind, MacroKind, Span, kw, sym}; +use rustc_span::{ExpnKind, MacroKind, Span, kw}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -241,7 +242,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { ) } ItemKind::Macro(_, _macro, MacroKind::Bang) - if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => + if find_attr!( + cx.tcx.get_all_attrs(item.owner_id.def_id), + AttributeKind::MacroExport { .. } + ) => { cx.emit_span_lint( NON_LOCAL_DEFINITIONS, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3b84c6b611016..9e5ceb8977c13 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4188,8 +4188,13 @@ declare_lint! { /// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`. /// pub INVALID_MACRO_EXPORT_ARGUMENTS, - Warn, + Deny, "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseError, + reference: "issue #57571 ", + report_in_deps: true, + }; } declare_lint! { diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 6c07e49734ab0..67bc89692ff79 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -174,36 +174,52 @@ impl<'tcx> TyCtxt<'tcx> { attrs: &SortedMap, delayed_lints: &[DelayedLint], define_opaque: Option<&[(Span, LocalDefId)]>, - ) -> (Option, Option, Option) { - if self.needs_crate_hash() { - self.with_stable_hashing_context(|mut hcx| { - let mut stable_hasher = StableHasher::new(); - node.hash_stable(&mut hcx, &mut stable_hasher); - // Bodies are stored out of line, so we need to pull them explicitly in the hash. - bodies.hash_stable(&mut hcx, &mut stable_hasher); - let h1 = stable_hasher.finish(); - - let mut stable_hasher = StableHasher::new(); - attrs.hash_stable(&mut hcx, &mut stable_hasher); - - // Hash the defined opaque types, which are not present in the attrs. - define_opaque.hash_stable(&mut hcx, &mut stable_hasher); - - let h2 = stable_hasher.finish(); - - // hash lints emitted during ast lowering - let mut stable_hasher = StableHasher::new(); - delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); - let h3 = stable_hasher.finish(); - - (Some(h1), Some(h2), Some(h3)) - }) - } else { - (None, None, None) + ) -> Hashes { + if !self.needs_crate_hash() { + return Hashes { + opt_hash_including_bodies: None, + attrs_hash: None, + delayed_lints_hash: None, + }; } + + self.with_stable_hashing_context(|mut hcx| { + let mut stable_hasher = StableHasher::new(); + node.hash_stable(&mut hcx, &mut stable_hasher); + // Bodies are stored out of line, so we need to pull them explicitly in the hash. + bodies.hash_stable(&mut hcx, &mut stable_hasher); + let h1 = stable_hasher.finish(); + + let mut stable_hasher = StableHasher::new(); + attrs.hash_stable(&mut hcx, &mut stable_hasher); + + // Hash the defined opaque types, which are not present in the attrs. + define_opaque.hash_stable(&mut hcx, &mut stable_hasher); + + let h2 = stable_hasher.finish(); + + // hash lints emitted during ast lowering + let mut stable_hasher = StableHasher::new(); + delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); + let h3 = stable_hasher.finish(); + + Hashes { + opt_hash_including_bodies: Some(h1), + attrs_hash: Some(h2), + delayed_lints_hash: Some(h3), + } + }) } } +/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary. +#[derive(Clone, Copy, Debug)] +pub struct Hashes { + pub opt_hash_including_bodies: Option, + pub attrs_hash: Option, + pub delayed_lints_hash: Option, +} + pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 94384e64afd15..3b0f4b7a3cdba 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -192,6 +192,10 @@ impl CodegenFnAttrs { /// * `#[export_name(...)]` is present /// * `#[linkage]` is present /// + /// Note that this returns true for foreign items. + /// However, in some places that care about `contains_extern_indicator`, foreign items + /// (in an `extern` block) should explicitly be ignored. + /// /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint. pub fn contains_extern_indicator(&self) -> bool { self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f4ee3d7971c3f..d583c5d496edc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1381,7 +1381,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _, _) = + let rustc_middle::hir::Hashes { opt_hash_including_bodies, .. } = self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6a28fe2617edf..f9c0f43803bc8 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -399,10 +399,6 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} -passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument - -passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments - passes_lang_item_fn = {$name -> [panic_impl] `#[panic_handler]` *[other] `{$name}` lang item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ede74bdc0df62..0fe47b5a14f7a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -38,9 +38,8 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_session::lint; use rustc_session::lint::builtin::{ - CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, - MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, - USELESS_DEPRECATED, + CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES, + MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -292,6 +291,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcBuiltinMacro { .. } | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } + Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => { + self.check_macro_export(hir_id, *span, target) + } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } @@ -325,6 +327,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { self.check_coverage(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { + self.check_coroutine(attr_span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -384,16 +389,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), - [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::should_panic, ..] => { self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn) } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok @@ -563,7 +564,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Fn | Target::Closure - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {} + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. + if let Some(did) = hir_id.as_owner() + && self.tcx.def_kind(did).has_codegen_attrs() + && kind != &InlineAttr::Never + { + let attrs = self.tcx.codegen_fn_attrs(did); + // Not checking naked as `#[inline]` is forbidden for naked functions anyways. + if attrs.contains_extern_indicator() { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::InlineIgnoredForExported {}, + ); + } + } + } Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -590,23 +608,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span }); } } - - // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. - if let Some(did) = hir_id.as_owner() - && self.tcx.def_kind(did).has_codegen_attrs() - && kind != &InlineAttr::Never - { - let attrs = self.tcx.codegen_fn_attrs(did); - // Not checking naked as `#[inline]` is forbidden for naked functions anyways. - if attrs.contains_extern_indicator() { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::InlineIgnoredForExported {}, - ); - } - } } /// Checks that `#[coverage(..)]` is applied to a function/closure/method, @@ -2433,32 +2434,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { + fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) { if target != Target::MacroDef { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::MacroExport::Normal, ); - } else if let Some(meta_item_list) = attr.meta_item_list() - && !meta_item_list.is_empty() - { - if meta_item_list.len() > 1 { - self.tcx.emit_node_span_lint( - INVALID_MACRO_EXPORT_ARGUMENTS, - hir_id, - attr.span(), - errors::MacroExport::TooManyItems, - ); - } else if !meta_item_list[0].has_name(sym::local_inner_macros) { - self.tcx.emit_node_span_lint( - INVALID_MACRO_EXPORT_ARGUMENTS, - hir_id, - meta_item_list[0].span(), - errors::MacroExport::InvalidArgument, - ); - } } else { // special case when `#[macro_export]` is applied to a macro 2.0 let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro(); @@ -2468,7 +2451,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::MacroExport::OnDeclMacro, ); } @@ -2652,11 +2635,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr: &Attribute, target: Target) { + fn check_coroutine(&self, attr_span: Span, target: Target) { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr_span }); } } } @@ -2821,7 +2804,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // In the long run, the checks should be harmonized. if let ItemKind::Macro(_, macro_def, _) = item.kind { let def_id = item.owner_id.to_def_id(); - if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) { + if macro_def.macro_rules + && !find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. }) + { check_non_exported_macro_for_invalid_attrs(self.tcx, item); } } @@ -2951,7 +2936,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // which were unsuccessfully resolved due to cannot determine // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ - sym::macro_export, sym::rustc_main, sym::derive, sym::test, @@ -2976,6 +2960,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { (*span, sym::path) } else if let Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) = attr { (*span, sym::automatically_derived) + } else if let Attribute::Parsed(AttributeKind::MacroExport { span, .. }) = attr { + (*span, sym::macro_export) } else { continue; }; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index a90d1af87ca19..4be3ad2562027 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -694,15 +694,17 @@ fn has_allow_dead_code_or_lang_attr( } fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.def_kind(def_id).has_codegen_attrs() && { - let cg_attrs = tcx.codegen_fn_attrs(def_id); - - // #[used], #[no_mangle], #[export_name], etc also keeps the item alive - // forcefully, e.g., for placing it in a specific section. - cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - } + tcx.def_kind(def_id).has_codegen_attrs() + && { + let cg_attrs = tcx.codegen_fn_attrs(def_id); + + // #[used], #[no_mangle], #[export_name], etc also keeps the item alive + // forcefully, e.g., for placing it in a specific section. + cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + } + && !tcx.is_foreign_item(def_id) } if has_allow_expect_dead_code(tcx, def_id) { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c6ab6b0d60179..ed9973df0e1d2 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -786,12 +786,6 @@ pub(crate) enum MacroExport { #[diag(passes_macro_export_on_decl_macro)] #[note] OnDeclMacro, - - #[diag(passes_invalid_macro_export_arguments)] - InvalidArgument, - - #[diag(passes_invalid_macro_export_arguments_too_many_items)] - TooManyItems, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 2f78c22c7483b..f3af2229f4292 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -183,7 +183,8 @@ impl<'tcx> ReachableContext<'tcx> { } else { CodegenFnAttrs::EMPTY }; - let is_extern = codegen_attrs.contains_extern_indicator(); + let is_extern = + codegen_attrs.contains_extern_indicator() && !self.tcx.is_foreign_item(search_item); if is_extern { self.reachable_symbols.insert(search_item); } @@ -417,12 +418,17 @@ fn check_item<'tcx>( } fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + if tcx.is_foreign_item(def_id) { + return false; + } + // Anything which has custom linkage gets thrown on the worklist no // matter where it is in the crate, along with "special std symbols" // which are currently akin to allocator symbols. if !tcx.def_kind(def_id).has_codegen_attrs() { return false; } + let codegen_attrs = tcx.codegen_fn_attrs(def_id); codegen_attrs.contains_extern_indicator() // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 6bcb7f6e093c4..d0549b91680a1 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -218,32 +218,9 @@ fn compute_symbol_name<'tcx>( } } - // Foreign items by default use no mangling for their symbol name. There's a - // few exceptions to this rule though: - // - // * This can be overridden with the `#[link_name]` attribute - // - // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the - // same-named symbol when imported from different wasm modules will get - // hooked up incorrectly. As a result foreign symbols, on the wasm target, - // with a wasm import module, get mangled. Additionally our codegen will - // deduplicate symbols based purely on the symbol name, but for wasm this - // isn't quite right because the same-named symbol on wasm can come from - // different modules. For these reasons if `#[link(wasm_import_module)]` - // is present we mangle everything on wasm because the demangled form will - // show up in the `wasm-import-name` custom attribute in LLVM IR. - // - // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way - // both for exports and imports through foreign items. This is handled above. - // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 - if tcx.is_foreign_item(def_id) - && (!tcx.sess.target.is_like_wasm - || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)) - { - if let Some(name) = attrs.link_name { - return name.to_string(); - } - return tcx.item_name(def_id).to_string(); + if let Some(name) = attrs.link_name { + // Use provided name + return name.to_string(); } if let Some(name) = attrs.export_name { diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index a7b915c48455b..202d81df5aec3 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -357,7 +357,7 @@ impl TypeVisitor for ValidateBoundVars { pub struct EarlyBinder { value: T, #[derive_where(skip(Debug))] - _tcx: PhantomData, + _tcx: PhantomData I>, } /// For early binders, you should first call `instantiate` before using any visitors. diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bd5b4e21baa0f..402634e49b37e 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_clike_unportable_variant)] + use crate::num::NonZero; use crate::ub_checks::assert_unsafe_precondition; use crate::{cmp, fmt, hash, mem, num}; @@ -241,7 +243,7 @@ impl const Default for Alignment { #[cfg(target_pointer_width = "16")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u16)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -263,7 +265,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "32")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u32)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -301,7 +303,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "64")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u64)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 77301d7228ead..fd06a3b540cda 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -294,6 +294,8 @@ #![feature(f128)] #![feature(ffi_const)] #![feature(formatting_options)] +#![feature(hash_map_internals)] +#![feature(hash_map_macro)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_advance_by)] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 25e2b7ea13703..254570ae9c836 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -379,3 +379,77 @@ macro_rules! dbg { ($($crate::dbg!($val)),+,) }; } + +#[doc(hidden)] +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_internals", issue = "none")] +macro_rules! repetition_utils { + (@count $($tokens:tt),*) => {{ + [$($crate::repetition_utils!(@replace $tokens => ())),*].len() + }}; + + (@replace $x:tt => $y:tt) => { $y } +} + +/// Creates a [`HashMap`] containing the arguments. +/// +/// `hash_map!` allows specifying the entries that make +/// up the [`HashMap`] where the key and value are separated by a `=>`. +/// +/// The entries are separated by commas with a trailing comma being allowed. +/// +/// It is semantically equivalent to using repeated [`HashMap::insert`] +/// on a newly created hashmap. +/// +/// `hash_map!` will attempt to avoid repeated reallocations by +/// using [`HashMap::with_capacity`]. +/// +/// # Examples +/// +/// ```rust +/// #![feature(hash_map_macro)] +/// +/// let map = hash_map! { +/// "key" => "value", +/// "key1" => "value1" +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// assert_eq!(map.get("key1"), Some(&"value1")); +/// assert!(map.get("brrrrrrooooommm").is_none()); +/// ``` +/// +/// And with a trailing comma +/// +///```rust +/// #![feature(hash_map_macro)] +/// +/// let map = hash_map! { +/// "key" => "value", // notice the , +/// }; +/// +/// assert_eq!(map.get("key"), Some(&"value")); +/// ``` +/// +/// The key and value are moved into the HashMap. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`HashMap::insert`]: crate::collections::HashMap::insert +/// [`HashMap::with_capacity`]: crate::collections::HashMap::with_capacity +#[macro_export] +#[allow_internal_unstable(hash_map_internals)] +#[unstable(feature = "hash_map_macro", issue = "144032")] +macro_rules! hash_map { + () => {{ + $crate::collections::HashMap::new() + }}; + + ( $( $key:expr => $value:expr ),* $(,)? ) => {{ + let mut map = $crate::collections::HashMap::with_capacity( + const { $crate::repetition_utils!(@count $($key),*) } + ); + $( map.insert($key, $value); )* + map + }} +} diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index e2f86b8a8549e..3304c61380993 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -6,6 +6,8 @@ use std::collections::{BTreeMap, VecDeque}; use encode::{bitmap_to_string, write_vlqhex_to_string}; use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::sym; @@ -421,16 +423,17 @@ pub(crate) fn build_index( if fqp.last() != Some(&item.name) { return None; } - let path = - if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) { - // `#[macro_export]` always exports to the crate root. - tcx.crate_name(defid.krate).to_string() - } else { - if fqp.len() < 2 { - return None; - } - join_path_syms(&fqp[..fqp.len() - 1]) - }; + let path = if item.ty == ItemType::Macro + && find_attr!(tcx.get_all_attrs(defid), AttributeKind::MacroExport { .. }) + { + // `#[macro_export]` always exports to the crate root. + tcx.crate_name(defid.krate).to_string() + } else { + if fqp.len() < 2 { + return None; + } + join_path_syms(&fqp[..fqp.len() - 1]) + }; if path == item.path { return None; } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f966d9265628b..dd54b4e30d15c 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -908,12 +908,8 @@ fn maybe_from_hir_attr( hir::Attribute::Parsed(kind) => kind, hir::Attribute::Unparsed(_) => { - return Some(if attr.has_name(sym::macro_export) { - Attribute::MacroExport - // FIXME: We should handle `#[doc(hidden)]`. - } else { - other_attr(tcx, attr) - }); + // FIXME: We should handle `#[doc(hidden)]`. + return Some(other_attr(tcx, attr)); } }; @@ -921,6 +917,7 @@ fn maybe_from_hir_attr( AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), + AK::MacroExport { .. } => Attribute::MacroExport, AK::MustUse { reason, span: _ } => { Attribute::MustUse { reason: reason.map(|s| s.to_string()) } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 3388ae46f056c..525d05b6a9860 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,9 +2,10 @@ use std::mem; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::find_attr; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; use tracing::debug; use crate::clean::utils::inherits_doc_hidden; @@ -114,7 +115,7 @@ impl DocFolder for Stripper<'_, '_> { // If the macro has the `#[macro_export]` attribute, it means it's accessible at the // crate level so it should be handled differently. clean::MacroItem(..) => { - i.attrs.other_attrs.iter().any(|attr| attr.has_name(sym::macro_export)) + find_attr!(&i.attrs.other_attrs, AttributeKind::MacroExport { .. }) } _ => false, }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 9058277d72eea..428149b95f468 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,10 +5,11 @@ use std::mem; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; use rustc_hir::intravisit::{Visitor, walk_body, walk_item}; -use rustc_hir::{CRATE_HIR_ID, Node}; +use rustc_hir::{CRATE_HIR_ID, Node, find_attr}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -167,7 +168,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if !child.reexport_chain.is_empty() && let Res::Def(DefKind::Macro(_), def_id) = child.res && let Some(local_def_id) = def_id.as_local() - && self.cx.tcx.has_attr(def_id, sym::macro_export) + && find_attr!(self.cx.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. }) && inserted.insert(def_id) { let item = self.cx.tcx.hir_expect_item(local_def_id); @@ -407,7 +408,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { || match item.kind { hir::ItemKind::Impl(..) => true, hir::ItemKind::Macro(_, _, MacroKind::Bang) => { - self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) + find_attr!(self.cx.tcx.get_all_attrs(item.owner_id.def_id), AttributeKind::MacroExport{..}) } _ => false, } @@ -525,7 +526,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let def_id = item.owner_id.to_def_id(); let is_macro_2_0 = !macro_def.macro_rules; - let nonexported = !tcx.has_attr(def_id, sym::macro_export); + let nonexported = + !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. }); if is_macro_2_0 || nonexported || self.inlining { self.add_to_current_mod(item, renamed, import_id); diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs index 9071c9c95f9d7..c5acaf0999332 100644 --- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -5,10 +5,12 @@ use itertools::Itertools; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; use rustc_middle::lint::LevelAndSource; use rustc_session::impl_lint_pass; -use rustc_span::{Span, SyntaxContext, sym}; +use rustc_span::{Span, SyntaxContext}; use std::collections::BTreeMap; use std::collections::btree_map::Entry; @@ -146,7 +148,8 @@ struct BodyVisitor<'a, 'tcx> { } fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { - (cx.effective_visibilities.is_exported(def_id) || cx.tcx.has_attr(def_id, sym::macro_export)) + ( cx.effective_visibilities.is_exported(def_id) || + find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::MacroExport{..}) ) && !cx.tcx.is_doc_hidden(def_id) } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ba7fcadbc2e59..35670ba89e997 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -354,13 +354,10 @@ impl<'test> TestCx<'test> { } } else { if proc_res.status.success() { - { - self.error(&format!("{} test did not emit an error", self.config.mode)); - if self.config.mode == crate::common::TestMode::Ui { - println!("note: by default, ui tests are expected not to compile"); - } - proc_res.fatal(None, || ()); - }; + let err = &format!("{} test did not emit an error", self.config.mode); + let extra_note = (self.config.mode == crate::common::TestMode::Ui) + .then_some("note: by default, ui tests are expected not to compile"); + self.fatal_proc_rec_general(err, extra_note, proc_res, || ()); } if !self.props.dont_check_failure_status { @@ -606,7 +603,10 @@ impl<'test> TestCx<'test> { ); } else { for pattern in missing_patterns { - self.error(&format!("error pattern '{}' not found!", pattern)); + println!( + "\n{prefix}: error pattern '{pattern}' not found!", + prefix = self.error_prefix() + ); } self.fatal_proc_rec("multiple error patterns not found", proc_res); } @@ -824,10 +824,11 @@ impl<'test> TestCx<'test> { // - only known line - meh, but suggested // - others are not worth suggesting if !unexpected.is_empty() { - self.error(&format!( - "{} diagnostics reported in JSON output but not expected in test file", - unexpected.len(), - )); + println!( + "\n{prefix}: {n} diagnostics reported in JSON output but not expected in test file", + prefix = self.error_prefix(), + n = unexpected.len(), + ); for error in &unexpected { print_error(error); let mut suggestions = Vec::new(); @@ -857,10 +858,11 @@ impl<'test> TestCx<'test> { } } if !not_found.is_empty() { - self.error(&format!( - "{} diagnostics expected in test file but not reported in JSON output", - not_found.len() - )); + println!( + "\n{prefix}: {n} diagnostics expected in test file but not reported in JSON output", + prefix = self.error_prefix(), + n = not_found.len(), + ); for error in ¬_found { print_error(error); let mut suggestions = Vec::new(); @@ -1995,33 +1997,52 @@ impl<'test> TestCx<'test> { output_base_name(self.config, self.testpaths, self.safe_revision()) } - fn error(&self, err: &str) { + /// Prefix to print before error messages. Normally just `error`, but also + /// includes the revision name for tests that use revisions. + #[must_use] + fn error_prefix(&self) -> String { match self.revision { - Some(rev) => println!("\nerror in revision `{}`: {}", rev, err), - None => println!("\nerror: {}", err), + Some(rev) => format!("error in revision `{rev}`"), + None => format!("error"), } } #[track_caller] fn fatal(&self, err: &str) -> ! { - self.error(err); + println!("\n{prefix}: {err}", prefix = self.error_prefix()); error!("fatal error, panic: {:?}", err); panic!("fatal error"); } fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! { - self.error(err); - proc_res.fatal(None, || ()); + self.fatal_proc_rec_general(err, None, proc_res, || ()); } - fn fatal_proc_rec_with_ctx( + /// Underlying implementation of [`Self::fatal_proc_rec`], providing some + /// extra capabilities not needed by most callers. + fn fatal_proc_rec_general( &self, err: &str, + extra_note: Option<&str>, proc_res: &ProcRes, - on_failure: impl FnOnce(Self), + callback_before_unwind: impl FnOnce(), ) -> ! { - self.error(err); - proc_res.fatal(None, || on_failure(*self)); + println!("\n{prefix}: {err}", prefix = self.error_prefix()); + + // Some callers want to print additional notes after the main error message. + if let Some(note) = extra_note { + println!("{note}"); + } + + // Print the details and output of the subprocess that caused this test to fail. + println!("{}", proc_res.format_info()); + + // Some callers want print more context or show a custom diff before the unwind occurs. + callback_before_unwind(); + + // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from + // compiletest, which is unnecessary noise. + std::panic::resume_unwind(Box::new(())); } // codegen tests (using FileCheck) @@ -2080,7 +2101,7 @@ impl<'test> TestCx<'test> { if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" } } - fn compare_to_default_rustdoc(&mut self, out_dir: &Utf8Path) { + fn compare_to_default_rustdoc(&self, out_dir: &Utf8Path) { if !self.config.has_html_tidy { return; } @@ -2957,7 +2978,8 @@ pub struct ProcRes { } impl ProcRes { - pub fn print_info(&self) { + #[must_use] + pub fn format_info(&self) -> String { fn render(name: &str, contents: &str) -> String { let contents = json::extract_rendered(contents); let contents = contents.trim_end(); @@ -2973,24 +2995,13 @@ impl ProcRes { } } - println!( + format!( "status: {}\ncommand: {}\n{}\n{}\n", self.status, self.cmdline, render("stdout", &self.stdout), render("stderr", &self.stderr), - ); - } - - pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! { - if let Some(e) = err { - println!("\nerror: {}", e); - } - self.print_info(); - on_failure(); - // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from - // compiletest, which is unnecessary noise. - std::panic::resume_unwind(Box::new(())); + ) } } diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs index 236f021ce827c..4a143aa5824e7 100644 --- a/src/tools/compiletest/src/runtest/rustdoc.rs +++ b/src/tools/compiletest/src/runtest/rustdoc.rs @@ -28,8 +28,8 @@ impl TestCx<'_> { } let res = self.run_command_to_procres(&mut cmd); if !res.status.success() { - self.fatal_proc_rec_with_ctx("htmldocck failed!", &res, |mut this| { - this.compare_to_default_rustdoc(&out_dir) + self.fatal_proc_rec_general("htmldocck failed!", None, &res, || { + self.compare_to_default_rustdoc(&out_dir); }); } } diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 4f35efedfde49..083398f927455 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -29,9 +29,9 @@ impl TestCx<'_> { ); if !res.status.success() { - self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| { + self.fatal_proc_rec_general("jsondocck failed!", None, &res, || { println!("Rustdoc Output:"); - proc_res.print_info(); + println!("{}", proc_res.format_info()); }) } diff --git a/src/tools/miri/tests/fail/validity/dangling_ref3.rs b/src/tools/miri/tests/fail/validity/dangling_ref3.rs index 8e8a75bd7ec04..0fecd8f1c285f 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref3.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref3.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(dangling_pointers_from_locals)] + use std::mem; fn dangling() -> *const u8 { diff --git a/tests/codegen-llvm/bounds-check-elision-slice-min.rs b/tests/codegen-llvm/bounds-check-elision-slice-min.rs new file mode 100644 index 0000000000000..e160e5da50f93 --- /dev/null +++ b/tests/codegen-llvm/bounds-check-elision-slice-min.rs @@ -0,0 +1,19 @@ +//! Regression test for #: +//! Multiple bounds checking elision failures +//! (ensures bounds checks are properly elided, +//! with no calls to panic_bounds_check in the LLVM IR). + +//@ compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo +// CHECK-NOT: panic_bounds_check +#[no_mangle] +pub fn foo(buf: &[u8], alloced_size: usize) -> &[u8] { + if alloced_size.checked_add(1).map(|total| buf.len() < total).unwrap_or(true) { + return &[]; + } + let size = buf[0]; + &buf[1..1 + usize::min(alloced_size, usize::from(size))] +} diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 2777bba893bbc..ba6ce0ee5286f 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 2777bba893bbc..ba6ce0ee5286f 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 2be0a478c852c..ba6ce0ee5286f 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 2be0a478c852c..ba6ce0ee5286f 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 11fb7afef0fb1..9ceba9444b8da 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -13,7 +13,6 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); - // CHECK: [[E:_.+]] = move [[D]] as usize (IntToInt); - // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[E]]) -> + // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) } diff --git a/tests/ui/attributes/invalid_macro_export_argument.allow.stderr b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr new file mode 100644 index 0000000000000..2db60a6897282 --- /dev/null +++ b/tests/ui/attributes/invalid_macro_export_argument.allow.stderr @@ -0,0 +1,40 @@ +Future incompatibility report: Future breakage diagnostic: +warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:7:1 + | +LL | #[macro_export(hello, world)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +Future breakage diagnostic: +warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:14:1 + | +LL | #[macro_export(not_local_inner_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +Future breakage diagnostic: +warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:31:1 + | +LL | #[macro_export()] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +Future breakage diagnostic: +warning: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:38:1 + | +LL | #[macro_export("blah")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr index 9d44bd162c7b7..fd50b824d0a26 100644 --- a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr +++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr @@ -1,26 +1,103 @@ -error: `#[macro_export]` can only take 1 or 0 arguments +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` --> $DIR/invalid_macro_export_argument.rs:7:1 | LL | #[macro_export(hello, world)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 note: the lint level is defined here --> $DIR/invalid_macro_export_argument.rs:4:24 | LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: invalid `#[macro_export]` argument - --> $DIR/invalid_macro_export_argument.rs:13:16 +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:14:1 | LL | #[macro_export(not_local_inner_macros)] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:31:1 + | +LL | #[macro_export()] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 -error: invalid `#[macro_export]` argument - --> $DIR/invalid_macro_export_argument.rs:33:16 +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:38:1 | LL | #[macro_export("blah")] - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: aborting due to 4 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:7:1 + | +LL | #[macro_export(hello, world)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 +note: the lint level is defined here + --> $DIR/invalid_macro_export_argument.rs:4:24 + | +LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:14:1 + | +LL | #[macro_export(not_local_inner_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 +note: the lint level is defined here + --> $DIR/invalid_macro_export_argument.rs:4:24 + | +LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:31:1 + | +LL | #[macro_export()] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 +note: the lint level is defined here + --> $DIR/invalid_macro_export_argument.rs:4:24 + | +LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/invalid_macro_export_argument.rs:38:1 + | +LL | #[macro_export("blah")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 +note: the lint level is defined here + --> $DIR/invalid_macro_export_argument.rs:4:24 + | +LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs index c5fe39d062a4e..05a40913434e8 100644 --- a/tests/ui/attributes/invalid_macro_export_argument.rs +++ b/tests/ui/attributes/invalid_macro_export_argument.rs @@ -5,13 +5,15 @@ #![cfg_attr(allow, allow(invalid_macro_export_arguments))] #[macro_export(hello, world)] -//[deny]~^ ERROR `#[macro_export]` can only take 1 or 0 arguments +//[deny]~^ ERROR valid forms for the attribute are +//[deny]~| WARN this was previously accepted macro_rules! a { () => () } #[macro_export(not_local_inner_macros)] -//[deny]~^ ERROR invalid `#[macro_export]` argument +//[deny]~^ ERROR valid forms for the attribute are +//[deny]~| WARN this was previously accepted macro_rules! b { () => () } @@ -20,18 +22,22 @@ macro_rules! b { macro_rules! c { () => () } + #[macro_export(local_inner_macros)] macro_rules! d { () => () } #[macro_export()] +//[deny]~^ ERROR valid forms for the attribute are +//[deny]~| WARN this was previously accepted macro_rules! e { () => () } #[macro_export("blah")] -//[deny]~^ ERROR invalid `#[macro_export]` argument +//[deny]~^ ERROR valid forms for the attribute are +//[deny]~| WARN this was previously accepted macro_rules! f { () => () } diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 2a8b7b41e58fd..e0e319335c778 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -213,7 +213,7 @@ extern crate wloop; //~^ ERROR can't find crate for `wloop` [E0463] #[macro_export = 18] -//~^ ERROR malformed `macro_export` attribute input +//~^ ERROR valid forms for the attribute are #[allow_internal_unsafe = 1] //~^ ERROR malformed //~| ERROR allow_internal_unsafe side-steps the unsafe_code lint diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 814a1e5f69192..d568f2381c9af 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -55,12 +55,6 @@ error: malformed `patchable_function_entry` attribute input LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:112:5 - | -LL | #[coroutine = 63] || {} - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` - error: malformed `must_not_suspend` attribute input --> $DIR/malformed-attrs.rs:133:1 | @@ -136,21 +130,6 @@ error: malformed `no_link` attribute input LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` -error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:215:1 - | -LL | #[macro_export = 18] - | ^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[macro_export = 18] -LL + #[macro_export(local_inner_macros)] - | -LL - #[macro_export = 18] -LL + #[macro_export] - | - error: malformed `allow_internal_unsafe` attribute input --> $DIR/malformed-attrs.rs:217:1 | @@ -445,6 +424,15 @@ LL | #[proc_macro = 18] | | didn't expect any arguments here | help: must be of the form: `#[proc_macro]` +error[E0565]: malformed `coroutine` attribute input + --> $DIR/malformed-attrs.rs:112:5 + | +LL | #[coroutine = 63] || {} + | ^^^^^^^^^^^^----^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[coroutine]` + error[E0565]: malformed `proc_macro_attribute` attribute input --> $DIR/malformed-attrs.rs:117:1 | @@ -567,6 +555,12 @@ error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and ` LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ +error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` + --> $DIR/malformed-attrs.rs:215:1 + | +LL | #[macro_export = 18] + | ^^^^^^^^^^^^^^^^^^^^ + error[E0565]: malformed `type_const` attribute input --> $DIR/malformed-attrs.rs:144:5 | diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 4cba54bf67c12..6d3b1e4e27380 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -91,21 +91,6 @@ error[E0518]: attribute should be applied to function or closure LL | #![inline] | ^^^^^^^^^^ not a function or closure -error: `macro_export` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 - | -LL | #![macro_export] - | ^^^^^^^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![macro_export] -LL + #[macro_export] - | - error: `rustc_main` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1 | @@ -136,6 +121,21 @@ LL - #![repr()] LL + #[repr()] | +error: `macro_export` attribute cannot be used at crate level + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 + | +LL | #![macro_export] + | ^^^^^^^^^^^^^^^^ +... +LL | mod inline { + | ------ the inner attribute doesn't annotate this module + | +help: perhaps you meant to use an outer attribute + | +LL - #![macro_export] +LL + #[macro_export] + | + error: `path` attribute cannot be used at crate level --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 | diff --git a/tests/ui/lint/dangling-pointers-from-locals.rs b/tests/ui/lint/dangling-pointers-from-locals.rs new file mode 100644 index 0000000000000..e321df2f42790 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.rs @@ -0,0 +1,188 @@ +//@ check-pass + +struct Zst((), ()); +struct Adt(u8); + +const X: u8 = 5; + +fn simple() -> *const u8 { + let x = 0; + &x + //~^ WARN a dangling pointer will be produced +} + +fn bindings() -> *const u8 { + let x = 0; + let x = &x; + x + //~^ WARN a dangling pointer will be produced +} + +fn bindings_with_return() -> *const u8 { + let x = 42; + let y = &x; + return y; + //~^ WARN a dangling pointer will be produced +} + +fn with_simple_cast() -> *const u8 { + let x = 0u8; + &x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn bindings_and_casts() -> *const u8 { + let x = 0u8; + let x = &x as *const u8; + x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn return_with_complex_cast() -> *mut u8 { + let mut x = 0u8; + return &mut x as *mut u8 as *const u8 as *mut u8; + //~^ WARN a dangling pointer will be produced +} + +fn with_block() -> *const u8 { + let x = 0; + &{ x } + //~^ WARN a dangling pointer will be produced +} + +fn with_many_blocks() -> *const u8 { + let x = 0; + { + { + &{ + //~^ WARN a dangling pointer will be produced + { x } + } + } + } +} + +fn simple_return() -> *const u8 { + let x = 0; + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn return_mut() -> *mut u8 { + let mut x = 0; + return &mut x; + //~^ WARN a dangling pointer will be produced +} + +fn const_and_flow() -> *const u8 { + if false { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + } + &X // not dangling +} + +fn vector() -> *const Vec { + let x = vec![T::default()]; + &x + //~^ WARN a dangling pointer will be produced +} + +fn local_adt() -> *const Adt { + let x = Adt(5); + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn closure() -> *const u8 { + let _x = || -> *const u8 { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + }; + &X // not dangling +} + +fn fn_ptr() -> *const fn() -> u8 { + fn ret_u8() -> u8 { + 0 + } + + let x = ret_u8 as fn() -> u8; + &x + //~^ WARN a dangling pointer will be produced +} + +fn as_arg(a: Adt) -> *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + &a + //~^ WARN a dangling pointer will be produced +} + +fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn adt_as_arg(a: &Adt) -> *const &Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn unit() -> *const () { + let x = (); + &x // not dangling +} + +fn zst() -> *const Zst { + let x = Zst((), ()); + &x // not dangling +} + +fn ref_implicit(a: &Adt) -> *const Adt { + a // not dangling +} + +fn ref_explicit(a: &Adt) -> *const Adt { + &*a // not dangling +} + +fn identity(a: *const Adt) -> *const Adt { + a // not dangling +} + +fn from_ref(a: &Adt) -> *const Adt { + std::ptr::from_ref(a) // not dangling +} + +fn inner_static() -> *const u8 { + static U: u8 = 5; + if false { + return &U as *const u8; // not dangling + } + &U // not dangling +} + +fn return_in_closure() { + let x = 0; + let c = || -> *const u8 { + &x // not dangling by it-self + }; +} + +fn option() -> *const Option { + let x = Some(T::default()); + &x // can't compute layout of `Option`, so cnat' be sure it won't be a ZST +} + +fn generic() -> *const T { + let x = T::default(); + &x // can't compute layout of `T`, so can't be sure it won't be a ZST +} + +fn main() {} diff --git a/tests/ui/lint/dangling-pointers-from-locals.stderr b/tests/ui/lint/dangling-pointers-from-locals.stderr new file mode 100644 index 0000000000000..e1d28bf22a0c1 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.stderr @@ -0,0 +1,247 @@ +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:10:5 + | +LL | fn simple() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + = note: `#[warn(dangling_pointers_from_locals)]` on by default + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:17:5 + | +LL | fn bindings() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x; + | -- dangling pointer created here +LL | x + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:24:12 + | +LL | fn bindings_with_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 42; + | - `x` is part the function and will be dropped at the end of the function +LL | let y = &x; + | -- dangling pointer created here +LL | return y; + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:30:5 + | +LL | fn with_simple_cast() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x as *const u8 + | --^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:37:5 + | +LL | fn bindings_and_casts() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x as *const u8; + | -- dangling pointer created here +LL | x as *const u8 + | ^^^^^^^^^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:43:12 + | +LL | fn return_with_complex_cast() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0u8; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x as *mut u8 as *const u8 as *mut u8; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:49:5 + | +LL | fn with_block() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &{ x } + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:57:13 + | +LL | fn with_many_blocks() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +... +LL | / &{ +LL | | +LL | | { x } +LL | | } + | |_____________^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:67:12 + | +LL | fn simple_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:73:12 + | +LL | fn return_mut() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x; + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:80:16 + | +LL | fn const_and_flow() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | if false { +LL | let x = 8; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:88:5 + | +LL | fn vector() -> *const Vec { + | ------------- return type of the function is `*const Vec` +LL | let x = vec![T::default()]; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Vec` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:94:12 + | +LL | fn local_adt() -> *const Adt { + | ---------- return type of the function is `*const Adt` +LL | let x = Adt(5); + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:101:16 + | +LL | let _x = || -> *const u8 { + | --------- return type of the closure is `*const u8` +LL | let x = 8; + | - `x` is part the closure and will be dropped at the end of the closure +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the closure because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:113:5 + | +LL | fn fn_ptr() -> *const fn() -> u8 { + | ----------------- return type of the function is `*const fn() -> u8` +... +LL | let x = ret_u8 as fn() -> u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:118:5 + | +LL | fn as_arg(a: Adt) -> *const Adt { + | - ---------- return type of the function is `*const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:123:5 + | +LL | fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + | - ----------------- return type of the function is `*const fn() -> u8` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:128:5 + | +LL | fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + | - ----------------- return type of the function is `*const *const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `*const Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:133:5 + | +LL | fn adt_as_arg(a: &Adt) -> *const &Adt { + | - ----------- return type of the function is `*const &Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `&Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: 19 warnings emitted + diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index e277f5203c698..817556aa165be 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -104,18 +104,6 @@ note: attribute also specified here LL | #![no_builtins] | ^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:40:5 - | -LL | #[macro_export] - | ^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:39:5 - | -LL | #[macro_export] - | ^^^^^^^^^^^^^^^ - error: unused attribute --> $DIR/unused-attr-duplicate.rs:37:1 | @@ -128,6 +116,18 @@ note: attribute also specified here LL | #[macro_use] | ^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:40:5 + | +LL | #[macro_export] + | ^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:39:5 + | +LL | #[macro_export] + | ^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:47:1 |