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.2 % 536 403
Test Date: 2026-10-24 16:24:59 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         4532 : UnsafeChecker::UnsafeChecker ()
      35         4532 :   : context (*Resolver::TypeCheckContext::get ()),
      36         4532 :     resolver (Resolver2_0::FinalizedNameResolutionContext::get ()),
      37         9064 :     mappings (Analysis::Mappings::get ())
      38         4532 : {}
      39              : 
      40              : void
      41         4532 : UnsafeChecker::go (HIR::Crate &crate)
      42              : {
      43        23939 :   for (auto &item : crate.get_items ())
      44        19407 :     item->accept_vis (*this);
      45         4532 : }
      46              : 
      47              : void
      48         4614 : UnsafeChecker::mark_unsafe_used ()
      49              : {
      50         4614 :   if (unsafe_context.is_in_context ())
      51         4614 :     used_unsafe_blocks.insert (unsafe_context.peek ());
      52         4614 : }
      53              : 
      54              : static bool
      55          897 : check_static_mut (HIR::Item *maybe_static, location_t locus, bool in_context)
      56              : {
      57          897 :   if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
      58              :     {
      59          897 :       auto item = static_cast<Item *> (maybe_static);
      60          897 :       if (item->get_item_kind () == Item::ItemKind::Static)
      61              :         {
      62           79 :           auto static_item = static_cast<StaticItem *> (item);
      63           79 :           if (static_item->is_mut ())
      64              :             {
      65           52 :               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        32962 : UnsafeChecker::check_use_of_static (HirId node_id, location_t locus)
      91              : {
      92        32962 :   bool in_context = unsafe_context.is_in_context ();
      93        32962 :   bool unsafe_op = false;
      94              : 
      95        32962 :   if (auto maybe_static_mut = mappings.hir.items.lookup (node_id))
      96          897 :     unsafe_op |= check_static_mut (*maybe_static_mut, locus, in_context);
      97              : 
      98        32962 :   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        32962 :   if (unsafe_op && in_context)
     104           49 :     mark_unsafe_used ();
     105        32962 : }
     106              : 
     107              : static bool
     108         5734 : check_unsafe_call (HIR::Function *fn, location_t locus, const std::string &kind,
     109              :                    bool in_context)
     110              : {
     111         5734 :   if (fn->get_qualifiers ().is_unsafe ())
     112              :     {
     113          615 :       if (!in_context)
     114            5 :         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         4033 : is_safe_intrinsic (const std::string &fn_name)
     124              : {
     125         4033 :   using Intrinsics = Values::Intrinsics;
     126              : 
     127         4033 :   static const std::unordered_set<std::string> safe_intrinsics = {
     128          481 :     Intrinsics::ABORT,
     129          481 :     Intrinsics::SIZE_OF,
     130          481 :     Intrinsics::MIN_ALIGN_OF,
     131          481 :     Intrinsics::NEEDS_DROP,
     132          481 :     Intrinsics::CALLER_LOCATION,
     133          481 :     Intrinsics::ADD_WITH_OVERFLOW,
     134          481 :     Intrinsics::SUB_WITH_OVERFLOW,
     135          481 :     Intrinsics::MUL_WITH_OVERFLOW,
     136          481 :     Intrinsics::WRAPPING_ADD,
     137          481 :     Intrinsics::WRAPPING_SUB,
     138          481 :     Intrinsics::WRAPPING_MUL,
     139          481 :     Intrinsics::SATURATING_ADD,
     140          481 :     Intrinsics::SATURATING_SUB,
     141          481 :     Intrinsics::ROTATE_LEFT,
     142          481 :     Intrinsics::ROTATE_RIGHT,
     143          481 :     Intrinsics::CTPOP,
     144          481 :     Intrinsics::CTLZ,
     145          481 :     Intrinsics::CTTZ,
     146          481 :     Intrinsics::BSWAP,
     147          481 :     Intrinsics::BITREVERSE,
     148          481 :     Intrinsics::DISCRIMINANT_VALUE,
     149          481 :     Intrinsics::TYPE_ID,
     150          481 :     Intrinsics::LIKELY,
     151          481 :     Intrinsics::UNLIKELY,
     152          481 :     Intrinsics::PTR_GUARANTEED_EQ,
     153          481 :     Intrinsics::PTR_GUARANTEED_NE,
     154          481 :     Intrinsics::MINNUMF32,
     155          481 :     Intrinsics::MINNUMF64,
     156          481 :     Intrinsics::MAXNUMF32,
     157          481 :     Intrinsics::MAXNUMF64,
     158          481 :     Intrinsics::RUSTC_PEEK,
     159          481 :     Intrinsics::TYPE_NAME,
     160          481 :     Intrinsics::FORGET,
     161          481 :     Intrinsics::BLACK_BOX,
     162          481 :     Intrinsics::VARIANT_COUNT,
     163        20868 :   };
     164              : 
     165         4033 :   return safe_intrinsics.find (fn_name) != safe_intrinsics.end ();
     166              : }
     167              : 
     168              : static bool
     169         5955 : 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         5955 :   if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function)
     182              :     return false;
     183              : 
     184              :   // Some intrinsics are safe to call
     185        11910 :   if (parent_block->get_abi () == Rust::ABI::INTRINSIC
     186        14021 :       && is_safe_intrinsic (maybe_fn->get_item_name ().as_string ()))
     187              :     return false;
     188              : 
     189         3442 :   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        13207 : UnsafeChecker::check_function_call (HirId node_id, location_t locus)
     197              : {
     198        13207 :   bool in_context = unsafe_context.is_in_context ();
     199        13207 :   bool unsafe_op = false;
     200              : 
     201        13207 :   auto maybe_fn = mappings.hir.items.lookup (node_id);
     202              : 
     203        13207 :   if (maybe_fn
     204        13207 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function)
     205         3708 :     unsafe_op |= check_unsafe_call (static_cast<Function *> (*maybe_fn), locus,
     206         7416 :                                     "function", in_context);
     207              : 
     208        13207 :   if (auto maybe_extern = mappings.lookup_hir_extern_item (node_id))
     209         5955 :     unsafe_op
     210         5955 :       |= check_extern_call (static_cast<ExternalItem *> (maybe_extern->first),
     211         5955 :                             *mappings.hir.extern_blocks.lookup (
     212         5955 :                               maybe_extern->second),
     213              :                             locus, in_context);
     214              : 
     215        13207 :   if (unsafe_op && in_context)
     216         3752 :     mark_unsafe_used ();
     217        13207 : }
     218              : 
     219              : static bool
     220         3708 : check_target_attr (HIR::Function *fn, location_t locus, bool in_context)
     221              : {
     222         3708 :   if (std::any_of (fn->get_outer_attrs ().begin (),
     223         3708 :                    fn->get_outer_attrs ().end (),
     224           51 :                    [] (const AST::Attribute &attr) {
     225           51 :                      return attr.get_path ().as_string ()
     226           51 :                             == 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        13207 : UnsafeChecker::check_function_attr (HirId node_id, location_t locus)
     240              : {
     241        13207 :   bool in_context = unsafe_context.is_in_context ();
     242              : 
     243        13207 :   auto maybe_fn = mappings.hir.items.lookup (node_id);
     244              : 
     245        13207 :   if (maybe_fn
     246         4581 :       && maybe_fn.value ()->get_item_kind () == Item::ItemKind::Function
     247         3708 :       && check_target_attr (static_cast<Function *> (*maybe_fn), locus,
     248              :                             in_context)
     249        13209 :       && in_context)
     250            1 :     mark_unsafe_used ();
     251        13207 : }
     252              : 
     253              : void
     254            0 : UnsafeChecker::visit (Lifetime &)
     255            0 : {}
     256              : 
     257              : void
     258            0 : UnsafeChecker::visit (LifetimeParam &)
     259            0 : {}
     260              : 
     261              : void
     262        32962 : UnsafeChecker::visit (PathInExpression &path)
     263              : {
     264        32962 :   NodeId ast_node_id = path.get_mappings ().get_nodeid ();
     265        32962 :   NodeId ref_node_id;
     266              : 
     267        65924 :   if (auto resolved
     268        32962 :       = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values,
     269        32962 :                          Resolver2_0::Namespace::Types))
     270        32962 :     ref_node_id = resolved->id;
     271              :   else
     272            0 :     return;
     273              : 
     274        32962 :   if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
     275              :     {
     276        32962 :       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        20700 : UnsafeChecker::visit (LiteralExpr &)
     310        20700 : {}
     311              : 
     312              : void
     313         2128 : UnsafeChecker::visit (BorrowExpr &expr)
     314              : {
     315         2128 :   expr.get_expr ().accept_vis (*this);
     316         2128 : }
     317              : 
     318              : void
     319         4276 : UnsafeChecker::visit (DereferenceExpr &expr)
     320              : {
     321         4276 :   TyTy::BaseType *to_deref_type;
     322         4276 :   auto to_deref = expr.get_expr ().get_mappings ().get_hirid ();
     323              : 
     324         4276 :   rust_assert (context.lookup_type (to_deref, &to_deref_type));
     325              : 
     326         4276 :   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         4276 : }
     335              : 
     336              : void
     337            0 : UnsafeChecker::visit (ErrorPropagationExpr &expr)
     338              : {
     339            0 :   expr.get_expr ().accept_vis (*this);
     340            0 : }
     341              : 
     342              : void
     343          611 : UnsafeChecker::visit (NegationExpr &expr)
     344              : {
     345          611 :   expr.get_expr ().accept_vis (*this);
     346          611 : }
     347              : 
     348              : void
     349         3651 : UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
     350              : {
     351         3651 :   expr.get_lhs ().accept_vis (*this);
     352         3651 :   expr.get_rhs ().accept_vis (*this);
     353         3651 : }
     354              : 
     355              : void
     356         3894 : UnsafeChecker::visit (ComparisonExpr &expr)
     357              : {
     358         3894 :   expr.get_lhs ().accept_vis (*this);
     359         3894 :   expr.get_rhs ().accept_vis (*this);
     360         3894 : }
     361              : 
     362              : void
     363          480 : UnsafeChecker::visit (LazyBooleanExpr &expr)
     364              : {
     365          480 :   expr.get_lhs ().accept_vis (*this);
     366          480 :   expr.get_rhs ().accept_vis (*this);
     367          480 : }
     368              : 
     369              : void
     370         5667 : UnsafeChecker::visit (TypeCastExpr &expr)
     371              : {
     372         5667 :   expr.get_expr ().accept_vis (*this);
     373         5667 : }
     374              : 
     375              : void
     376         2552 : UnsafeChecker::visit (AssignmentExpr &expr)
     377              : {
     378         2552 :   expr.get_lhs ().accept_vis (*this);
     379         2552 :   expr.get_rhs ().accept_vis (*this);
     380         2552 : }
     381              : 
     382              : void
     383          719 : UnsafeChecker::visit (CompoundAssignmentExpr &expr)
     384              : {
     385          719 :   expr.get_lhs ().accept_vis (*this);
     386          719 :   expr.get_rhs ().accept_vis (*this);
     387          719 : }
     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          116 : UnsafeChecker::visit (ArrayElemsCopied &elems)
     404              : {
     405          116 :   elems.get_elem_to_copy ().accept_vis (*this);
     406          116 : }
     407              : 
     408              : void
     409          414 : UnsafeChecker::visit (ArrayExpr &expr)
     410              : {
     411          414 :   expr.get_internal_elements ().accept_vis (*this);
     412          414 : }
     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          620 : UnsafeChecker::visit (TupleExpr &expr)
     423              : {
     424         1715 :   for (auto &elem : expr.get_tuple_elems ())
     425         1095 :     elem->accept_vis (*this);
     426          620 : }
     427              : 
     428              : void
     429          912 : UnsafeChecker::visit (TupleIndexExpr &expr)
     430              : {
     431          912 :   expr.get_tuple_expr ().accept_vis (*this);
     432          912 : }
     433              : 
     434              : void
     435           79 : UnsafeChecker::visit (StructExprStruct &)
     436           79 : {}
     437              : 
     438              : void
     439          235 : UnsafeChecker::visit (StructExprFieldIdentifier &)
     440          235 : {}
     441              : 
     442              : void
     443         2738 : UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
     444              : {
     445         2738 :   field.get_value ().accept_vis (*this);
     446         2738 : }
     447              : 
     448              : void
     449           42 : UnsafeChecker::visit (StructExprFieldIndexValue &field)
     450              : {
     451           42 :   field.get_value ().accept_vis (*this);
     452           42 : }
     453              : 
     454              : void
     455         1412 : UnsafeChecker::visit (StructExprStructFields &expr)
     456              : {
     457         4427 :   for (auto &field : expr.get_fields ())
     458         3015 :     field->accept_vis (*this);
     459         1412 : }
     460              : 
     461              : void
     462            0 : UnsafeChecker::visit (StructExprStructBase &)
     463            0 : {}
     464              : 
     465              : void
     466        13277 : UnsafeChecker::visit (CallExpr &expr)
     467              : {
     468        13277 :   if (!expr.has_fnexpr ())
     469              :     return;
     470              : 
     471        13277 :   NodeId ast_node_id = expr.get_fnexpr ().get_mappings ().get_nodeid ();
     472        13277 :   NodeId ref_node_id;
     473              : 
     474        13277 :   if (auto resolved
     475        13277 :       = resolver.lookup (ast_node_id, Resolver2_0::Namespace::Values))
     476        13207 :     ref_node_id = resolved.value ();
     477              :   else
     478           70 :     return;
     479              : 
     480        13207 :   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        13207 :       check_function_call (*definition_id, expr.get_locus ());
     488        13207 :       check_function_attr (*definition_id, expr.get_locus ());
     489              : 
     490        13207 :       if (expr.has_params ())
     491        25794 :         for (auto &arg : expr.get_arguments ())
     492        15194 :           arg->accept_vis (*this);
     493              :     }
     494              :   else
     495              :     {
     496            0 :       rust_unreachable ();
     497              :     }
     498              : }
     499              : 
     500              : void
     501         3012 : UnsafeChecker::visit (MethodCallExpr &expr)
     502              : {
     503         3012 :   TyTy::BaseType *method_type;
     504         3012 :   context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
     505              :                        &method_type);
     506         3012 :   if (!method_type || !method_type->is<TyTy::FnType> ())
     507            0 :     return;
     508              : 
     509         3012 :   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         3012 :   auto method = mappings.lookup_hir_implitem (fn.get_ref ());
     515         3012 :   if (method
     516         2026 :       && check_unsafe_call (static_cast<Function *> (method->first),
     517         5038 :                             expr.get_locus (), "method",
     518              :                             unsafe_context.is_in_context ())
     519         3312 :       && unsafe_context.is_in_context ())
     520          299 :     mark_unsafe_used ();
     521              : 
     522         3012 :   expr.get_receiver ().accept_vis (*this);
     523              : 
     524         5044 :   for (auto &arg : expr.get_arguments ())
     525         2032 :     arg->accept_vis (*this);
     526              : }
     527              : 
     528              : void
     529         5710 : UnsafeChecker::visit (FieldAccessExpr &expr)
     530              : {
     531         5710 :   expr.get_receiver_expr ().accept_vis (*this);
     532              : 
     533         5710 :   TyTy::BaseType *receiver_ty;
     534         5710 :   if (!context.lookup_type (
     535         5710 :         expr.get_receiver_expr ().get_mappings ().get_hirid (), &receiver_ty))
     536            0 :     return;
     537              : 
     538         5710 :   if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
     539              :     {
     540         2206 :       auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
     541         2206 :       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        25032 : UnsafeChecker::visit (BlockExpr &expr)
     561              : {
     562        50200 :   for (auto &stmt : expr.get_statements ())
     563        25168 :     stmt->accept_vis (*this);
     564              : 
     565        25032 :   if (expr.has_expr ())
     566        18103 :     expr.get_final_expr ().accept_vis (*this);
     567        25032 : }
     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          630 : UnsafeChecker::visit (ReturnExpr &expr)
     629              : {
     630          630 :   if (expr.has_return_expr ())
     631          594 :     expr.get_expr ().accept_vis (*this);
     632          630 : }
     633              : 
     634              : void
     635         4034 : UnsafeChecker::visit (UnsafeBlockExpr &expr)
     636              : {
     637         4034 :   auto id = expr.get_mappings ().get_hirid ();
     638         4034 :   unsafe_context.enter (id);
     639              : 
     640         4034 :   expr.get_block_expr ().accept_vis (*this);
     641              : 
     642         4034 :   unsafe_context.exit ();
     643              : 
     644         4034 :   if (flag_unused_check_2_0
     645         4034 :       && used_unsafe_blocks.find (id) == used_unsafe_blocks.end ())
     646            1 :     rust_warning_at (expr.get_locus (), OPT_Wunused,
     647              :                      "unnecessary %<unsafe%> block");
     648         4034 : }
     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         1342 : UnsafeChecker::visit (IfExpr &expr)
     672              : {
     673         1342 :   expr.get_if_condition ().accept_vis (*this);
     674         1342 :   expr.get_if_block ().accept_vis (*this);
     675         1342 : }
     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         1150 : UnsafeChecker::visit (MatchExpr &expr)
     687              : {
     688         1150 :   expr.get_scrutinee_expr ().accept_vis (*this);
     689              : 
     690         3818 :   for (auto &match_arm : expr.get_match_cases ())
     691              :     {
     692         2668 :       if (match_arm.get_arm ().has_match_arm_guard ())
     693           60 :         match_arm.get_arm ().get_guard_expr ().accept_vis (*this);
     694         2668 :       match_arm.get_expr ().accept_vis (*this);
     695              :     }
     696         1150 : }
     697              : 
     698              : void
     699            0 : UnsafeChecker::visit (AwaitExpr &)
     700              : {
     701              :   // TODO: Visit expression
     702            0 : }
     703              : 
     704              : void
     705            0 : UnsafeChecker::visit (AsyncBlockExpr &)
     706              : {
     707              :   // TODO: Visit block expression
     708            0 : }
     709              : 
     710              : void
     711           27 : UnsafeChecker::visit (InlineAsm &expr)
     712              : {
     713           27 :   if (unsafe_context.is_in_context ())
     714              :     {
     715           26 :       mark_unsafe_used ();
     716           26 :       return;
     717              :     }
     718              : 
     719            1 :   rust_error_at (
     720            1 :     expr.get_locus (), ErrorCode::E0133,
     721              :     "use of inline assembly is unsafe and requires unsafe function or block");
     722              : }
     723              : 
     724              : void
     725            2 : UnsafeChecker::visit (LlvmInlineAsm &expr)
     726              : {
     727            2 :   if (unsafe_context.is_in_context ())
     728              :     {
     729            2 :       mark_unsafe_used ();
     730            2 :       return;
     731              :     }
     732              : 
     733            0 :   rust_error_at (
     734            0 :     expr.get_locus (), ErrorCode::E0133,
     735              :     "use of inline assembly is unsafe and requires unsafe function or block");
     736              : }
     737              : 
     738              : void
     739           15 : UnsafeChecker::visit (OffsetOf &expr)
     740              : {
     741              :   // nothing to do, offset_of!() is safe
     742           15 : }
     743              : 
     744              : void
     745            0 : UnsafeChecker::visit (TypeParam &)
     746            0 : {}
     747              : 
     748              : void
     749            0 : UnsafeChecker::visit (ConstGenericParam &)
     750            0 : {}
     751              : 
     752              : void
     753            0 : UnsafeChecker::visit (LifetimeWhereClauseItem &)
     754            0 : {}
     755              : 
     756              : void
     757            0 : UnsafeChecker::visit (TypeBoundWhereClauseItem &)
     758            0 : {}
     759              : 
     760              : void
     761         1232 : UnsafeChecker::visit (Module &module)
     762              : {
     763         5379 :   for (auto &item : module.get_items ())
     764         4147 :     item->accept_vis (*this);
     765         1232 : }
     766              : 
     767              : void
     768            0 : UnsafeChecker::visit (ExternCrate &)
     769            0 : {}
     770              : 
     771              : void
     772            0 : UnsafeChecker::visit (UseTreeGlob &)
     773            0 : {}
     774              : 
     775              : void
     776            0 : UnsafeChecker::visit (UseTreeList &)
     777            0 : {}
     778              : 
     779              : void
     780            0 : UnsafeChecker::visit (UseTreeRebind &)
     781            0 : {}
     782              : 
     783              : void
     784            0 : UnsafeChecker::visit (UseDeclaration &)
     785            0 : {}
     786              : 
     787              : void
     788        14619 : UnsafeChecker::visit (Function &function)
     789              : {
     790        14619 :   auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
     791              : 
     792        14619 :   if (is_unsafe_fn)
     793          528 :     unsafe_context.enter (function.get_mappings ().get_hirid ());
     794              : 
     795        14619 :   function.get_definition ().accept_vis (*this);
     796              : 
     797        14619 :   if (is_unsafe_fn)
     798          528 :     unsafe_context.exit ();
     799        14619 : }
     800              : 
     801              : void
     802         1483 : UnsafeChecker::visit (TypeAlias &)
     803              : {
     804              :   // FIXME: What do we need to do to handle type aliasing? Is it possible to
     805              :   // have unsafe types? Type aliases on unsafe functions?
     806         1483 : }
     807              : 
     808              : void
     809         1629 : UnsafeChecker::visit (StructStruct &)
     810         1629 : {}
     811              : 
     812              : void
     813          987 : UnsafeChecker::visit (TupleStruct &)
     814          987 : {}
     815              : 
     816              : void
     817            0 : UnsafeChecker::visit (EnumItem &)
     818            0 : {}
     819              : 
     820              : void
     821            0 : UnsafeChecker::visit (EnumItemTuple &)
     822            0 : {}
     823              : 
     824              : void
     825            0 : UnsafeChecker::visit (EnumItemStruct &)
     826            0 : {}
     827              : 
     828              : void
     829            0 : UnsafeChecker::visit (EnumItemDiscriminant &)
     830            0 : {}
     831              : 
     832              : void
     833          530 : UnsafeChecker::visit (Enum &)
     834          530 : {}
     835              : 
     836              : void
     837          102 : UnsafeChecker::visit (Union &)
     838          102 : {}
     839              : 
     840              : void
     841          543 : UnsafeChecker::visit (ConstantItem &const_item)
     842              : {
     843          543 :   const_item.get_expr ().accept_vis (*this);
     844          543 : }
     845              : 
     846              : void
     847           75 : UnsafeChecker::visit (StaticItem &static_item)
     848              : {
     849           75 :   static_item.get_expr ().accept_vis (*this);
     850           75 : }
     851              : 
     852              : void
     853         2703 : UnsafeChecker::visit (TraitItemFunc &item)
     854              : {
     855         2703 :   if (item.has_definition ())
     856          861 :     item.get_block_expr ().accept_vis (*this);
     857         2703 : }
     858              : 
     859              : void
     860           32 : UnsafeChecker::visit (TraitItemConst &item)
     861              : {
     862           32 :   if (item.has_expr ())
     863            7 :     item.get_expr ().accept_vis (*this);
     864           32 : }
     865              : 
     866              : void
     867          804 : UnsafeChecker::visit (TraitItemType &)
     868          804 : {}
     869              : 
     870              : void
     871         4063 : UnsafeChecker::visit (Trait &trait)
     872              : {
     873              :   // FIXME: Handle unsafe traits
     874         7602 :   for (auto &item : trait.get_trait_items ())
     875         3539 :     item->accept_vis (*this);
     876         4063 : }
     877              : 
     878              : void
     879         6350 : UnsafeChecker::visit (ImplBlock &impl)
     880              : {
     881         6350 :   bool safe = !impl.is_unsafe ();
     882              :   // Check for unsafe-only attributes on generics and lifetimes
     883         6350 :   if (safe)
     884         7415 :     for (auto &parm : impl.get_generic_params ())
     885              :       {
     886         1138 :         for (auto o_attr : parm->get_outer_attrs ())
     887              :           {
     888            2 :             rust_assert (!o_attr.is_inner_attribute ());
     889              : 
     890            2 :             Rust::AST::SimplePath path = o_attr.get_path ();
     891            2 :             if (path == Values::Attributes::MAY_DANGLE)
     892            2 :               rust_error_at (
     893              :                 o_attr.get_locus (), ErrorCode::E0569,
     894              :                 "use of %<may_dangle%> is unsafe and requires unsafe impl");
     895            2 :           }
     896              :       }
     897              : 
     898        15712 :   for (auto &item : impl.get_impl_items ())
     899         9362 :     item->accept_vis (*this);
     900         6350 : }
     901              : 
     902              : void
     903            1 : UnsafeChecker::visit (ExternalStaticItem &)
     904            1 : {}
     905              : 
     906              : void
     907         2681 : UnsafeChecker::visit (ExternalFunctionItem &)
     908         2681 : {}
     909              : 
     910              : void
     911            2 : UnsafeChecker::visit (ExternalTypeItem &)
     912            2 : {}
     913              : 
     914              : void
     915         1710 : UnsafeChecker::visit (ExternBlock &block)
     916              : {
     917              :   // FIXME: Do we need to do this?
     918         4394 :   for (auto &item : block.get_extern_items ())
     919         2684 :     item->accept_vis (*this);
     920         1710 : }
     921              : 
     922              : void
     923            0 : UnsafeChecker::visit (LiteralPattern &)
     924            0 : {}
     925              : 
     926              : void
     927            0 : UnsafeChecker::visit (IdentifierPattern &)
     928            0 : {}
     929              : 
     930              : void
     931            0 : UnsafeChecker::visit (WildcardPattern &)
     932            0 : {}
     933              : 
     934              : void
     935            0 : UnsafeChecker::visit (RangePatternBoundLiteral &)
     936            0 : {}
     937              : 
     938              : void
     939            0 : UnsafeChecker::visit (RangePatternBoundPath &)
     940            0 : {}
     941              : 
     942              : void
     943            0 : UnsafeChecker::visit (RangePatternBoundQualPath &)
     944            0 : {}
     945              : 
     946              : void
     947            0 : UnsafeChecker::visit (RangePattern &)
     948            0 : {}
     949              : 
     950              : void
     951            0 : UnsafeChecker::visit (ReferencePattern &)
     952            0 : {}
     953              : 
     954              : void
     955            0 : UnsafeChecker::visit (StructPatternFieldTuplePat &)
     956            0 : {}
     957              : 
     958              : void
     959            0 : UnsafeChecker::visit (StructPatternFieldIdentPat &)
     960            0 : {}
     961              : 
     962              : void
     963            0 : UnsafeChecker::visit (StructPatternFieldIdent &)
     964            0 : {}
     965              : 
     966              : void
     967            0 : UnsafeChecker::visit (StructPattern &)
     968            0 : {}
     969              : 
     970              : void
     971            0 : UnsafeChecker::visit (TupleStructItemsNoRest &)
     972            0 : {}
     973              : 
     974              : void
     975            0 : UnsafeChecker::visit (TupleStructItemsHasRest &)
     976            0 : {}
     977              : 
     978              : void
     979            0 : UnsafeChecker::visit (TupleStructPattern &)
     980            0 : {}
     981              : 
     982              : void
     983            0 : UnsafeChecker::visit (TuplePatternItemsNoRest &)
     984            0 : {}
     985              : 
     986              : void
     987            0 : UnsafeChecker::visit (TuplePatternItemsHasRest &)
     988            0 : {}
     989              : 
     990              : void
     991            0 : UnsafeChecker::visit (TuplePattern &)
     992            0 : {}
     993              : 
     994              : void
     995            0 : UnsafeChecker::visit (SlicePatternItemsNoRest &)
     996            0 : {}
     997              : 
     998              : void
     999            0 : UnsafeChecker::visit (SlicePatternItemsHasRest &)
    1000            0 : {}
    1001              : 
    1002              : void
    1003            0 : UnsafeChecker::visit (SlicePattern &)
    1004            0 : {}
    1005              : 
    1006              : void
    1007            0 : UnsafeChecker::visit (AltPattern &)
    1008            0 : {}
    1009              : 
    1010              : void
    1011           45 : UnsafeChecker::visit (EmptyStmt &)
    1012           45 : {}
    1013              : 
    1014              : void
    1015        13328 : UnsafeChecker::visit (LetStmt &stmt)
    1016              : {
    1017        13328 :   if (stmt.has_init_expr ())
    1018        12184 :     stmt.get_init_expr ().accept_vis (*this);
    1019        13328 : }
    1020              : 
    1021              : void
    1022        11388 : UnsafeChecker::visit (ExprStmt &stmt)
    1023              : {
    1024        11388 :   stmt.get_expr ().accept_vis (*this);
    1025        11388 : }
    1026              : 
    1027              : void
    1028            0 : UnsafeChecker::visit (TraitBound &)
    1029            0 : {}
    1030              : 
    1031              : void
    1032            0 : UnsafeChecker::visit (ImplTraitType &)
    1033            0 : {}
    1034              : 
    1035              : void
    1036            0 : UnsafeChecker::visit (TraitObjectType &)
    1037            0 : {}
    1038              : 
    1039              : void
    1040            0 : UnsafeChecker::visit (ParenthesisedType &)
    1041            0 : {}
    1042              : 
    1043              : void
    1044            0 : UnsafeChecker::visit (TupleType &)
    1045            0 : {}
    1046              : 
    1047              : void
    1048            0 : UnsafeChecker::visit (NeverType &)
    1049            0 : {}
    1050              : 
    1051              : void
    1052            0 : UnsafeChecker::visit (RawPointerType &)
    1053            0 : {}
    1054              : 
    1055              : void
    1056            0 : UnsafeChecker::visit (ReferenceType &)
    1057            0 : {}
    1058              : 
    1059              : void
    1060            0 : UnsafeChecker::visit (ArrayType &)
    1061            0 : {}
    1062              : 
    1063              : void
    1064            0 : UnsafeChecker::visit (SliceType &)
    1065            0 : {}
    1066              : 
    1067              : void
    1068            0 : UnsafeChecker::visit (InferredType &)
    1069            0 : {}
    1070              : 
    1071              : void
    1072            0 : UnsafeChecker::visit (BareFunctionType &)
    1073            0 : {}
    1074              : 
    1075              : } // namespace HIR
    1076              : } // namespace Rust
        

Generated by: LCOV version 2.5.0-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.