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