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