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