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