about summary refs log tree commit diff
path: root/compiler/rustc_lint/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src')
-rw-r--r--compiler/rustc_lint/src/builtin.rs4
-rw-r--r--compiler/rustc_lint/src/context.rs23
-rw-r--r--compiler/rustc_lint/src/dangling.rs152
-rw-r--r--compiler/rustc_lint/src/default_could_be_derived.rs3
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs16
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs4
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs4
-rw-r--r--compiler/rustc_lint/src/types/literal.rs8
-rw-r--r--compiler/rustc_lint/src/unused.rs4
10 files changed, 186 insertions, 35 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 152971c4ed6..c893b723375 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -21,14 +21,14 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::expr_to_string;
-use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_errors::{Applicability, LintDiagnostic};
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_hir::intravisit::FnKind as HirFnKind;
-use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin};
+use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin, find_attr};
 use rustc_middle::bug;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::ty::layout::LayoutOf;
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index b694d3dd49b..11181d10af5 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -756,22 +756,22 @@ impl<'tcx> LateContext<'tcx> {
             }
 
             fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
-                Ok(())
+                unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
             fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
-                Ok(())
+                unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
             fn print_dyn_existential(
                 &mut self,
                 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
             ) -> Result<(), PrintError> {
-                Ok(())
+                unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
             fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
-                Ok(())
+                unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
             fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
@@ -784,10 +784,10 @@ impl<'tcx> LateContext<'tcx> {
                 self_ty: Ty<'tcx>,
                 trait_ref: Option<ty::TraitRef<'tcx>>,
             ) -> Result<(), PrintError> {
-                if trait_ref.is_none() {
-                    if let ty::Adt(def, args) = self_ty.kind() {
-                        return self.print_def_path(def.did(), args);
-                    }
+                if trait_ref.is_none()
+                    && let ty::Adt(def, args) = self_ty.kind()
+                {
+                    return self.print_def_path(def.did(), args);
                 }
 
                 // This shouldn't ever be needed, but just in case:
@@ -803,7 +803,6 @@ impl<'tcx> LateContext<'tcx> {
             fn path_append_impl(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
-                _disambiguated_data: &DisambiguatedDefPathData,
                 self_ty: Ty<'tcx>,
                 trait_ref: Option<ty::TraitRef<'tcx>>,
             ) -> Result<(), PrintError> {
@@ -854,9 +853,9 @@ impl<'tcx> LateContext<'tcx> {
             }
         }
 
-        let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
-        printer.print_def_path(def_id, &[]).unwrap();
-        printer.path
+        let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
+        p.print_def_path(def_id, &[]).unwrap();
+        p.path
     }
 
     /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`.
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index c737919db9c..af4457f4314 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_attr_data_structures::{AttributeKind, find_attr};
+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};
-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 `&<path_to_local_in_same_body>` 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/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs
index b5fc083a095..7c39d8917ce 100644
--- a/compiler/rustc_lint/src/default_could_be_derived.rs
+++ b/compiler/rustc_lint/src/default_could_be_derived.rs
@@ -1,7 +1,8 @@
-use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
 use rustc_middle::ty;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint, impl_lint_pass};
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index d6c402d481f..759e6c927b8 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -1,9 +1,10 @@
 use rustc_abi::FIRST_VARIANT;
-use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::DefKind;
+use rustc_hir::find_attr;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
 use rustc_session::declare_lint;
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index fd8d0f832aa..ef63c0dee8c 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<Span>,
+}
+
 // multiple_supertrait_upcastable.rs
 #[derive(LintDiagnostic)]
 #[diag(lint_multiple_supertrait_upcastable)]
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 76e374deef6..7e5f43ba77f 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,11 +1,11 @@
 use rustc_abi::ExternAbi;
-use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
 use rustc_attr_parsing::AttributeParser;
 use rustc_errors::Applicability;
+use rustc_hir::attrs::{AttributeKind, ReprAttr};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{FnKind, Visitor};
-use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
+use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind, find_attr};
 use rustc_middle::hir::nested_filter::All;
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index a3cf3d568b1..4f65acd8001 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,6 +1,6 @@
-use rustc_attr_data_structures::{AttributeKind, find_attr};
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::Res;
-use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind};
+use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind, find_attr};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index 2bac58ba23d..1febbff4bbf 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -1,11 +1,11 @@
 use hir::{ExprKind, Node, is_range_literal};
 use rustc_abi::{Integer, Size};
-use rustc_hir::HirId;
+use rustc_hir::{HirId, attrs};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::{bug, ty};
 use rustc_span::Span;
-use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir};
+use {rustc_ast as ast, rustc_hir as hir};
 
 use crate::LateContext;
 use crate::context::LintContext;
@@ -272,7 +272,7 @@ fn lint_int_literal<'tcx>(
                 cx,
                 hir_id,
                 span,
-                attrs::IntType::SignedInt(ty::ast_int_ty(t)),
+                attrs::IntType::SignedInt(t),
                 Integer::from_int_ty(cx, t).size(),
                 repr_str,
                 v,
@@ -358,7 +358,7 @@ fn lint_uint_literal<'tcx>(
                 cx,
                 hir_id,
                 span,
-                attrs::IntType::UnsignedInt(ty::ast_uint_ty(t)),
+                attrs::IntType::UnsignedInt(t),
                 Integer::from_uint_ty(cx, t).size(),
                 repr_str,
                 lit_val,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 00e40b515a3..22d89d24612 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -2,12 +2,12 @@ use std::iter;
 
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{self as ast, ExprKind, FnRetTy, HasAttrs as _, StmtKind};
-use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{MultiSpan, pluralize};
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, LangItem};
+use rustc_hir::{self as hir, LangItem, find_attr};
 use rustc_infer::traits::util::elaborate;
 use rustc_middle::ty::{self, Ty, adjustment};
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};