aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-27 12:32:38 +0000
committerGitHub <noreply@github.com>2022-07-27 12:32:38 +0000
commitd94d5b1ea23220d423fd40bd00cadb0e6ede751f (patch)
tree9a6292e682c843b6ee7c3f65f23e6f74fd6c0dca /gcc
parentdec7ee4c5e703422ecb9bc94417645d66af7eaae (diff)
parent961468ed824a7b49f10ed597ba9dcc98177125ca (diff)
downloadgcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.zip
gcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.tar.gz
gcc-d94d5b1ea23220d423fd40bd00cadb0e6ede751f.tar.bz2
Merge #1410
1410: unsafe: Add UnsafeCheck visitor r=CohenArthur a=CohenArthur This visitor takes care of checking for unsafe expressions in safe contexts. This first iteration reports the dereferencing of raw pointers. Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.cc779
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.h193
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h2
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h1
-rw-r--r--gcc/rust/rust-session-manager.cc9
-rw-r--r--gcc/testsuite/rust/compile/unsafe4.rs29
-rw-r--r--gcc/testsuite/rust/compile/unsafe5.rs4
8 files changed, 1017 insertions, 1 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index d340e36..1ae9bd7 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -123,6 +123,7 @@ GRS_OBJS = \
rust/rust-lint-marklive.o \
rust/rust-lint-unused-var.o \
rust/rust-hir-type-check-path.o \
+ rust/rust-unsafe-checker.o \
rust/rust-compile-intrinsic.o \
rust/rust-compile-pattern.o \
rust/rust-compile-fnparam.o \
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc
new file mode 100644
index 0000000..def3cc1
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -0,0 +1,779 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-unsafe-checker.h"
+#include "rust-hir.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-stmt.h"
+#include "rust-hir-item.h"
+
+namespace Rust {
+namespace HIR {
+
+UnsafeChecker::UnsafeChecker () : context (*Resolver::TypeCheckContext::get ())
+{}
+
+void
+UnsafeChecker::go (HIR::Crate &crate)
+{
+ for (auto &item : crate.items)
+ item->accept_vis (*this);
+}
+
+void
+UnsafeChecker::push_unsafe (HirId id)
+{
+ unsafe_contexts.emplace_back (id);
+}
+
+HirId
+UnsafeChecker::pop_unsafe ()
+{
+ rust_assert (!unsafe_contexts.empty ());
+
+ auto last = unsafe_contexts.back ();
+ unsafe_contexts.pop_back ();
+
+ return last;
+}
+
+bool
+UnsafeChecker::is_unsafe_context ()
+{
+ return !unsafe_contexts.empty ();
+}
+
+void
+UnsafeChecker::visit (IdentifierExpr &ident_expr)
+{}
+
+void
+UnsafeChecker::visit (Lifetime &lifetime)
+{}
+
+void
+UnsafeChecker::visit (LifetimeParam &lifetime_param)
+{}
+
+void
+UnsafeChecker::visit (PathInExpression &path)
+{}
+
+void
+UnsafeChecker::visit (TypePathSegment &segment)
+{}
+
+void
+UnsafeChecker::visit (TypePathSegmentGeneric &segment)
+{}
+
+void
+UnsafeChecker::visit (TypePathSegmentFunction &segment)
+{}
+
+void
+UnsafeChecker::visit (TypePath &path)
+{}
+
+void
+UnsafeChecker::visit (QualifiedPathInExpression &path)
+{}
+
+void
+UnsafeChecker::visit (QualifiedPathInType &path)
+{}
+
+void
+UnsafeChecker::visit (LiteralExpr &expr)
+{}
+
+void
+UnsafeChecker::visit (BorrowExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (DereferenceExpr &expr)
+{
+ TyTy::BaseType *to_deref_type;
+ auto to_deref = expr.get_expr ()->get_mappings ().get_hirid ();
+
+ rust_assert (context.lookup_type (to_deref, &to_deref_type));
+
+ if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER
+ && !is_unsafe_context ())
+ rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
+ "unsafe function or block");
+}
+
+void
+UnsafeChecker::visit (ErrorPropagationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (NegationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ComparisonExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (LazyBooleanExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TypeCastExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (AssignmentExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (CompoundAssignmentExpr &expr)
+{
+ expr.get_left_expr ()->accept_vis (*this);
+ expr.get_right_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (GroupedExpr &expr)
+{
+ expr.get_expr_in_parens ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ArrayElemsValues &elems)
+{
+ for (auto &elem : elems.get_values ())
+ elem->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ArrayElemsCopied &elems)
+{
+ elems.get_elem_to_copy ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ArrayExpr &expr)
+{
+ expr.get_internal_elements ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ArrayIndexExpr &expr)
+{
+ expr.get_array_expr ()->accept_vis (*this);
+ expr.get_index_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TupleExpr &expr)
+{
+ for (auto &elem : expr.get_tuple_elems ())
+ elem->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TupleIndexExpr &expr)
+{
+ expr.get_tuple_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (StructExprStruct &expr)
+{}
+
+void
+UnsafeChecker::visit (StructExprFieldIdentifier &field)
+{}
+
+void
+UnsafeChecker::visit (StructExprFieldIdentifierValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (StructExprFieldIndexValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (StructExprStructFields &expr)
+{
+ for (auto &field : expr.get_fields ())
+ field->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (StructExprStructBase &expr)
+{}
+
+void
+UnsafeChecker::visit (CallExpr &expr)
+{}
+
+void
+UnsafeChecker::visit (MethodCallExpr &expr)
+{}
+
+void
+UnsafeChecker::visit (FieldAccessExpr &expr)
+{
+ // FIXME: If the receiver is an union, we need to be in an unsafe context to
+ // access it. Make sure to check.
+
+ expr.get_receiver_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ClosureExprInner &expr)
+{}
+
+void
+UnsafeChecker::visit (BlockExpr &expr)
+{
+ for (auto &stmt : expr.get_statements ())
+ stmt->accept_vis (*this);
+
+ if (expr.has_expr ())
+ expr.get_final_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ClosureExprInnerTyped &expr)
+{}
+
+void
+UnsafeChecker::visit (ContinueExpr &expr)
+{}
+
+void
+UnsafeChecker::visit (BreakExpr &expr)
+{
+ if (expr.has_break_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (RangeFromToExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (RangeFromExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (RangeToExpr &expr)
+{
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (RangeFullExpr &expr)
+{}
+
+void
+UnsafeChecker::visit (RangeFromToInclExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (RangeToInclExpr &expr)
+{
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ReturnExpr &expr)
+{
+ if (expr.has_return_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (UnsafeBlockExpr &expr)
+{
+ push_unsafe (expr.get_mappings ().get_hirid ());
+
+ expr.get_block_expr ()->accept_vis (*this);
+
+ pop_unsafe ();
+}
+
+void
+UnsafeChecker::visit (LoopExpr &expr)
+{
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (WhileLoopExpr &expr)
+{
+ expr.get_predicate_expr ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (WhileLetLoopExpr &expr)
+{
+ expr.get_cond ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ForLoopExpr &expr)
+{
+ expr.get_iterator_expr ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfExpr &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfExprConseqElse &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+ expr.get_else_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfExprConseqIf &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+ expr.get_conseq_if_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfExprConseqIfLet &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit conseq if let expression
+}
+
+void
+UnsafeChecker::visit (IfLetExpr &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfLetExprConseqElse &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit else expression
+}
+
+void
+UnsafeChecker::visit (IfLetExprConseqIf &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (IfLetExprConseqIfLet &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit conseq if let expression
+}
+
+void
+UnsafeChecker::visit (MatchExpr &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+
+ for (auto &match_arm : expr.get_match_cases ())
+ match_arm.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (AwaitExpr &expr)
+{
+ // TODO: Visit expression
+}
+
+void
+UnsafeChecker::visit (AsyncBlockExpr &expr)
+{
+ // TODO: Visit block expression
+}
+
+void
+UnsafeChecker::visit (TypeParam &param)
+{}
+
+void
+UnsafeChecker::visit (ConstGenericParam &param)
+{}
+
+void
+UnsafeChecker::visit (LifetimeWhereClauseItem &item)
+{}
+
+void
+UnsafeChecker::visit (TypeBoundWhereClauseItem &item)
+{}
+
+void
+UnsafeChecker::visit (Module &module)
+{
+ for (auto &item : module.get_items ())
+ item->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ExternCrate &crate)
+{}
+
+void
+UnsafeChecker::visit (UseTreeGlob &use_tree)
+{}
+
+void
+UnsafeChecker::visit (UseTreeList &use_tree)
+{}
+
+void
+UnsafeChecker::visit (UseTreeRebind &use_tree)
+{}
+
+void
+UnsafeChecker::visit (UseDeclaration &use_decl)
+{}
+
+void
+UnsafeChecker::visit (Function &function)
+{
+ auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
+
+ if (is_unsafe_fn)
+ push_unsafe (function.get_mappings ().get_hirid ());
+
+ function.get_definition ()->accept_vis (*this);
+
+ if (is_unsafe_fn)
+ pop_unsafe ();
+}
+
+void
+UnsafeChecker::visit (TypeAlias &type_alias)
+{
+ // FIXME: What do we need to do to handle type aliasing? Is it possible to
+ // have unsafe types? Type aliases on unsafe functions?
+}
+
+void
+UnsafeChecker::visit (StructStruct &struct_item)
+{}
+
+void
+UnsafeChecker::visit (TupleStruct &tuple_struct)
+{}
+
+void
+UnsafeChecker::visit (EnumItem &item)
+{}
+
+void
+UnsafeChecker::visit (EnumItemTuple &item)
+{}
+
+void
+UnsafeChecker::visit (EnumItemStruct &item)
+{}
+
+void
+UnsafeChecker::visit (EnumItemDiscriminant &item)
+{}
+
+void
+UnsafeChecker::visit (Enum &enum_item)
+{}
+
+void
+UnsafeChecker::visit (Union &union_item)
+{}
+
+void
+UnsafeChecker::visit (ConstantItem &const_item)
+{
+ const_item.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (StaticItem &static_item)
+{
+ static_item.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TraitItemFunc &item)
+{
+ if (item.has_block_defined ())
+ item.get_block_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TraitItemConst &item)
+{
+ if (item.has_expr ())
+ item.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TraitItemType &item)
+{}
+
+void
+UnsafeChecker::visit (Trait &trait)
+{
+ // FIXME: Handle unsafe traits
+ for (auto &item : trait.get_trait_items ())
+ item->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ImplBlock &impl)
+{
+ // FIXME: Handle unsafe impls
+ for (auto &item : impl.get_impl_items ())
+ item->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ExternalStaticItem &item)
+{}
+
+void
+UnsafeChecker::visit (ExternalFunctionItem &item)
+{}
+
+void
+UnsafeChecker::visit (ExternBlock &block)
+{
+ // FIXME: Do we need to do this?
+ for (auto &item : block.get_extern_items ())
+ item->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (LiteralPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (IdentifierPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (WildcardPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (RangePatternBoundLiteral &bound)
+{}
+
+void
+UnsafeChecker::visit (RangePatternBoundPath &bound)
+{}
+
+void
+UnsafeChecker::visit (RangePatternBoundQualPath &bound)
+{}
+
+void
+UnsafeChecker::visit (RangePattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (ReferencePattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (StructPatternFieldTuplePat &field)
+{}
+
+void
+UnsafeChecker::visit (StructPatternFieldIdentPat &field)
+{}
+
+void
+UnsafeChecker::visit (StructPatternFieldIdent &field)
+{}
+
+void
+UnsafeChecker::visit (StructPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (TupleStructItemsNoRange &tuple_items)
+{}
+
+void
+UnsafeChecker::visit (TupleStructItemsRange &tuple_items)
+{}
+
+void
+UnsafeChecker::visit (TupleStructPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (TuplePatternItemsMultiple &tuple_items)
+{}
+
+void
+UnsafeChecker::visit (TuplePatternItemsRanged &tuple_items)
+{}
+
+void
+UnsafeChecker::visit (TuplePattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (GroupedPattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (SlicePattern &pattern)
+{}
+
+void
+UnsafeChecker::visit (EmptyStmt &stmt)
+{}
+
+void
+UnsafeChecker::visit (LetStmt &stmt)
+{
+ if (stmt.has_init_expr ())
+ stmt.get_init_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ExprStmtWithoutBlock &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (ExprStmtWithBlock &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+UnsafeChecker::visit (TraitBound &bound)
+{}
+
+void
+UnsafeChecker::visit (ImplTraitType &type)
+{}
+
+void
+UnsafeChecker::visit (TraitObjectType &type)
+{}
+
+void
+UnsafeChecker::visit (ParenthesisedType &type)
+{}
+
+void
+UnsafeChecker::visit (ImplTraitTypeOneBound &type)
+{}
+
+void
+UnsafeChecker::visit (TupleType &type)
+{}
+
+void
+UnsafeChecker::visit (NeverType &type)
+{}
+
+void
+UnsafeChecker::visit (RawPointerType &type)
+{}
+
+void
+UnsafeChecker::visit (ReferenceType &type)
+{}
+
+void
+UnsafeChecker::visit (ArrayType &type)
+{}
+
+void
+UnsafeChecker::visit (SliceType &type)
+{}
+
+void
+UnsafeChecker::visit (InferredType &type)
+{}
+
+void
+UnsafeChecker::visit (BareFunctionType &type)
+{}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h
new file mode 100644
index 0000000..3c81707
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.h
@@ -0,0 +1,193 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_UNSAFE_CHECKER_H
+#define RUST_UNSAFE_CHECKER_H
+
+#include "rust-hir-visitor.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace HIR {
+class UnsafeChecker : public HIRFullVisitor
+{
+public:
+ UnsafeChecker ();
+
+ void go (HIR::Crate &crate);
+
+private:
+ /* Stack of unsafe contexts */
+ std::vector<HirId> unsafe_contexts;
+
+ /**
+ * Add an unsafe context to the stack. To call when entering unsafe blocks
+ */
+ void push_unsafe (HirId id);
+
+ /**
+ * Remove an unsafe context from the stack. Call this when exiting unsafe
+ * blocks
+ */
+ HirId pop_unsafe ();
+
+ /**
+ * Are we currently in an unsafe context or not
+ */
+ bool is_unsafe_context ();
+
+ Resolver::TypeCheckContext &context;
+
+ virtual void visit (IdentifierExpr &ident_expr) override;
+ virtual void visit (Lifetime &lifetime) override;
+ virtual void visit (LifetimeParam &lifetime_param) override;
+ virtual void visit (PathInExpression &path) override;
+ virtual void visit (TypePathSegment &segment) override;
+ virtual void visit (TypePathSegmentGeneric &segment) override;
+ virtual void visit (TypePathSegmentFunction &segment) override;
+ virtual void visit (TypePath &path) override;
+ virtual void visit (QualifiedPathInExpression &path) override;
+ virtual void visit (QualifiedPathInType &path) override;
+ virtual void visit (LiteralExpr &expr) override;
+ virtual void visit (BorrowExpr &expr) override;
+ virtual void visit (DereferenceExpr &expr) override;
+ virtual void visit (ErrorPropagationExpr &expr) override;
+ virtual void visit (NegationExpr &expr) override;
+ virtual void visit (ArithmeticOrLogicalExpr &expr) override;
+ virtual void visit (ComparisonExpr &expr) override;
+ virtual void visit (LazyBooleanExpr &expr) override;
+ virtual void visit (TypeCastExpr &expr) override;
+ virtual void visit (AssignmentExpr &expr) override;
+ virtual void visit (CompoundAssignmentExpr &expr) override;
+ virtual void visit (GroupedExpr &expr) override;
+ virtual void visit (ArrayElemsValues &elems) override;
+ virtual void visit (ArrayElemsCopied &elems) override;
+ virtual void visit (ArrayExpr &expr) override;
+ virtual void visit (ArrayIndexExpr &expr) override;
+ virtual void visit (TupleExpr &expr) override;
+ virtual void visit (TupleIndexExpr &expr) override;
+ virtual void visit (StructExprStruct &expr) override;
+ virtual void visit (StructExprFieldIdentifier &field) override;
+ virtual void visit (StructExprFieldIdentifierValue &field) override;
+ virtual void visit (StructExprFieldIndexValue &field) override;
+ virtual void visit (StructExprStructFields &expr) override;
+ virtual void visit (StructExprStructBase &expr) override;
+ virtual void visit (CallExpr &expr) override;
+ virtual void visit (MethodCallExpr &expr) override;
+ virtual void visit (FieldAccessExpr &expr) override;
+ virtual void visit (ClosureExprInner &expr) override;
+ virtual void visit (BlockExpr &expr) override;
+ virtual void visit (ClosureExprInnerTyped &expr) override;
+ virtual void visit (ContinueExpr &expr) override;
+ virtual void visit (BreakExpr &expr) override;
+ virtual void visit (RangeFromToExpr &expr) override;
+ virtual void visit (RangeFromExpr &expr) override;
+ virtual void visit (RangeToExpr &expr) override;
+ virtual void visit (RangeFullExpr &expr) override;
+ virtual void visit (RangeFromToInclExpr &expr) override;
+ virtual void visit (RangeToInclExpr &expr) override;
+ virtual void visit (ReturnExpr &expr) override;
+ virtual void visit (UnsafeBlockExpr &expr) override;
+ virtual void visit (LoopExpr &expr) override;
+ virtual void visit (WhileLoopExpr &expr) override;
+ virtual void visit (WhileLetLoopExpr &expr) override;
+ virtual void visit (ForLoopExpr &expr) override;
+ virtual void visit (IfExpr &expr) override;
+ virtual void visit (IfExprConseqElse &expr) override;
+ virtual void visit (IfExprConseqIf &expr) override;
+ virtual void visit (IfExprConseqIfLet &expr) override;
+ virtual void visit (IfLetExpr &expr) override;
+ virtual void visit (IfLetExprConseqElse &expr) override;
+ virtual void visit (IfLetExprConseqIf &expr) override;
+ virtual void visit (IfLetExprConseqIfLet &expr) override;
+ virtual void visit (MatchExpr &expr) override;
+ virtual void visit (AwaitExpr &expr) override;
+ virtual void visit (AsyncBlockExpr &expr) override;
+ virtual void visit (TypeParam &param) override;
+ virtual void visit (ConstGenericParam &param) override;
+ virtual void visit (LifetimeWhereClauseItem &item) override;
+ virtual void visit (TypeBoundWhereClauseItem &item) override;
+ virtual void visit (Module &module) override;
+ virtual void visit (ExternCrate &crate) override;
+ virtual void visit (UseTreeGlob &use_tree) override;
+ virtual void visit (UseTreeList &use_tree) override;
+ virtual void visit (UseTreeRebind &use_tree) override;
+ virtual void visit (UseDeclaration &use_decl) override;
+ virtual void visit (Function &function) override;
+ virtual void visit (TypeAlias &type_alias) override;
+ virtual void visit (StructStruct &struct_item) override;
+ virtual void visit (TupleStruct &tuple_struct) override;
+ virtual void visit (EnumItem &item) override;
+ virtual void visit (EnumItemTuple &item) override;
+ virtual void visit (EnumItemStruct &item) override;
+ virtual void visit (EnumItemDiscriminant &item) override;
+ virtual void visit (Enum &enum_item) override;
+ virtual void visit (Union &union_item) override;
+ virtual void visit (ConstantItem &const_item) override;
+ virtual void visit (StaticItem &static_item) override;
+ virtual void visit (TraitItemFunc &item) override;
+ virtual void visit (TraitItemConst &item) override;
+ virtual void visit (TraitItemType &item) override;
+ virtual void visit (Trait &trait) override;
+ virtual void visit (ImplBlock &impl) override;
+ virtual void visit (ExternalStaticItem &item) override;
+ virtual void visit (ExternalFunctionItem &item) override;
+ virtual void visit (ExternBlock &block) override;
+ virtual void visit (LiteralPattern &pattern) override;
+ virtual void visit (IdentifierPattern &pattern) override;
+ virtual void visit (WildcardPattern &pattern) override;
+ virtual void visit (RangePatternBoundLiteral &bound) override;
+ virtual void visit (RangePatternBoundPath &bound) override;
+ virtual void visit (RangePatternBoundQualPath &bound) override;
+ virtual void visit (RangePattern &pattern) override;
+ virtual void visit (ReferencePattern &pattern) override;
+ virtual void visit (StructPatternFieldTuplePat &field) override;
+ virtual void visit (StructPatternFieldIdentPat &field) override;
+ virtual void visit (StructPatternFieldIdent &field) override;
+ virtual void visit (StructPattern &pattern) override;
+ virtual void visit (TupleStructItemsNoRange &tuple_items) override;
+ virtual void visit (TupleStructItemsRange &tuple_items) override;
+ virtual void visit (TupleStructPattern &pattern) override;
+ virtual void visit (TuplePatternItemsMultiple &tuple_items) override;
+ virtual void visit (TuplePatternItemsRanged &tuple_items) override;
+ virtual void visit (TuplePattern &pattern) override;
+ virtual void visit (GroupedPattern &pattern) override;
+ virtual void visit (SlicePattern &pattern) override;
+ virtual void visit (EmptyStmt &stmt) override;
+ virtual void visit (LetStmt &stmt) override;
+ virtual void visit (ExprStmtWithoutBlock &stmt) override;
+ virtual void visit (ExprStmtWithBlock &stmt) override;
+ virtual void visit (TraitBound &bound) override;
+ virtual void visit (ImplTraitType &type) override;
+ virtual void visit (TraitObjectType &type) override;
+ virtual void visit (ParenthesisedType &type) override;
+ virtual void visit (ImplTraitTypeOneBound &type) override;
+ virtual void visit (TupleType &type) override;
+ virtual void visit (NeverType &type) override;
+ virtual void visit (RawPointerType &type) override;
+ virtual void visit (ReferenceType &type) override;
+ virtual void visit (ArrayType &type) override;
+ virtual void visit (SliceType &type) override;
+ virtual void visit (InferredType &type) override;
+ virtual void visit (BareFunctionType &type) override;
+};
+
+} // namespace HIR
+} // namespace Rust
+
+#endif /* !RUST_UNSAFE_CHECKER_H */
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index c695412..327a9ac 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -2716,6 +2716,8 @@ public:
void accept_vis (HIRFullVisitor &vis) override;
void accept_vis (HIRExpressionVisitor &vis) override;
+ std::unique_ptr<Expr> &get_to_expr () { return to; };
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 1fcecb8..0d41bd0 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -502,6 +502,7 @@ public:
AsyncConstStatus get_status () const { return const_status; }
bool is_const () const { return const_status == AsyncConstStatus::CONST_FN; }
+ bool is_unsafe () const { return unsafety == Unsafety::Unsafe; }
ABI get_abi () const { return abi; }
};
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 1ef6765..6a2c1b6 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-session-manager.h"
+#include "rust-unsafe-checker.h"
#include "rust-diagnostics.h"
#include "rust-lex.h"
#include "rust-parse.h"
@@ -789,8 +790,14 @@ Session::parse_file (const char *filename)
if (saw_errors ())
return;
- // privacy pass
+ // Various HIR error passes. The privacy pass happens before the unsafe checks
Privacy::Resolver::resolve (hir);
+ if (saw_errors ())
+ return;
+
+ HIR::UnsafeChecker ().go (hir);
+ if (saw_errors ())
+ return;
// do compile to gcc generic
Compile::Context ctx (backend);
diff --git a/gcc/testsuite/rust/compile/unsafe4.rs b/gcc/testsuite/rust/compile/unsafe4.rs
new file mode 100644
index 0000000..7d1356b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe4.rs
@@ -0,0 +1,29 @@
+fn foo() -> i32 {
+ let a = 15;
+ let p_a = &a as *const i32;
+
+ unsafe { *p_a }
+}
+
+unsafe fn bar() -> i32 {
+ let a = 15;
+ let p_a = &a as *const i32;
+
+ *p_a
+}
+
+fn baz() -> i32 {
+ let a = 15;
+ let p_a = &a as *const i32;
+
+ *p_a // { dg-error "dereference of raw pointer" }
+}
+
+unsafe fn qux() -> i32 {
+ let a = 15;
+ let p_a = &a as *const i32;
+
+ unsafe {}
+
+ *p_a
+}
diff --git a/gcc/testsuite/rust/compile/unsafe5.rs b/gcc/testsuite/rust/compile/unsafe5.rs
new file mode 100644
index 0000000..35990f6
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe5.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let b = 15;
+ let c = *(&b as *const i32); // { dg-error "dereference of raw pointer" }
+}