LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors - rust-unsafe-checker.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 75.1 % 534 401
Test Date: 2026-09-19 16:22:48 Functions: 57.0 % 142 81
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-unsafe-checker.h"
      20              : #include "rust-hir.h"
      21              : #include "rust-hir-expr.h"
      22              : #include "rust-hir-stmt.h"
      23              : #include "rust-hir-item.h"
      24              : #include "rust-attribute-values.h"
      25              : #include "rust-rib.h"
      26              : #include "rust-system.h"
      27              : #include "rust-finalized-name-resolution-context.h"
      28              : #include "rust-intrinsic-values.h"
      29              : #include "options.h"
      30              : 
      31              : namespace Rust {
      32              : namespace HIR {
      33              : 
      34         4477 : UnsafeChecker::UnsafeChecker ()
      35         4477 :   : context (*Resolver::TypeCheckContext::get ()),
      36         4477 :     resolver (Resolver2_0::FinalizedNameResolutionContext::get ()),
      37         8954 :     mappings (Analysis::Mappings::get ())
      38         4477 : {}
      39              : 
      40              : void
      41         4477 : UnsafeChecker::go (HIR::Crate &crate)
      42              : {
      43        23581 :   for (auto &item : crate.get_items ())
      44        19104 :     item->accept_vis (*this);
      45         4477 : }
      46              : 
      47              : void
      48         4559 : UnsafeChecker::mark_unsafe_used ()
      49              : {
      50         4559 :   if (unsafe_context.is_in_context ())
      51         4559 :     used_unsafe_blocks.insert (unsafe_context.peek ());
      52         4559 : }
      53              : 
      54              : static bool
      55          845 : check_static_mut (HIR::Item *maybe_static, location_t locus, bool in_context)
      56              : {
      57          845 :   if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
      58              :     {
      59          845 :       auto item = static_cast<Item *> (maybe_static);
      60          845 :       if (item->get_item_kind () == Item::ItemKind::Static)
      61              :         {
      62           37 :           auto static_item = static_cast<StaticItem *> (item);
      63           37 :           if (static_item->is_mut ())
      64              :             {
      65           10 :               if (!in_context)
      66            4 :                 rust_error_at (locus, "use of mutable static requires unsafe "
      67              :                                       "function or block");
      68              :               return true;
      69              :             }
      70              :         }
      71              :     }
      72              :   return false;
      73              : }
      74              : 
      75              : static bool
      76            6 : check_extern_static (HIR::ExternalItem *maybe_static, location_t locus,
      77              :                      bool in_context)
      78              : {
      79            6 :   if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static)
      80              :     {
      81            2 :       if (!in_context)
      82            1 :         rust_error_at (
      83              :           locus, "use of extern static requires unsafe function or block");
      84              :       return true;
      85              :     }
      86              :   return false;
      87              : }
      88              : 
      89              : void
      90        32671 : UnsafeChecker::check_use_of_static (HirId node_id, location_t locus)
      91              : {
      92        32671 :   bool in_context = unsafe_context.is_in_context ();
      93        32671 :   bool unsafe_op = false;
      94              : 
      95        32671 :   if (auto maybe_static_mut = mappings.lookup_hir_item (node_id))
      96          845 :     unsafe_op |= check_static_mut (*maybe_static_mut, locus, in_context);
      97              : 
      98        32671 :   if (auto maybe_extern_static = mappings.lookup_hir_extern_item (node_id))
      99            6 :     unsafe_op |= check_extern_static (static_cast<ExternalItem *> (
     100            6 :                                         maybe_extern_static->first),
     101              :                                       locus, in_context);
     102              : 
     103        32671 :   if (unsafe_op && in_context)
     104            7 :     mark_unsafe_used ();
     105        32671 : }
     106              : 
     107              : static bool
     108         5545 : check_unsafe_call (HIR::Function *fn, location_t locus, const std::string &kind,
     109              :                    bool in_context)
     110              : {
     111         5545 :   if (fn->get_qualifiers ().is_unsafe ())
     112              :     {
     113          614 :       if (!in_context)
     114            4 :         rust_error_at (locus, ErrorCode::E0133,
     115              :                        "call to unsafe %s requires unsafe function or block",
     116              :                        kind.c_str ());
     117              :       return true;
     118              :     }
     119              :   return false;
     120              : }
     121              : 
     122              : static bool
     123         4020 : is_safe_intrinsic (const std::string &fn_name)
     124              : {
     125         4020 :   using Intrinsics = Values::Intrinsics;
     126              : 
     127         4020 :   static const std::unordered_set<std::string> safe_intrinsics = {
     128          473 :     Intrinsics::ABORT,
     129          473 :     Intrinsics::SIZE_OF,
     130          473 :     Intrinsics::MIN_ALIGN_OF,
     131          473 :     Intrinsics::NEEDS_DROP,
     132          473 :     Intrinsics::CALLER_LOCATION,
     133          473 :     Intrinsics::ADD_WITH_OVERFLOW,
     134          473 :     Intrinsics::SUB_WITH_OVERFLOW,
     135          473 :     Intrinsics::MUL_WITH_OVERFLOW,
     136          473 :     Intrinsics::WRAPPING_ADD,
     137          473 :     Intrinsics::WRAPPING_SUB,
     138          473 :     Intrinsics::WRAPPING_MUL,
     139          473 :     Intrinsics::SATURATING_ADD,
     140          473 :     Intrinsics::SATURATING_SUB,
     141          473 :     Intrinsics::ROTATE_LEFT,
     142          473 :     Intrinsics::ROTATE_RIGHT,
     143          473 :     Intrinsics::CTPOP,
     144          473 :     Intrinsics::CTLZ,
     145          473 :     Intrinsics::CTTZ,
     146          473 :     Intrinsics::BSWAP,
     147          473 :     Intrinsics::BITREVERSE,
     148          473 :     Intrinsics::DISCRIMINANT_VALUE,
     149          473 :     Intrinsics::TYPE_ID,
     150          473 :     Intrinsics::LIKELY,
     151          473 :     Intrinsics::UNLIKELY,
     152          473 :     Intrinsics::PTR_GUARANTEED_EQ,
     153          473 :     Intrinsics::PTR_GUARANTEED_NE,
     154          473 :     Intrinsics::MINNUMF32,
     155          473 :     Intrinsics::MINNUMF64,
     156          473 :     Intrinsics::MAXNUMF32,
     157          473 :     Intrinsics::MAXNUMF64,
     158          473 :     Intrinsics::RUSTC_PEEK,
     159          473 :     Intrinsics::TYPE_NAME,
     160          473 :     Intrinsics::FORGET,
     161          473 :     Intrinsics::BLACK_BOX,
     162          473 :     Intrinsics::VARIANT_COUNT,
     163        20575 :   };
     164              : 
     165         4020 :   return safe_intrinsics.find (fn_name) != safe_intrinsics.end ();
     166              : }
     167              : 
     168              : static bool
     169         5942 : check_extern_call (HIR::ExternalItem *maybe_fn, HIR::ExternBlock *parent_block,
     170              :                    location_t locus, bool in_context)
     171              : {
     172              :   // We have multiple operations to perform here
     173              :   //     1. Is the item an actual function we're calling
     174              :   //     2. Is the block it's defined in an FFI block or an `extern crate` block
     175              :   //
     176              :   // It is not unsafe to call into other crates, so items defined in an `extern
     177              :   // crate` must be callable without being in an unsafe context. On the other
     178              :   // hand, any function defined in a block with a specific ABI (even `extern
     179              :   // "Rust"` blocks) is unsafe to call
     180              : 
     181         5942 :   if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function)
     182              :     return false;
     183              : 
     184              :   // Some intrinsics are safe to call
     185        11884 :   if (parent_block->get_abi () == Rust::ABI::INTRINSIC
     186        13982 :       && is_safe_intrinsic (maybe_fn->get_item_name ().as_string ()))
     187              :     return false;
     188              : 
     189         3429 :   if (!in_context)
     190            1 :     rust_error_at (locus,
     191              :                    "call to extern function requires unsafe function or block");
     192              :   return true;
     193              : }
     194              : 
     195              : void
     196        12976 : UnsafeChecker::check_function_call (HirId node_id, location_t locus)
     197              : {
     198        12976 :   bool in_context = unsafe_context.is_in_context ();
     199        12976 :   bool unsafe_op = false;
     200              : 
     201        12976 :   auto maybe_fn = mappings.lookup_hir_item (node_id);
     202              : 
     203        12976 :   if (maybe_fn
     204        12976 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
     205         3528 :     unsafe_op |= check_unsafe_call (static_cast<Function *> (*maybe_fn), locus,
     206         7056 :                                     "function", in_context);
     207              : 
     208        12976 :   if (auto maybe_extern = mappings.lookup_hir_extern_item (node_id))
     209         5942 :     unsafe_op
     210         5942 :       |= check_extern_call (static_cast<ExternalItem *> (maybe_extern->first),
     211         5942 :                             *mappings.lookup_hir_extern_block (
     212         5942 :                               maybe_extern->second),
     213              :                             locus, in_context);
     214              : 
     215        12976 :   if (unsafe_op && in_context)
     216         3739 :     mark_unsafe_used ();
     217        12976 : }
     218              : 
     219              : static bool
     220         3528 : check_target_attr (HIR::Function *fn, location_t locus, bool in_context)
     221              : {
     222         3528 :   if (std::any_of (fn->get_outer_attrs ().begin (),
     223         3528 :                    fn->get_outer_attrs ().end (),
     224           50 :                    [] (const AST::Attribute &attr) {
     225           50 :                      return attr.get_path ().as_string ()
     226           50 :                             == Values::Attributes::TARGET_FEATURE;
     227              :                    }))
     228              :     {
     229            2 :       if (!in_context)
     230            1 :         rust_error_at (locus,
     231              :                        "call to function with %<#[target_feature]%> requires "
     232              :                        "unsafe function or block");
     233              :       return true;
     234              :     }
     235              :   return false;
     236              : }
     237              : 
     238              : void
     239        12976 : UnsafeChecker::check_function_attr (HirId node_id, location_t locus)
     240              : {
     241        12976 :   bool in_context = unsafe_context.is_in_context ();
     242              : 
     243        12976 :   auto maybe_fn = mappings.lookup_hir_item (node_id);
     244              : 
     245        12976 :   if (maybe_fn
     246         4394 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function
     247         3528 :       && check_target_attr (static_cast<Function *> (*maybe_fn), locus,
     248              :                             in_context)
     249        12978 :       && in_context)
     250            1 :     mark_unsafe_used ();
     251        12976 : }
     252              : 
     253              : void
     254            0 : UnsafeChecker::visit (Lifetime &)
     255            0 : {}
     256              : 
     257              : void
     258            0 : UnsafeChecker::visit (LifetimeParam &)
     259            0 : {}
     260              : 
     261              : void
     262        32671 : UnsafeChecker::visit (PathInExpression &path)
     263              : {
     264        32671 :   NodeId ast_node_id = path.get_mappings ().get_nodeid ();
     265        32671 :   NodeId ref_node_id;
     266              : 
     267        65342 :   if (auto resolved
     268        32671 :       = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values,
     269        32671 :                          Resolver2_0::Namespace::Types))
     270        32671 :     ref_node_id = resolved->id;
     271              :   else
     272            0 :     return;
     273              : 
     274        32671 :   if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
     275              :     {
     276        32671 :       check_use_of_static (*definition_id, path.get_locus ());
     277              :     }
     278              :   else
     279              :     {
     280            0 :       rust_unreachable ();
     281              :     }
     282              : }
     283              : 
     284              : void
     285            0 : UnsafeChecker::visit (TypePathSegment &)
     286            0 : {}
     287              : 
     288              : void
     289            0 : UnsafeChecker::visit (TypePathSegmentGeneric &)
     290            0 : {}
     291              : 
     292              : void
     293            0 : UnsafeChecker::visit (TypePathSegmentFunction &)
     294            0 : {}
     295              : 
     296              : void
     297            0 : UnsafeChecker::visit (TypePath &)
     298            0 : {}
     299              : 
     300              : void
     301           15 : UnsafeChecker::visit (QualifiedPathInExpression &)
     302           15 : {}
     303              : 
     304              : void
     305            0 : UnsafeChecker::visit (QualifiedPathInType &)
     306            0 : {}
     307              : 
     308              : void
     309        20076 : UnsafeChecker::visit (LiteralExpr &)
     310        20076 : {}
     311              : 
     312              : void
     313         2123 : UnsafeChecker::visit (BorrowExpr &expr)
     314              : {
     315         2123 :   expr.get_expr ().accept_vis (*this);
     316         2123 : }
     317              : 
     318              : void
     319         4275 : UnsafeChecker::visit (DereferenceExpr &expr)
     320              : {
     321         4275 :   TyTy::BaseType *to_deref_type;
     322         4275 :   auto to_deref = expr.get_expr ().get_mappings ().get_hirid ();
     323              : 
     324         4275 :   rust_assert (context.lookup_type (to_deref, &to_deref_type));
     325              : 
     326         4275 :   if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER)
     327              :     {
     328          209 :       if (unsafe_context.is_in_context ())
     329          207 :         mark_unsafe_used ();
     330              :       else
     331            2 :         rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
     332              :                                           "unsafe function or block");
     333              :     }
     334         4275 : }
     335              : 
     336              : void
     337            0 : UnsafeChecker::visit (ErrorPropagationExpr &expr)
     338              : {
     339            0 :   expr.get_expr ().accept_vis (*this);
     340            0 : }
     341              : 
     342              : void
     343          603 : UnsafeChecker::visit (NegationExpr &expr)
     344              : {
     345          603 :   expr.get_expr ().accept_vis (*this);
     346          603 : }
     347              : 
     348              : void
     349         3558 : UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
     350              : {
     351         3558 :   expr.get_lhs ().accept_vis (*this);
     352         3558 :   expr.get_rhs ().accept_vis (*this);
     353         3558 : }
     354              : 
     355              : void
     356         3733 : UnsafeChecker::visit (ComparisonExpr &expr)
     357              : {
     358         3733 :   expr.get_lhs ().accept_vis (*this);
     359         3733 :   expr.get_rhs ().accept_vis (*this);
     360         3733 : }
     361              : 
     362              : void
     363          424 : UnsafeChecker::visit (LazyBooleanExpr &expr)
     364              : {
     365          424 :   expr.get_lhs ().accept_vis (*this);
     366          424 :   expr.get_rhs ().accept_vis (*this);
     367          424 : }
     368              : 
     369              : void
     370         5656 : UnsafeChecker::visit (TypeCastExpr &expr)
     371              : {
     372         5656 :   expr.get_expr ().accept_vis (*this);
     373         5656 : }
     374              : 
     375              : void
     376         2520 : UnsafeChecker::visit (AssignmentExpr &expr)
     377              : {
     378         2520 :   expr.get_lhs ().accept_vis (*this);
     379         2520 :   expr.get_rhs ().accept_vis (*this);
     380         2520 : }
     381              : 
     382              : void
     383          704 : UnsafeChecker::visit (CompoundAssignmentExpr &expr)
     384              : {
     385          704 :   expr.get_lhs ().accept_vis (*this);
     386          704 :   expr.get_rhs ().accept_vis (*this);
     387          704 : }
     388              : 
     389              : void
     390          337 : UnsafeChecker::visit (GroupedExpr &expr)
     391              : {
     392          337 :   expr.get_expr_in_parens ().accept_vis (*this);
     393          337 : }
     394              : 
     395              : void
     396          298 : UnsafeChecker::visit (ArrayElemsValues &elems)
     397              : {
     398         1793 :   for (auto &elem : elems.get_values ())
     399         1495 :     elem->accept_vis (*this);
     400          298 : }
     401              : 
     402              : void
     403          115 : UnsafeChecker::visit (ArrayElemsCopied &elems)
     404              : {
     405          115 :   elems.get_elem_to_copy ().accept_vis (*this);
     406          115 : }
     407              : 
     408              : void
     409          413 : UnsafeChecker::visit (ArrayExpr &expr)
     410              : {
     411          413 :   expr.get_internal_elements ().accept_vis (*this);
     412          413 : }
     413              : 
     414              : void
     415          293 : UnsafeChecker::visit (ArrayIndexExpr &expr)
     416              : {
     417          293 :   expr.get_array_expr ().accept_vis (*this);
     418          293 :   expr.get_index_expr ().accept_vis (*this);
     419          293 : }
     420              : 
     421              : void
     422          599 : UnsafeChecker::visit (TupleExpr &expr)
     423              : {
     424         1652 :   for (auto &elem : expr.get_tuple_elems ())
     425         1053 :     elem->accept_vis (*this);
     426          599 : }
     427              : 
     428              : void
     429          898 : UnsafeChecker::visit (TupleIndexExpr &expr)
     430              : {
     431          898 :   expr.get_tuple_expr ().accept_vis (*this);
     432          898 : }
     433              : 
     434              : void
     435           79 : UnsafeChecker::visit (StructExprStruct &)
     436           79 : {}
     437              : 
     438              : void
     439          235 : UnsafeChecker::visit (StructExprFieldIdentifier &)
     440          235 : {}
     441              : 
     442              : void
     443         2727 : UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
     444              : {
     445         2727 :   field.get_value ().accept_vis (*this);
     446         2727 : }
     447              : 
     448              : void
     449           42 : UnsafeChecker::visit (StructExprFieldIndexValue &field)
     450              : {
     451           42 :   field.get_value ().accept_vis (*this);
     452           42 : }
     453              : 
     454              : void
     455         1406 : UnsafeChecker::visit (StructExprStructFields &expr)
     456              : {
     457         4410 :   for (auto &field : expr.get_fields ())
     458         3004 :     field->accept_vis (*this);
     459         1406 : }
     460              : 
     461              : void
     462            0 : UnsafeChecker::visit (StructExprStructBase &)
     463            0 : {}
     464              : 
     465              : void
     466        13046 : UnsafeChecker::visit (CallExpr &expr)
     467              : {
     468        13046 :   if (!expr.has_fnexpr ())
     469              :     return;
     470              : 
     471        13046 :   NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid ();
     472        13046 :   NodeId ref_node_id;
     473              : 
     474        13046 :   if (auto resolved
     475        13046 :       = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values))
     476        12976 :     ref_node_id = resolved.value ();
     477              :   else
     478           70 :     return;
     479              : 
     480        12976 :   if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
     481              :     {
     482              :       // At this point we have the function's HIR Id. There are three checks we
     483              :       // must perform:
     484              :       //     1. The function is an unsafe one
     485              :       //     2. The function is an extern one
     486              :       //     3. The function is marked with a target_feature attribute
     487        12976 :       check_function_call (*definition_id, expr.get_locus ());
     488        12976 :       check_function_attr (*definition_id, expr.get_locus ());
     489              : 
     490        12976 :       if (expr.has_params ())
     491        25442 :         for (auto &arg : expr.get_arguments ())
     492        15000 :           arg->accept_vis (*this);
     493              :     }
     494              :   else
     495              :     {
     496            0 :       rust_unreachable ();
     497              :     }
     498              : }
     499              : 
     500              : void
     501         3002 : UnsafeChecker::visit (MethodCallExpr &expr)
     502              : {
     503         3002 :   TyTy::BaseType *method_type;
     504         3002 :   context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
     505              :                        &method_type);
     506         3002 :   if (!method_type || !method_type->is<TyTy::FnType> ())
     507            0 :     return;
     508              : 
     509         3002 :   auto &fn = static_cast<TyTy::FnType &> (*method_type);
     510              : 
     511              :   // FIXME
     512              :   // should probably use the defid lookup instead
     513              :   // tl::optional<HIR::Item *> lookup_defid (DefId id);
     514         3002 :   auto method = mappings.lookup_hir_implitem (fn.get_ref ());
     515         3002 :   if (method
     516         2017 :       && check_unsafe_call (static_cast<Function *> (method->first),
     517         5019 :                             expr.get_locus (), "method",
     518              :                             unsafe_context.is_in_context ())
     519         3302 :       && unsafe_context.is_in_context ())
     520          299 :     mark_unsafe_used ();
     521              : 
     522         3002 :   expr.get_receiver ().accept_vis (*this);
     523              : 
     524         5019 :   for (auto &arg : expr.get_arguments ())
     525         2017 :     arg->accept_vis (*this);
     526              : }
     527              : 
     528              : void
     529         5697 : UnsafeChecker::visit (FieldAccessExpr &expr)
     530              : {
     531         5697 :   expr.get_receiver_expr ().accept_vis (*this);
     532              : 
     533         5697 :   TyTy::BaseType *receiver_ty;
     534         5697 :   if (!context.lookup_type (
     535         5697 :         expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver_ty))
     536            0 :     return;
     537              : 
     538         5697 :   if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
     539              :     {
     540         2198 :       auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
     541         2198 :       if (maybe_union->is_union ())
     542              :         {
     543          279 :           if (unsafe_context.is_in_context ())
     544          278 :             mark_unsafe_used ();
     545              :           else
     546            1 :             rust_error_at (
     547              :               expr.get_locus (),
     548              :               "access to union field requires unsafe function or block");
     549              :         }
     550              :     }
     551              : }
     552              : 
     553              : void
     554           53 : UnsafeChecker::visit (ClosureExpr &expr)
     555              : {
     556           53 :   expr.get_expr ().accept_vis (*this);
     557           53 : }
     558              : 
     559              : void
     560        24778 : UnsafeChecker::visit (BlockExpr &expr)
     561              : {
     562        49713 :   for (auto &stmt : expr.get_statements ())
     563        24935 :     stmt->accept_vis (*this);
     564              : 
     565        24778 :   if (expr.has_expr ())
     566        17939 :     expr.get_final_expr ().accept_vis (*this);
     567        24778 : }
     568              : 
     569              : void
     570           15 : UnsafeChecker::visit (AnonConst &expr)
     571              : {
     572           15 :   expr.get_inner_expr ().accept_vis (*this);
     573           15 : }
     574              : 
     575              : void
     576           15 : UnsafeChecker::visit (ConstBlock &expr)
     577              : {
     578           15 :   expr.get_const_expr ().accept_vis (*this);
     579           15 : }
     580              : 
     581              : void
     582           25 : UnsafeChecker::visit (ContinueExpr &)
     583           25 : {}
     584              : 
     585              : void
     586          112 : UnsafeChecker::visit (BreakExpr &expr)
     587              : {
     588          112 :   if (expr.has_break_expr ())
     589           21 :     expr.get_expr ().accept_vis (*this);
     590          112 : }
     591              : 
     592              : void
     593           74 : UnsafeChecker::visit (RangeFromToExpr &expr)
     594              : {
     595           74 :   expr.get_from_expr ().accept_vis (*this);
     596           74 :   expr.get_to_expr ().accept_vis (*this);
     597           74 : }
     598              : 
     599              : void
     600            7 : UnsafeChecker::visit (RangeFromExpr &expr)
     601              : {
     602            7 :   expr.get_from_expr ().accept_vis (*this);
     603            7 : }
     604              : 
     605              : void
     606            7 : UnsafeChecker::visit (RangeToExpr &expr)
     607              : {
     608            7 :   expr.get_to_expr ().accept_vis (*this);
     609            7 : }
     610              : 
     611              : void
     612            0 : UnsafeChecker::visit (RangeFullExpr &)
     613            0 : {}
     614              : 
     615              : void
     616            0 : UnsafeChecker::visit (RangeToInclExpr &expr)
     617              : {
     618            0 :   expr.get_to_expr ().accept_vis (*this);
     619            0 : }
     620              : 
     621              : void
     622            4 : UnsafeChecker::visit (BoxExpr &expr)
     623              : {
     624            4 :   expr.get_expr ().accept_vis (*this);
     625            4 : }
     626              : 
     627              : void
     628          560 : UnsafeChecker::visit (ReturnExpr &expr)
     629              : {
     630          560 :   if (expr.has_return_expr ())
     631          524 :     expr.get_expr ().accept_vis (*this);
     632          560 : }
     633              : 
     634              : void
     635         3991 : UnsafeChecker::visit (UnsafeBlockExpr &expr)
     636              : {
     637         3991 :   auto id = expr.get_mappings ().get_hirid ();
     638         3991 :   unsafe_context.enter (id);
     639              : 
     640         3991 :   expr.get_block_expr ().accept_vis (*this);
     641              : 
     642         3991 :   unsafe_context.exit ();
     643              : 
     644         3991 :   if (flag_unused_check_2_0
     645         3991 :       && used_unsafe_blocks.find (id) == used_unsafe_blocks.end ())
     646            1 :     rust_warning_at (expr.get_locus (), OPT_Wunused,
     647              :                      "unnecessary %<unsafe%> block");
     648         3991 : }
     649              : 
     650              : void
     651          151 : UnsafeChecker::visit (LoopExpr &expr)
     652              : {
     653          151 :   expr.get_loop_block ().accept_vis (*this);
     654          151 : }
     655              : 
     656              : void
     657           88 : UnsafeChecker::visit (WhileLoopExpr &expr)
     658              : {
     659           88 :   expr.get_predicate_expr ().accept_vis (*this);
     660           88 :   expr.get_loop_block ().accept_vis (*this);
     661           88 : }
     662              : 
     663              : void
     664            0 : UnsafeChecker::visit (WhileLetLoopExpr &expr)
     665              : {
     666            0 :   expr.get_cond ().accept_vis (*this);
     667            0 :   expr.get_loop_block ().accept_vis (*this);
     668            0 : }
     669              : 
     670              : void
     671         1279 : UnsafeChecker::visit (IfExpr &expr)
     672              : {
     673         1279 :   expr.get_if_condition ().accept_vis (*this);
     674         1279 :   expr.get_if_block ().accept_vis (*this);
     675         1279 : }
     676              : 
     677              : void
     678         1335 : UnsafeChecker::visit (IfExprConseqElse &expr)
     679              : {
     680         1335 :   expr.get_if_condition ().accept_vis (*this);
     681         1335 :   expr.get_if_block ().accept_vis (*this);
     682         1335 :   expr.get_else_block ().accept_vis (*this);
     683         1335 : }
     684              : 
     685              : void
     686         1111 : UnsafeChecker::visit (MatchExpr &expr)
     687              : {
     688         1111 :   expr.get_scrutinee_expr ().accept_vis (*this);
     689              : 
     690         3653 :   for (auto &match_arm : expr.get_match_cases ())
     691         2542 :     match_arm.get_expr ().accept_vis (*this);
     692         1111 : }
     693              : 
     694              : void
     695            0 : UnsafeChecker::visit (AwaitExpr &)
     696              : {
     697              :   // TODO: Visit expression
     698            0 : }
     699              : 
     700              : void
     701            0 : UnsafeChecker::visit (AsyncBlockExpr &)
     702              : {
     703              :   // TODO: Visit block expression
     704            0 : }
     705              : 
     706              : void
     707           27 : UnsafeChecker::visit (InlineAsm &expr)
     708              : {
     709           27 :   if (unsafe_context.is_in_context ())
     710              :     {
     711           26 :       mark_unsafe_used ();
     712           26 :       return;
     713              :     }
     714              : 
     715            1 :   rust_error_at (
     716            1 :     expr.get_locus (), ErrorCode::E0133,
     717              :     "use of inline assembly is unsafe and requires unsafe function or block");
     718              : }
     719              : 
     720              : void
     721            2 : UnsafeChecker::visit (LlvmInlineAsm &expr)
     722              : {
     723            2 :   if (unsafe_context.is_in_context ())
     724              :     {
     725            2 :       mark_unsafe_used ();
     726            2 :       return;
     727              :     }
     728              : 
     729            0 :   rust_error_at (
     730            0 :     expr.get_locus (), ErrorCode::E0133,
     731              :     "use of inline assembly is unsafe and requires unsafe function or block");
     732              : }
     733              : 
     734              : void
     735           15 : UnsafeChecker::visit (OffsetOf &expr)
     736              : {
     737              :   // nothing to do, offset_of!() is safe
     738           15 : }
     739              : 
     740              : void
     741            0 : UnsafeChecker::visit (TypeParam &)
     742            0 : {}
     743              : 
     744              : void
     745            0 : UnsafeChecker::visit (ConstGenericParam &)
     746            0 : {}
     747              : 
     748              : void
     749            0 : UnsafeChecker::visit (LifetimeWhereClauseItem &)
     750            0 : {}
     751              : 
     752              : void
     753            0 : UnsafeChecker::visit (TypeBoundWhereClauseItem &)
     754            0 : {}
     755              : 
     756              : void
     757         1232 : UnsafeChecker::visit (Module &module)
     758              : {
     759         5379 :   for (auto &item : module.get_items ())
     760         4147 :     item->accept_vis (*this);
     761         1232 : }
     762              : 
     763              : void
     764            0 : UnsafeChecker::visit (ExternCrate &)
     765            0 : {}
     766              : 
     767              : void
     768            0 : UnsafeChecker::visit (UseTreeGlob &)
     769            0 : {}
     770              : 
     771              : void
     772            0 : UnsafeChecker::visit (UseTreeList &)
     773            0 : {}
     774              : 
     775              : void
     776            0 : UnsafeChecker::visit (UseTreeRebind &)
     777            0 : {}
     778              : 
     779              : void
     780            0 : UnsafeChecker::visit (UseDeclaration &)
     781            0 : {}
     782              : 
     783              : void
     784        14489 : UnsafeChecker::visit (Function &function)
     785              : {
     786        14489 :   auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
     787              : 
     788        14489 :   if (is_unsafe_fn)
     789          527 :     unsafe_context.enter (function.get_mappings ().get_hirid ());
     790              : 
     791        14489 :   function.get_definition ().accept_vis (*this);
     792              : 
     793        14489 :   if (is_unsafe_fn)
     794          527 :     unsafe_context.exit ();
     795        14489 : }
     796              : 
     797              : void
     798         1468 : UnsafeChecker::visit (TypeAlias &)
     799              : {
     800              :   // FIXME: What do we need to do to handle type aliasing? Is it possible to
     801              :   // have unsafe types? Type aliases on unsafe functions?
     802         1468 : }
     803              : 
     804              : void
     805         1598 : UnsafeChecker::visit (StructStruct &)
     806         1598 : {}
     807              : 
     808              : void
     809          972 : UnsafeChecker::visit (TupleStruct &)
     810          972 : {}
     811              : 
     812              : void
     813            0 : UnsafeChecker::visit (EnumItem &)
     814            0 : {}
     815              : 
     816              : void
     817            0 : UnsafeChecker::visit (EnumItemTuple &)
     818            0 : {}
     819              : 
     820              : void
     821            0 : UnsafeChecker::visit (EnumItemStruct &)
     822            0 : {}
     823              : 
     824              : void
     825            0 : UnsafeChecker::visit (EnumItemDiscriminant &)
     826            0 : {}
     827              : 
     828              : void
     829          518 : UnsafeChecker::visit (Enum &)
     830          518 : {}
     831              : 
     832              : void
     833          102 : UnsafeChecker::visit (Union &)
     834          102 : {}
     835              : 
     836              : void
     837          528 : UnsafeChecker::visit (ConstantItem &const_item)
     838              : {
     839          528 :   const_item.get_expr ().accept_vis (*this);
     840          528 : }
     841              : 
     842              : void
     843           56 : UnsafeChecker::visit (StaticItem &static_item)
     844              : {
     845           56 :   static_item.get_expr ().accept_vis (*this);
     846           56 : }
     847              : 
     848              : void
     849         2683 : UnsafeChecker::visit (TraitItemFunc &item)
     850              : {
     851         2683 :   if (item.has_definition ())
     852          861 :     item.get_block_expr ().accept_vis (*this);
     853         2683 : }
     854              : 
     855              : void
     856           32 : UnsafeChecker::visit (TraitItemConst &item)
     857              : {
     858           32 :   if (item.has_expr ())
     859            7 :     item.get_expr ().accept_vis (*this);
     860           32 : }
     861              : 
     862              : void
     863          786 : UnsafeChecker::visit (TraitItemType &)
     864          786 : {}
     865              : 
     866              : void
     867         3999 : UnsafeChecker::visit (Trait &trait)
     868              : {
     869              :   // FIXME: Handle unsafe traits
     870         7500 :   for (auto &item : trait.get_trait_items ())
     871         3501 :     item->accept_vis (*this);
     872         3999 : }
     873              : 
     874              : void
     875         6321 : UnsafeChecker::visit (ImplBlock &impl)
     876              : {
     877         6321 :   bool safe = !impl.is_unsafe ();
     878              :   // Check for unsafe-only attributes on generics and lifetimes
     879         6321 :   if (safe)
     880         7364 :     for (auto &parm : impl.get_generic_params ())
     881              :       {
     882         1115 :         for (auto o_attr : parm->get_outer_attrs ())
     883              :           {
     884            2 :             rust_assert (!o_attr.is_inner_attribute ());
     885              : 
     886            2 :             Rust::AST::SimplePath path = o_attr.get_path ();
     887            2 :             if (path == Values::Attributes::MAY_DANGLE)
     888            2 :               rust_error_at (
     889              :                 o_attr.get_locus (), ErrorCode::E0569,
     890              :                 "use of %<may_dangle%> is unsafe and requires unsafe impl");
     891            2 :           }
     892              :       }
     893              : 
     894        15647 :   for (auto &item : impl.get_impl_items ())
     895         9326 :     item->accept_vis (*this);
     896         6321 : }
     897              : 
     898              : void
     899            1 : UnsafeChecker::visit (ExternalStaticItem &)
     900            1 : {}
     901              : 
     902              : void
     903         2668 : UnsafeChecker::visit (ExternalFunctionItem &)
     904         2668 : {}
     905              : 
     906              : void
     907            2 : UnsafeChecker::visit (ExternalTypeItem &)
     908            2 : {}
     909              : 
     910              : void
     911         1701 : UnsafeChecker::visit (ExternBlock &block)
     912              : {
     913              :   // FIXME: Do we need to do this?
     914         4372 :   for (auto &item : block.get_extern_items ())
     915         2671 :     item->accept_vis (*this);
     916         1701 : }
     917              : 
     918              : void
     919            0 : UnsafeChecker::visit (LiteralPattern &)
     920            0 : {}
     921              : 
     922              : void
     923            0 : UnsafeChecker::visit (IdentifierPattern &)
     924            0 : {}
     925              : 
     926              : void
     927            0 : UnsafeChecker::visit (WildcardPattern &)
     928            0 : {}
     929              : 
     930              : void
     931            0 : UnsafeChecker::visit (RangePatternBoundLiteral &)
     932            0 : {}
     933              : 
     934              : void
     935            0 : UnsafeChecker::visit (RangePatternBoundPath &)
     936            0 : {}
     937              : 
     938              : void
     939            0 : UnsafeChecker::visit (RangePatternBoundQualPath &)
     940            0 : {}
     941              : 
     942              : void
     943            0 : UnsafeChecker::visit (RangePattern &)
     944            0 : {}
     945              : 
     946              : void
     947            0 : UnsafeChecker::visit (ReferencePattern &)
     948            0 : {}
     949              : 
     950              : void
     951            0 : UnsafeChecker::visit (StructPatternFieldTuplePat &)
     952            0 : {}
     953              : 
     954              : void
     955            0 : UnsafeChecker::visit (StructPatternFieldIdentPat &)
     956            0 : {}
     957              : 
     958              : void
     959            0 : UnsafeChecker::visit (StructPatternFieldIdent &)
     960            0 : {}
     961              : 
     962              : void
     963            0 : UnsafeChecker::visit (StructPattern &)
     964            0 : {}
     965              : 
     966              : void
     967            0 : UnsafeChecker::visit (TupleStructItemsNoRest &)
     968            0 : {}
     969              : 
     970              : void
     971            0 : UnsafeChecker::visit (TupleStructItemsHasRest &)
     972            0 : {}
     973              : 
     974              : void
     975            0 : UnsafeChecker::visit (TupleStructPattern &)
     976            0 : {}
     977              : 
     978              : void
     979            0 : UnsafeChecker::visit (TuplePatternItemsNoRest &)
     980            0 : {}
     981              : 
     982              : void
     983            0 : UnsafeChecker::visit (TuplePatternItemsHasRest &)
     984            0 : {}
     985              : 
     986              : void
     987            0 : UnsafeChecker::visit (TuplePattern &)
     988            0 : {}
     989              : 
     990              : void
     991            0 : UnsafeChecker::visit (SlicePatternItemsNoRest &)
     992            0 : {}
     993              : 
     994              : void
     995            0 : UnsafeChecker::visit (SlicePatternItemsHasRest &)
     996            0 : {}
     997              : 
     998              : void
     999            0 : UnsafeChecker::visit (SlicePattern &)
    1000            0 : {}
    1001              : 
    1002              : void
    1003            0 : UnsafeChecker::visit (AltPattern &)
    1004            0 : {}
    1005              : 
    1006              : void
    1007           45 : UnsafeChecker::visit (EmptyStmt &)
    1008           45 : {}
    1009              : 
    1010              : void
    1011        13276 : UnsafeChecker::visit (LetStmt &stmt)
    1012              : {
    1013        13276 :   if (stmt.has_init_expr ())
    1014        12133 :     stmt.get_init_expr ().accept_vis (*this);
    1015        13276 : }
    1016              : 
    1017              : void
    1018        11207 : UnsafeChecker::visit (ExprStmt &stmt)
    1019              : {
    1020        11207 :   stmt.get_expr ().accept_vis (*this);
    1021        11207 : }
    1022              : 
    1023              : void
    1024            0 : UnsafeChecker::visit (TraitBound &)
    1025            0 : {}
    1026              : 
    1027              : void
    1028            0 : UnsafeChecker::visit (ImplTraitType &)
    1029            0 : {}
    1030              : 
    1031              : void
    1032            0 : UnsafeChecker::visit (TraitObjectType &)
    1033            0 : {}
    1034              : 
    1035              : void
    1036            0 : UnsafeChecker::visit (ParenthesisedType &)
    1037            0 : {}
    1038              : 
    1039              : void
    1040            0 : UnsafeChecker::visit (TupleType &)
    1041            0 : {}
    1042              : 
    1043              : void
    1044            0 : UnsafeChecker::visit (NeverType &)
    1045            0 : {}
    1046              : 
    1047              : void
    1048            0 : UnsafeChecker::visit (RawPointerType &)
    1049            0 : {}
    1050              : 
    1051              : void
    1052            0 : UnsafeChecker::visit (ReferenceType &)
    1053            0 : {}
    1054              : 
    1055              : void
    1056            0 : UnsafeChecker::visit (ArrayType &)
    1057            0 : {}
    1058              : 
    1059              : void
    1060            0 : UnsafeChecker::visit (SliceType &)
    1061            0 : {}
    1062              : 
    1063              : void
    1064            0 : UnsafeChecker::visit (InferredType &)
    1065            0 : {}
    1066              : 
    1067              : void
    1068            0 : UnsafeChecker::visit (BareFunctionType &)
    1069            0 : {}
    1070              : 
    1071              : } // namespace HIR
    1072              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.