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
|