]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / checks / errors / privacy / rust-privacy-reporter.cc
1 // Copyright (C) 2020-2023 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-privacy-reporter.h"
20 #include "rust-hir-expr.h"
21 #include "rust-hir-stmt.h"
22 #include "rust-hir-item.h"
23
24 namespace Rust {
25 namespace Privacy {
26
27 PrivacyReporter::PrivacyReporter (
28 Analysis::Mappings &mappings, Resolver::Resolver &resolver,
29 const Rust::Resolver::TypeCheckContext &ty_ctx)
30 : mappings (mappings), resolver (resolver), ty_ctx (ty_ctx),
31 current_module (Optional<NodeId>::none ())
32 {}
33
34 void
35 PrivacyReporter::go (HIR::Crate &crate)
36 {
37 for (auto &item : crate.items)
38 item->accept_vis (*this);
39 }
40
41 static bool
42 is_child_module (Analysis::Mappings &mappings, NodeId parent,
43 NodeId possible_child)
44 {
45 auto children = mappings.lookup_module_children (parent);
46
47 if (!children)
48 return false;
49
50 // Visit all toplevel children
51 for (auto &child : *children)
52 if (child == possible_child)
53 return true;
54
55 // Now descend recursively in the child module tree
56 for (auto &child : *children)
57 if (is_child_module (mappings, child, possible_child))
58 return true;
59
60 return false;
61 }
62
63 // FIXME: This function needs a lot of refactoring
64 void
65 PrivacyReporter::check_for_privacy_violation (const NodeId &use_id,
66 const Location &locus)
67 {
68 NodeId ref_node_id = UNKNOWN_NODEID;
69
70 // FIXME: Don't assert here - we might be dealing with a type
71 if (!resolver.lookup_resolved_name (use_id, &ref_node_id))
72 resolver.lookup_resolved_type (use_id, &ref_node_id);
73
74 // FIXME: Assert here. For now, we return since this causes issues when
75 // checking inferred types (#1260)
76 // rust_assert (ref_node_id != UNKNOWN_NODEID);
77 if (ref_node_id == UNKNOWN_NODEID)
78 return;
79
80 ModuleVisibility vis;
81
82 // FIXME: Can we really return here if the item has no visibility?
83 if (!mappings.lookup_visibility (ref_node_id, vis))
84 return;
85
86 auto valid = true;
87
88 switch (vis.get_kind ())
89 {
90 case ModuleVisibility::Public:
91 break;
92 case ModuleVisibility::Restricted: {
93 // If we are in the crate, everything is restricted correctly, but we
94 // can't get a module for it
95 if (current_module.is_none ())
96 return;
97
98 auto module = mappings.lookup_defid (vis.get_module_id ());
99 rust_assert (module != nullptr);
100
101 auto mod_node_id = module->get_mappings ().get_nodeid ();
102
103 // We are in the module referenced by the pub(restricted) visibility.
104 // This is valid
105 if (mod_node_id == current_module.get ())
106 break;
107
108 // FIXME: This needs a LOT of TLC: hinting about the definition, a
109 // string to say if it's a module, function, type, etc...
110 if (!is_child_module (mappings, mod_node_id, current_module.get ()))
111 valid = false;
112 }
113 break;
114 case ModuleVisibility::Unknown:
115 rust_unreachable ();
116 break;
117 }
118
119 if (!valid)
120 rust_error_at (locus, "definition is private in this context");
121 }
122
123 void
124 PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings,
125 const TyTy::BaseType *ty,
126 const Location &locus)
127 {
128 // Avoids repeating commong argument such as `use_id` or `locus` since we're
129 // doing a lot of recursive calls here
130 auto recursive_check
131 = [this, &node_mappings, &locus] (const TyTy::BaseType *ty) {
132 return check_base_type_privacy (node_mappings, ty, locus);
133 };
134
135 switch (ty->get_kind ())
136 {
137 // These "simple" types are our stop condition
138 case TyTy::BOOL:
139 case TyTy::CHAR:
140 case TyTy::INT:
141 case TyTy::UINT:
142 case TyTy::FLOAT:
143 case TyTy::USIZE:
144 case TyTy::ISIZE:
145 case TyTy::ADT:
146 case TyTy::STR: {
147 auto ref_id = ty->get_ref ();
148 NodeId lookup_id;
149
150 bool ok = mappings.lookup_hir_to_node (ref_id, &lookup_id);
151 rust_assert (ok);
152
153 return check_for_privacy_violation (lookup_id, locus);
154 }
155 case TyTy::REF:
156 return recursive_check (
157 static_cast<const TyTy::ReferenceType *> (ty)->get_base ());
158 case TyTy::POINTER:
159 return recursive_check (
160 static_cast<const TyTy::PointerType *> (ty)->get_base ());
161 case TyTy::ARRAY:
162 return recursive_check (
163 static_cast<const TyTy::ArrayType *> (ty)->get_element_type ());
164 case TyTy::SLICE:
165 return recursive_check (
166 static_cast<const TyTy::SliceType *> (ty)->get_element_type ());
167 case TyTy::FNPTR:
168 for (auto &param : static_cast<const TyTy::FnPtr *> (ty)->get_params ())
169 recursive_check (param.get_tyty ());
170 return recursive_check (
171 static_cast<const TyTy::FnPtr *> (ty)->get_return_type ());
172 case TyTy::TUPLE:
173 for (auto &param :
174 static_cast<const TyTy::TupleType *> (ty)->get_fields ())
175 recursive_check (param.get_tyty ());
176 return;
177 case TyTy::PLACEHOLDER:
178 return recursive_check (
179 // FIXME: Can we use `resolve` here? Is that what we should do?
180 static_cast<const TyTy::PlaceholderType *> (ty)->resolve ());
181 case TyTy::PROJECTION:
182 return recursive_check (
183 static_cast<const TyTy::ProjectionType *> (ty)->get ());
184 case TyTy::CLOSURE:
185 rust_sorry_at (locus, "privacy pass for closures is not handled yet");
186 break;
187
188 // If we're dealing with a generic param, there's nothing we should be
189 // doing here
190 case TyTy::PARAM:
191 // We are dealing with a function definition that has been assigned
192 // somewhere else. Nothing to resolve privacy-wise other than the actual
193 // function, which is resolved as an expression
194 case TyTy::FNDEF:
195 // FIXME: Can we really not resolve Dynamic types here? Shouldn't we have
196 // a look at the path and perform proper privacy analysis?
197 case TyTy::DYNAMIC:
198 // The never type is builtin and always available
199 case TyTy::NEVER:
200 // We shouldn't have inference types here, ever
201 case TyTy::INFER:
202 return;
203 case TyTy::ERROR:
204 rust_unreachable ();
205 }
206 }
207
208 void
209 PrivacyReporter::check_type_privacy (const HIR::Type *type)
210 {
211 rust_assert (type);
212
213 TyTy::BaseType *lookup = nullptr;
214 rust_assert (
215 ty_ctx.lookup_type (type->get_mappings ().get_hirid (), &lookup));
216
217 auto node_mappings = type->get_mappings ();
218 return check_base_type_privacy (node_mappings, lookup, type->get_locus ());
219 }
220
221 void
222 PrivacyReporter::visit (HIR::PathInExpression &path)
223 {
224 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
225 path.get_locus ());
226 }
227
228 void
229 PrivacyReporter::visit (HIR::TypePathSegmentFunction &segment)
230 {
231 // FIXME: Do we need to do anything for this?
232 }
233
234 void
235 PrivacyReporter::visit (HIR::TypePath &path)
236 {
237 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
238 path.get_locus ());
239 }
240
241 void
242 PrivacyReporter::visit (HIR::QualifiedPathInExpression &path)
243 {
244 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
245 path.get_locus ());
246 }
247
248 void
249 PrivacyReporter::visit (HIR::QualifiedPathInType &path)
250 {
251 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
252 path.get_locus ());
253 }
254
255 void
256 PrivacyReporter::visit (HIR::LiteralExpr &expr)
257 {
258 // Literals cannot contain any sort of privacy violation
259 }
260
261 void
262 PrivacyReporter::visit (HIR::BorrowExpr &expr)
263 {
264 expr.get_expr ()->accept_vis (*this);
265 }
266
267 void
268 PrivacyReporter::visit (HIR::DereferenceExpr &expr)
269 {
270 expr.get_expr ()->accept_vis (*this);
271 }
272
273 void
274 PrivacyReporter::visit (HIR::ErrorPropagationExpr &expr)
275 {
276 expr.get_expr ()->accept_vis (*this);
277 }
278
279 void
280 PrivacyReporter::visit (HIR::NegationExpr &expr)
281 {
282 expr.get_expr ()->accept_vis (*this);
283 }
284
285 void
286 PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr &expr)
287 {
288 expr.get_lhs ()->accept_vis (*this);
289 expr.get_rhs ()->accept_vis (*this);
290 }
291
292 void
293 PrivacyReporter::visit (HIR::ComparisonExpr &expr)
294 {
295 expr.get_lhs ()->accept_vis (*this);
296 expr.get_rhs ()->accept_vis (*this);
297 }
298
299 void
300 PrivacyReporter::visit (HIR::LazyBooleanExpr &expr)
301 {
302 expr.get_lhs ()->accept_vis (*this);
303 expr.get_rhs ()->accept_vis (*this);
304 }
305
306 void
307 PrivacyReporter::visit (HIR::TypeCastExpr &expr)
308 {
309 expr.get_expr ()->accept_vis (*this);
310 }
311
312 void
313 PrivacyReporter::visit (HIR::AssignmentExpr &expr)
314 {
315 expr.get_lhs ()->accept_vis (*this);
316 expr.get_rhs ()->accept_vis (*this);
317 }
318
319 void
320 PrivacyReporter::visit (HIR::CompoundAssignmentExpr &expr)
321 {
322 expr.get_left_expr ()->accept_vis (*this);
323 expr.get_right_expr ()->accept_vis (*this);
324 }
325
326 void
327 PrivacyReporter::visit (HIR::GroupedExpr &expr)
328 {
329 expr.get_expr_in_parens ()->accept_vis (*this);
330 }
331
332 void
333 PrivacyReporter::visit (HIR::ArrayExpr &expr)
334 {
335 HIR::ArrayElems &elements = *expr.get_internal_elements ();
336 switch (elements.get_array_expr_type ())
337 {
338 case HIR::ArrayElems::ArrayExprType::VALUES: {
339 HIR::ArrayElemsValues &elems
340 = static_cast<HIR::ArrayElemsValues &> (elements);
341 for (auto &value : elems.get_values ())
342 value->accept_vis (*this);
343 }
344 return;
345
346 case HIR::ArrayElems::ArrayExprType::COPIED:
347 HIR::ArrayElemsCopied &elems
348 = static_cast<HIR::ArrayElemsCopied &> (elements);
349 elems.get_elem_to_copy ()->accept_vis (*this);
350 }
351 }
352
353 void
354 PrivacyReporter::visit (HIR::ArrayIndexExpr &expr)
355 {
356 expr.get_array_expr ()->accept_vis (*this);
357 expr.get_index_expr ()->accept_vis (*this);
358 }
359
360 void
361 PrivacyReporter::visit (HIR::TupleExpr &expr)
362 {
363 for (auto &value : expr.get_tuple_elems ())
364 value->accept_vis (*this);
365 }
366
367 void
368 PrivacyReporter::visit (HIR::TupleIndexExpr &expr)
369 {
370 expr.get_tuple_expr ()->accept_vis (*this);
371 }
372
373 void
374 PrivacyReporter::visit (HIR::StructExprStruct &expr)
375 {
376 // FIXME: We need to check the visibility of the type it refers to here
377 }
378
379 void
380 PrivacyReporter::visit (HIR::StructExprFieldIdentifier &field)
381 {}
382
383 void
384 PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue &field)
385 {
386 field.get_value ()->accept_vis (*this);
387 }
388
389 void
390 PrivacyReporter::visit (HIR::StructExprFieldIndexValue &field)
391 {
392 field.get_value ()->accept_vis (*this);
393 }
394
395 void
396 PrivacyReporter::visit (HIR::StructExprStructFields &expr)
397 {
398 for (auto &field : expr.get_fields ())
399 field->accept_vis (*this);
400 }
401
402 void
403 PrivacyReporter::visit (HIR::CallExpr &expr)
404 {
405 expr.get_fnexpr ()->accept_vis (*this);
406
407 for (auto &param : expr.get_arguments ())
408 param->accept_vis (*this);
409 }
410
411 void
412 PrivacyReporter::visit (HIR::MethodCallExpr &expr)
413 {
414 expr.get_receiver ()->accept_vis (*this);
415
416 for (auto &param : expr.get_arguments ())
417 param->accept_vis (*this);
418 }
419
420 void
421 PrivacyReporter::visit (HIR::FieldAccessExpr &expr)
422 {
423 expr.get_receiver_expr ()->accept_vis (*this);
424
425 // FIXME: We should also check if the field is public?
426 }
427
428 void
429 PrivacyReporter::visit (HIR::ClosureExprInner &expr)
430 {
431 // Not handled yet
432 }
433
434 void
435 PrivacyReporter::visit (HIR::BlockExpr &expr)
436 {
437 for (auto &stmt : expr.get_statements ())
438 stmt->accept_vis (*this);
439
440 auto &last_expr = expr.get_final_expr ();
441 if (last_expr)
442 last_expr->accept_vis (*this);
443 }
444
445 void
446 PrivacyReporter::visit (HIR::ClosureExprInnerTyped &expr)
447 {
448 // Not handled yet
449 }
450
451 void
452 PrivacyReporter::visit (HIR::ContinueExpr &expr)
453 {}
454
455 void
456 PrivacyReporter::visit (HIR::BreakExpr &expr)
457 {
458 auto &break_expr = expr.get_expr ();
459 if (break_expr)
460 break_expr->accept_vis (*this);
461 }
462
463 void
464 PrivacyReporter::visit (HIR::RangeFromToExpr &expr)
465 {
466 expr.get_from_expr ()->accept_vis (*this);
467 expr.get_to_expr ()->accept_vis (*this);
468 }
469
470 void
471 PrivacyReporter::visit (HIR::RangeFromExpr &expr)
472 {
473 expr.get_from_expr ()->accept_vis (*this);
474 }
475
476 void
477 PrivacyReporter::visit (HIR::RangeToExpr &expr)
478 {
479 expr.get_to_expr ()->accept_vis (*this);
480 }
481
482 void
483 PrivacyReporter::visit (HIR::RangeFullExpr &expr)
484 {}
485
486 void
487 PrivacyReporter::visit (HIR::RangeFromToInclExpr &expr)
488 {
489 expr.get_from_expr ()->accept_vis (*this);
490 expr.get_to_expr ()->accept_vis (*this);
491 }
492
493 void
494 PrivacyReporter::visit (HIR::RangeToInclExpr &expr)
495 {
496 // Not handled yet
497 }
498
499 void
500 PrivacyReporter::visit (HIR::ReturnExpr &expr)
501 {
502 auto return_expr = expr.get_expr ();
503 if (return_expr)
504 return_expr->accept_vis (*this);
505 }
506
507 void
508 PrivacyReporter::visit (HIR::UnsafeBlockExpr &expr)
509 {
510 expr.get_block_expr ()->accept_vis (*this);
511 }
512
513 void
514 PrivacyReporter::visit (HIR::LoopExpr &expr)
515 {
516 expr.get_loop_block ()->accept_vis (*this);
517 }
518
519 void
520 PrivacyReporter::visit (HIR::WhileLoopExpr &expr)
521 {
522 expr.get_predicate_expr ()->accept_vis (*this);
523 expr.get_loop_block ()->accept_vis (*this);
524 }
525
526 void
527 PrivacyReporter::visit (HIR::WhileLetLoopExpr &expr)
528 {
529 expr.get_cond ()->accept_vis (*this);
530 expr.get_loop_block ()->accept_vis (*this);
531 }
532
533 void
534 PrivacyReporter::visit (HIR::ForLoopExpr &expr)
535 {
536 expr.get_iterator_expr ()->accept_vis (*this);
537 expr.get_loop_block ()->accept_vis (*this);
538 }
539
540 void
541 PrivacyReporter::visit (HIR::IfExpr &expr)
542 {
543 expr.get_if_condition ()->accept_vis (*this);
544 expr.get_if_block ()->accept_vis (*this);
545 }
546
547 void
548 PrivacyReporter::visit (HIR::IfExprConseqElse &expr)
549 {
550 expr.get_if_condition ()->accept_vis (*this);
551 expr.get_if_block ()->accept_vis (*this);
552 expr.get_else_block ()->accept_vis (*this);
553 }
554
555 void
556 PrivacyReporter::visit (HIR::IfExprConseqIf &expr)
557 {
558 expr.get_if_condition ()->accept_vis (*this);
559 expr.get_if_block ()->accept_vis (*this);
560 expr.get_conseq_if_expr ()->accept_vis (*this);
561 }
562
563 void
564 PrivacyReporter::visit (HIR::IfExprConseqIfLet &expr)
565 {
566 expr.get_if_condition ()->accept_vis (*this);
567 expr.get_if_block ()->accept_vis (*this);
568
569 // TODO: We need to visit the if_let_expr as well
570 }
571
572 void
573 PrivacyReporter::visit (HIR::IfLetExpr &expr)
574 {
575 // TODO: We need to visit the if_let_expr
576 // TODO: We need to visit the block as well
577 }
578
579 void
580 PrivacyReporter::visit (HIR::IfLetExprConseqElse &expr)
581 {
582 // TODO: We need to visit the if_let_expr
583 // TODO: We need to visit the if_block as well
584 // TODO: We need to visit the else_block as well
585 }
586
587 void
588 PrivacyReporter::visit (HIR::IfLetExprConseqIf &expr)
589 {
590 // TODO: We need to visit the if_let_expr
591 // TODO: We need to visit the if_block as well
592 // TODO: We need to visit the else_block as well
593 }
594
595 void
596 PrivacyReporter::visit (HIR::IfLetExprConseqIfLet &expr)
597 {
598 // TODO: We need to visit the if_let_expr
599 // TODO: We need to visit the if_block as well
600 // TODO: We need to visit the else_block as well
601 }
602
603 void
604 PrivacyReporter::visit (HIR::MatchExpr &expr)
605 {
606 expr.get_scrutinee_expr ()->accept_vis (*this);
607 }
608
609 void
610 PrivacyReporter::visit (HIR::AwaitExpr &expr)
611 {
612 // Not handled yet
613 }
614
615 void
616 PrivacyReporter::visit (HIR::AsyncBlockExpr &expr)
617 {
618 // Not handled yet
619 }
620
621 void
622 PrivacyReporter::visit (HIR::Module &module)
623 {
624 // FIXME: We also need to think about module privacy
625
626 auto old_module = current_module;
627 current_module
628 = Optional<NodeId>::some (module.get_mappings ().get_nodeid ());
629
630 for (auto &item : module.get_items ())
631 item->accept_vis (*this);
632
633 current_module = old_module;
634 }
635
636 void
637 PrivacyReporter::visit (HIR::ExternCrate &crate)
638 {}
639
640 void
641 PrivacyReporter::visit (HIR::UseDeclaration &use_decl)
642 {
643 // FIXME: Is there anything we need to do here?
644 }
645
646 void
647 PrivacyReporter::visit (HIR::Function &function)
648 {
649 for (auto &param : function.get_function_params ())
650 check_type_privacy (param.get_type ());
651
652 function.get_definition ()->accept_vis (*this);
653 }
654
655 void
656 PrivacyReporter::visit (HIR::TypeAlias &type_alias)
657 {
658 // TODO: Check the type here
659 }
660
661 void
662 PrivacyReporter::visit (HIR::StructStruct &struct_item)
663 {
664 // TODO: Check the type of all fields
665 }
666
667 void
668 PrivacyReporter::visit (HIR::TupleStruct &tuple_struct)
669 {
670 // TODO: Check the type of all fields
671 }
672
673 void
674 PrivacyReporter::visit (HIR::EnumItem &item)
675 {
676 // TODO: Check the type of all variants
677 }
678
679 void
680 PrivacyReporter::visit (HIR::EnumItemTuple &item)
681 {
682 // TODO: Check the type
683 }
684
685 void
686 PrivacyReporter::visit (HIR::EnumItemStruct &item)
687 {
688 // TODO: Check the type
689 }
690
691 void
692 PrivacyReporter::visit (HIR::EnumItemDiscriminant &item)
693 {}
694
695 void
696 PrivacyReporter::visit (HIR::Enum &enum_item)
697 {}
698
699 void
700 PrivacyReporter::visit (HIR::Union &union_item)
701 {
702 // TODO: Check the type
703 }
704
705 void
706 PrivacyReporter::visit (HIR::ConstantItem &const_item)
707 {
708 // TODO: We need to visit the type
709 const_item.get_expr ()->accept_vis (*this);
710 }
711
712 void
713 PrivacyReporter::visit (HIR::StaticItem &static_item)
714 {
715 // TODO: We need to visit the type
716 static_item.get_expr ()->accept_vis (*this);
717 }
718
719 void
720 PrivacyReporter::visit (HIR::Trait &trait)
721 {
722 // FIXME: We need to be an ItemVisitor as well
723 // for (auto &item : trait.get_trait_items ())
724 // item->accept_vis (*this);
725 }
726
727 void
728 PrivacyReporter::visit (HIR::ImplBlock &impl)
729 {
730 for (auto &item : impl.get_impl_items ())
731 item->accept_vis (*this);
732 }
733
734 void
735 PrivacyReporter::visit (HIR::ExternBlock &block)
736 {
737 // FIXME: We need to be an ItemVisitor as well
738 // for (auto &item : block.get_extern_items ())
739 // item->accept_vis (*this);
740 }
741
742 void
743 PrivacyReporter::visit (HIR::EmptyStmt &stmt)
744 {}
745
746 void
747 PrivacyReporter::visit (HIR::LetStmt &stmt)
748 {
749 auto type = stmt.get_type ();
750 if (type)
751 check_type_privacy (type);
752
753 auto init_expr = stmt.get_init_expr ();
754 if (init_expr)
755 init_expr->accept_vis (*this);
756 }
757
758 void
759 PrivacyReporter::visit (HIR::ExprStmtWithoutBlock &stmt)
760 {
761 stmt.get_expr ()->accept_vis (*this);
762 }
763
764 void
765 PrivacyReporter::visit (HIR::ExprStmtWithBlock &stmt)
766 {
767 stmt.get_expr ()->accept_vis (*this);
768 }
769
770 } // namespace Privacy
771 } // namespace Rust