aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.cc803
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.h183
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.cc113
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.h24
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h18
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h20
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h37
-rw-r--r--gcc/rust/hir/tree/rust-hir.h20
-rw-r--r--gcc/rust/rust-session-manager.cc5
-rw-r--r--gcc/rust/util/rust-stacked-contexts.h86
-rw-r--r--gcc/testsuite/rust/compile/const1.rs6
-rw-r--r--gcc/testsuite/rust/compile/const2.rs7
-rw-r--r--gcc/testsuite/rust/compile/const3.rs7
-rw-r--r--gcc/testsuite/rust/compile/unsafe1.rs14
-rw-r--r--gcc/testsuite/rust/compile/unsafe2.rs16
-rw-r--r--gcc/testsuite/rust/compile/unsafe3.rs10
-rw-r--r--gcc/testsuite/rust/compile/unsafe9.rs10
18 files changed, 1329 insertions, 51 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 1ae9bd7..78c3d0f 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -120,6 +120,7 @@ GRS_OBJS = \
rust/rust-hir-type-check-base.o \
rust/rust-autoderef.o \
rust/rust-substitution-mapper.o \
+ rust/rust-const-checker.o \
rust/rust-lint-marklive.o \
rust/rust-lint-unused-var.o \
rust/rust-hir-type-check-path.o \
diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc
new file mode 100644
index 0000000..bb6ae10
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-const-checker.cc
@@ -0,0 +1,803 @@
+// 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-const-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 {
+
+ConstChecker::ConstChecker ()
+ : resolver (*Resolver::Resolver::get ()),
+ mappings (*Analysis::Mappings::get ())
+{}
+
+void
+ConstChecker::go (HIR::Crate &crate)
+{
+ for (auto &item : crate.items)
+ item->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (IdentifierExpr &ident_expr)
+{}
+
+void
+ConstChecker::visit (Lifetime &lifetime)
+{}
+
+void
+ConstChecker::visit (LifetimeParam &lifetime_param)
+{}
+
+void
+ConstChecker::visit (PathInExpression &path)
+{}
+
+void
+ConstChecker::visit (TypePathSegment &segment)
+{}
+
+void
+ConstChecker::visit (TypePathSegmentGeneric &segment)
+{}
+
+void
+ConstChecker::visit (TypePathSegmentFunction &segment)
+{}
+
+void
+ConstChecker::visit (TypePath &path)
+{}
+
+void
+ConstChecker::visit (QualifiedPathInExpression &path)
+{}
+
+void
+ConstChecker::visit (QualifiedPathInType &path)
+{}
+
+void
+ConstChecker::visit (LiteralExpr &expr)
+{}
+
+void
+ConstChecker::visit (BorrowExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (DereferenceExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ErrorPropagationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (NegationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ArithmeticOrLogicalExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ComparisonExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (LazyBooleanExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TypeCastExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (AssignmentExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (CompoundAssignmentExpr &expr)
+{
+ expr.get_left_expr ()->accept_vis (*this);
+ expr.get_right_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (GroupedExpr &expr)
+{
+ expr.get_expr_in_parens ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ArrayElemsValues &elems)
+{
+ for (auto &elem : elems.get_values ())
+ elem->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ArrayElemsCopied &elems)
+{
+ elems.get_elem_to_copy ()->accept_vis (*this);
+
+ const_context.enter (elems.get_mappings ().get_hirid ());
+
+ elems.get_num_copies_expr ()->accept_vis (*this);
+
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (ArrayExpr &expr)
+{
+ expr.get_internal_elements ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ArrayIndexExpr &expr)
+{
+ expr.get_array_expr ()->accept_vis (*this);
+ expr.get_index_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TupleExpr &expr)
+{
+ for (auto &elem : expr.get_tuple_elems ())
+ elem->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TupleIndexExpr &expr)
+{
+ expr.get_tuple_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (StructExprStruct &expr)
+{}
+
+void
+ConstChecker::visit (StructExprFieldIdentifier &field)
+{}
+
+void
+ConstChecker::visit (StructExprFieldIdentifierValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (StructExprFieldIndexValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (StructExprStructFields &expr)
+{
+ for (auto &field : expr.get_fields ())
+ field->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (StructExprStructBase &expr)
+{}
+
+void
+ConstChecker::check_function_call (HirId fn_id, Location locus)
+{
+ if (!const_context.is_in_context ())
+ return;
+
+ auto maybe_fn = mappings.lookup_hir_item (fn_id);
+ if (!maybe_fn || maybe_fn->get_item_kind () != Item::ItemKind::Function)
+ return;
+
+ auto fn = static_cast<Function *> (maybe_fn);
+ if (!fn->get_qualifiers ().is_const ())
+ rust_error_at (locus, "only functions marked as %<const%> are allowed to "
+ "be called from constant contexts");
+}
+
+void
+ConstChecker::visit (CallExpr &expr)
+{
+ auto fn = expr.get_fnexpr ();
+ if (!fn)
+ return;
+
+ NodeId ast_node_id = fn->get_mappings ().get_nodeid ();
+ NodeId ref_node_id;
+ HirId definition_id;
+
+ // We don't care about types here
+ if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+ return;
+
+ rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
+
+ check_function_call (definition_id, expr.get_locus ());
+
+ for (auto &arg : expr.get_arguments ())
+ arg->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (MethodCallExpr &expr)
+{
+ expr.get_receiver ()->accept_vis (*this);
+
+ for (auto &arg : expr.get_arguments ())
+ arg->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (FieldAccessExpr &expr)
+{
+ expr.get_receiver_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ClosureExprInner &expr)
+{}
+
+void
+ConstChecker::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
+ConstChecker::visit (ClosureExprInnerTyped &expr)
+{}
+
+void
+ConstChecker::visit (ContinueExpr &expr)
+{}
+
+void
+ConstChecker::visit (BreakExpr &expr)
+{
+ if (expr.has_break_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (RangeFromToExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (RangeFromExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (RangeToExpr &expr)
+{
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (RangeFullExpr &expr)
+{}
+
+void
+ConstChecker::visit (RangeFromToInclExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (RangeToInclExpr &expr)
+{
+ // FIXME: Visit to_expr
+}
+
+void
+ConstChecker::visit (ReturnExpr &expr)
+{
+ if (expr.has_return_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (UnsafeBlockExpr &expr)
+{
+ expr.get_block_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (LoopExpr &expr)
+{
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (WhileLoopExpr &expr)
+{
+ expr.get_predicate_expr ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (WhileLetLoopExpr &expr)
+{
+ expr.get_cond ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ForLoopExpr &expr)
+{
+ expr.get_iterator_expr ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (IfExpr &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::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
+ConstChecker::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
+ConstChecker::visit (IfExprConseqIfLet &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit conseq if let expression
+}
+
+void
+ConstChecker::visit (IfLetExpr &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (IfLetExprConseqElse &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit else expression
+}
+
+void
+ConstChecker::visit (IfLetExprConseqIf &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (IfLetExprConseqIfLet &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ // TODO: Visit conseq if let expression
+}
+
+void
+ConstChecker::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
+ConstChecker::visit (AwaitExpr &expr)
+{
+ // TODO: Visit expression
+}
+
+void
+ConstChecker::visit (AsyncBlockExpr &expr)
+{
+ // TODO: Visit block expression
+}
+
+void
+ConstChecker::visit (TypeParam &param)
+{}
+
+void
+ConstChecker::visit (ConstGenericParam &param)
+{}
+
+void
+ConstChecker::visit (LifetimeWhereClauseItem &item)
+{}
+
+void
+ConstChecker::visit (TypeBoundWhereClauseItem &item)
+{}
+
+void
+ConstChecker::visit (Module &module)
+{
+ for (auto &item : module.get_items ())
+ item->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ExternCrate &crate)
+{}
+
+void
+ConstChecker::visit (UseTreeGlob &use_tree)
+{}
+
+void
+ConstChecker::visit (UseTreeList &use_tree)
+{}
+
+void
+ConstChecker::visit (UseTreeRebind &use_tree)
+{}
+
+void
+ConstChecker::visit (UseDeclaration &use_decl)
+{}
+
+void
+ConstChecker::visit (Function &function)
+{
+ auto const_fn = function.get_qualifiers ().is_const ();
+ if (const_fn)
+ const_context.enter (function.get_mappings ().get_hirid ());
+
+ function.get_definition ()->accept_vis (*this);
+
+ if (const_fn)
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (TypeAlias &type_alias)
+{}
+
+void
+ConstChecker::visit (StructStruct &struct_item)
+{}
+
+void
+ConstChecker::visit (TupleStruct &tuple_struct)
+{}
+
+void
+ConstChecker::visit (EnumItem &item)
+{}
+
+void
+ConstChecker::visit (EnumItemTuple &item)
+{}
+
+void
+ConstChecker::visit (EnumItemStruct &item)
+{}
+
+void
+ConstChecker::visit (EnumItemDiscriminant &item)
+{
+ const_context.enter (item.get_mappings ().get_hirid ());
+
+ item.get_discriminant_expression ()->accept_vis (*this);
+
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (Enum &enum_item)
+{}
+
+void
+ConstChecker::visit (Union &union_item)
+{}
+
+void
+ConstChecker::visit (ConstantItem &const_item)
+{
+ const_context.enter (const_item.get_mappings ().get_hirid ());
+
+ const_item.get_expr ()->accept_vis (*this);
+
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (StaticItem &static_item)
+{
+ const_context.enter (static_item.get_mappings ().get_hirid ());
+
+ static_item.get_expr ()->accept_vis (*this);
+
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (TraitItemFunc &item)
+{
+ if (item.has_block_defined ())
+ item.get_block_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TraitItemConst &item)
+{
+ if (item.has_expr ())
+ item.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TraitItemType &item)
+{}
+
+void
+ConstChecker::visit (Trait &trait)
+{
+ for (auto &item : trait.get_trait_items ())
+ item->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ImplBlock &impl)
+{
+ for (auto &item : impl.get_impl_items ())
+ item->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ExternalStaticItem &item)
+{}
+
+void
+ConstChecker::visit (ExternalFunctionItem &item)
+{}
+
+void
+ConstChecker::visit (ExternBlock &block)
+{
+ // FIXME: Do we need to do this?
+ for (auto &item : block.get_extern_items ())
+ item->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (LiteralPattern &pattern)
+{}
+
+void
+ConstChecker::visit (IdentifierPattern &pattern)
+{}
+
+void
+ConstChecker::visit (WildcardPattern &pattern)
+{}
+
+void
+ConstChecker::visit (RangePatternBoundLiteral &bound)
+{}
+
+void
+ConstChecker::visit (RangePatternBoundPath &bound)
+{}
+
+void
+ConstChecker::visit (RangePatternBoundQualPath &bound)
+{}
+
+void
+ConstChecker::visit (RangePattern &pattern)
+{}
+
+void
+ConstChecker::visit (ReferencePattern &pattern)
+{}
+
+void
+ConstChecker::visit (StructPatternFieldTuplePat &field)
+{}
+
+void
+ConstChecker::visit (StructPatternFieldIdentPat &field)
+{}
+
+void
+ConstChecker::visit (StructPatternFieldIdent &field)
+{}
+
+void
+ConstChecker::visit (StructPattern &pattern)
+{}
+
+void
+ConstChecker::visit (TupleStructItemsNoRange &tuple_items)
+{}
+
+void
+ConstChecker::visit (TupleStructItemsRange &tuple_items)
+{}
+
+void
+ConstChecker::visit (TupleStructPattern &pattern)
+{}
+
+void
+ConstChecker::visit (TuplePatternItemsMultiple &tuple_items)
+{}
+
+void
+ConstChecker::visit (TuplePatternItemsRanged &tuple_items)
+{}
+
+void
+ConstChecker::visit (TuplePattern &pattern)
+{}
+
+void
+ConstChecker::visit (GroupedPattern &pattern)
+{}
+
+void
+ConstChecker::visit (SlicePattern &pattern)
+{}
+
+void
+ConstChecker::visit (EmptyStmt &stmt)
+{}
+
+void
+ConstChecker::visit (LetStmt &stmt)
+{
+ if (stmt.has_init_expr ())
+ stmt.get_init_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ExprStmtWithoutBlock &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (ExprStmtWithBlock &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+ConstChecker::visit (TraitBound &bound)
+{}
+
+void
+ConstChecker::visit (ImplTraitType &type)
+{}
+
+void
+ConstChecker::visit (TraitObjectType &type)
+{}
+
+void
+ConstChecker::visit (ParenthesisedType &type)
+{}
+
+void
+ConstChecker::visit (ImplTraitTypeOneBound &type)
+{}
+
+void
+ConstChecker::visit (TupleType &type)
+{}
+
+void
+ConstChecker::visit (NeverType &type)
+{}
+
+void
+ConstChecker::visit (RawPointerType &type)
+{}
+
+void
+ConstChecker::visit (ReferenceType &type)
+{}
+
+void
+ConstChecker::visit (ArrayType &type)
+{
+ const_context.enter (type.get_mappings ().get_hirid ());
+
+ type.get_size_expr ()->accept_vis (*this);
+
+ const_context.exit ();
+}
+
+void
+ConstChecker::visit (SliceType &type)
+{}
+
+void
+ConstChecker::visit (InferredType &type)
+{}
+
+void
+ConstChecker::visit (BareFunctionType &type)
+{}
+
+} // namespace HIR
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h
new file mode 100644
index 0000000..a474fc8
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-const-checker.h
@@ -0,0 +1,183 @@
+// 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_CONST_CHECKER_H
+#define RUST_CONST_CHECKER_H
+
+#include "rust-hir-visitor.h"
+#include "rust-hir-type-check.h"
+#include "rust-stacked-contexts.h"
+#include "rust-name-resolver.h"
+
+namespace Rust {
+namespace HIR {
+class ConstChecker : public HIRFullVisitor
+{
+public:
+ ConstChecker ();
+
+ void go (HIR::Crate &crate);
+
+private:
+ /**
+ * Check that only const functions are called in const contexts
+ */
+ void check_function_call (HirId fn_id, Location locus);
+
+ StackedContexts<HirId> const_context;
+ Resolver::Resolver &resolver;
+ Analysis::Mappings &mappings;
+
+ 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_CONST_CHECKER_H */
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc
index def3cc1..0d1e0e9 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.cc
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -25,7 +25,10 @@
namespace Rust {
namespace HIR {
-UnsafeChecker::UnsafeChecker () : context (*Resolver::TypeCheckContext::get ())
+UnsafeChecker::UnsafeChecker ()
+ : context (*Resolver::TypeCheckContext::get ()),
+ resolver (*Resolver::Resolver::get ()),
+ mappings (*Analysis::Mappings::get ())
{}
void
@@ -35,32 +38,61 @@ UnsafeChecker::go (HIR::Crate &crate)
item->accept_vis (*this);
}
-void
-UnsafeChecker::push_unsafe (HirId id)
+static void
+check_static_mut (HIR::Item *maybe_static, Location locus)
{
- unsafe_contexts.emplace_back (id);
+ if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM)
+ {
+ auto item = static_cast<Item *> (maybe_static);
+ if (item->get_item_kind () == Item::ItemKind::Static)
+ {
+ auto static_item = static_cast<StaticItem *> (item);
+ if (static_item->is_mut ())
+ rust_error_at (
+ locus, "use of mutable static requires unsafe function or block");
+ }
+ }
}
-HirId
-UnsafeChecker::pop_unsafe ()
+static void
+check_extern_static (HIR::ExternalItem *maybe_static, Location locus)
{
- rust_assert (!unsafe_contexts.empty ());
-
- auto last = unsafe_contexts.back ();
- unsafe_contexts.pop_back ();
-
- return last;
+ if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static)
+ rust_error_at (locus,
+ "use of extern static requires unsafe function or block");
}
-bool
-UnsafeChecker::is_unsafe_context ()
+void
+UnsafeChecker::check_use_of_static (HirId node_id, Location locus)
{
- return !unsafe_contexts.empty ();
+ if (unsafe_context.is_in_context ())
+ return;
+
+ auto maybe_static_mut = mappings.lookup_hir_item (node_id);
+ auto maybe_extern_static = mappings.lookup_hir_extern_item (node_id);
+
+ if (maybe_static_mut)
+ check_static_mut (maybe_static_mut, locus);
+
+ if (maybe_extern_static)
+ check_extern_static (static_cast<ExternalItem *> (maybe_extern_static),
+ locus);
}
void
UnsafeChecker::visit (IdentifierExpr &ident_expr)
-{}
+{
+ NodeId ast_node_id = ident_expr.get_mappings ().get_nodeid ();
+ NodeId ref_node_id;
+ HirId definition_id;
+
+ if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+ return;
+
+ rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
+
+ check_use_of_static (definition_id, ident_expr.get_locus ());
+}
void
UnsafeChecker::visit (Lifetime &lifetime)
@@ -72,7 +104,18 @@ UnsafeChecker::visit (LifetimeParam &lifetime_param)
void
UnsafeChecker::visit (PathInExpression &path)
-{}
+{
+ NodeId ast_node_id = path.get_mappings ().get_nodeid ();
+ NodeId ref_node_id;
+ HirId definition_id;
+
+ if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+ return;
+
+ rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id));
+
+ check_use_of_static (definition_id, path.get_locus ());
+}
void
UnsafeChecker::visit (TypePathSegment &segment)
@@ -117,7 +160,7 @@ UnsafeChecker::visit (DereferenceExpr &expr)
rust_assert (context.lookup_type (to_deref, &to_deref_type));
if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER
- && !is_unsafe_context ())
+ && !unsafe_context.is_in_context ())
rust_error_at (expr.get_locus (), "dereference of raw pointer requires "
"unsafe function or block");
}
@@ -253,7 +296,11 @@ UnsafeChecker::visit (StructExprStructBase &expr)
void
UnsafeChecker::visit (CallExpr &expr)
-{}
+{
+ if (expr.has_params ())
+ for (auto &arg : expr.get_arguments ())
+ arg->accept_vis (*this);
+}
void
UnsafeChecker::visit (MethodCallExpr &expr)
@@ -262,10 +309,24 @@ 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);
+
+ if (unsafe_context.is_in_context ())
+ return;
+
+ TyTy::BaseType *receiver_ty;
+ auto ok = context.lookup_type (
+ expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver_ty);
+ rust_assert (ok);
+
+ if (receiver_ty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ auto maybe_union = static_cast<TyTy::ADTType *> (receiver_ty);
+ if (maybe_union->is_union ())
+ rust_error_at (
+ expr.get_locus (),
+ "access to union field requires unsafe function or block");
+ }
}
void
@@ -343,11 +404,11 @@ UnsafeChecker::visit (ReturnExpr &expr)
void
UnsafeChecker::visit (UnsafeBlockExpr &expr)
{
- push_unsafe (expr.get_mappings ().get_hirid ());
+ unsafe_context.enter (expr.get_mappings ().get_hirid ());
expr.get_block_expr ()->accept_vis (*this);
- pop_unsafe ();
+ unsafe_context.exit ();
}
void
@@ -511,12 +572,12 @@ UnsafeChecker::visit (Function &function)
auto is_unsafe_fn = function.get_qualifiers ().is_unsafe ();
if (is_unsafe_fn)
- push_unsafe (function.get_mappings ().get_hirid ());
+ unsafe_context.enter (function.get_mappings ().get_hirid ());
function.get_definition ()->accept_vis (*this);
if (is_unsafe_fn)
- pop_unsafe ();
+ unsafe_context.exit ();
}
void
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h
index 3c81707..b9d06ef 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.h
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.h
@@ -20,7 +20,9 @@
#define RUST_UNSAFE_CHECKER_H
#include "rust-hir-visitor.h"
+#include "rust-name-resolver.h"
#include "rust-hir-type-check.h"
+#include "rust-stacked-contexts.h"
namespace Rust {
namespace HIR {
@@ -32,26 +34,16 @@ public:
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
+ * Check if a mutable static or external static item is used outside of an
+ * unsafe context
*/
- bool is_unsafe_context ();
+ void check_use_of_static (HirId node_id, Location locus);
+ StackedContexts<HirId> unsafe_context;
Resolver::TypeCheckContext &context;
+ Resolver::Resolver &resolver;
+ Analysis::Mappings &mappings;
virtual void visit (IdentifierExpr &ident_expr) override;
virtual void visit (Lifetime &lifetime) override;
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
index 166a44b..b420a4d 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -307,7 +307,14 @@ public:
elements.push_back (std::unique_ptr<HIR::Expr> (translated_elem));
}
- translated_array_elems = new HIR::ArrayElemsValues (std::move (elements));
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (mappings->get_current_crate (),
+ elems.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
+ translated_array_elems
+ = new HIR::ArrayElemsValues (mapping, std::move (elements));
}
void visit (AST::ArrayElemsCopied &elems) override
@@ -317,8 +324,15 @@ public:
HIR::Expr *num_copies
= ASTLoweringExpr::translate (elems.get_num_copies ().get ());
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (mappings->get_current_crate (),
+ elems.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ UNKNOWN_LOCAL_DEFID);
+
translated_array_elems
- = new HIR::ArrayElemsCopied (std::unique_ptr<HIR::Expr> (element),
+ = new HIR::ArrayElemsCopied (mapping,
+ std::unique_ptr<HIR::Expr> (element),
std::unique_ptr<HIR::Expr> (num_copies));
}
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 327a9ac..d16ac92 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -849,6 +849,8 @@ public:
COPIED,
};
+ ArrayElems (Analysis::NodeMapping mappings) : mappings (mappings){};
+
virtual ~ArrayElems () {}
// Unique pointer custom clone ArrayElems function
@@ -863,9 +865,13 @@ public:
virtual ArrayExprType get_array_expr_type () const = 0;
+ Analysis::NodeMapping &get_mappings () { return mappings; }
+
protected:
// pure virtual clone implementation
virtual ArrayElems *clone_array_elems_impl () const = 0;
+
+ Analysis::NodeMapping mappings;
};
// Value array elements
@@ -876,12 +882,13 @@ class ArrayElemsValues : public ArrayElems
// TODO: should this store location data?
public:
- ArrayElemsValues (std::vector<std::unique_ptr<Expr> > elems)
- : values (std::move (elems))
+ ArrayElemsValues (Analysis::NodeMapping mappings,
+ std::vector<std::unique_ptr<Expr> > elems)
+ : ArrayElems (mappings), values (std::move (elems))
{}
// copy constructor with vector clone
- ArrayElemsValues (ArrayElemsValues const &other)
+ ArrayElemsValues (ArrayElemsValues const &other) : ArrayElems (other)
{
values.reserve (other.values.size ());
for (const auto &e : other.values)
@@ -930,15 +937,16 @@ class ArrayElemsCopied : public ArrayElems
public:
// Constructor requires pointers for polymorphism
- ArrayElemsCopied (std::unique_ptr<Expr> copied_elem,
+ ArrayElemsCopied (Analysis::NodeMapping mappings,
+ std::unique_ptr<Expr> copied_elem,
std::unique_ptr<Expr> copy_amount)
- : elem_to_copy (std::move (copied_elem)),
+ : ArrayElems (mappings), elem_to_copy (std::move (copied_elem)),
num_copies (std::move (copy_amount))
{}
// Copy constructor required due to unique_ptr - uses custom clone
ArrayElemsCopied (ArrayElemsCopied const &other)
- : elem_to_copy (other.elem_to_copy->clone_expr ()),
+ : ArrayElems (other), elem_to_copy (other.elem_to_copy->clone_expr ()),
num_copies (other.num_copies->clone_expr ())
{}
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 0d41bd0..394b04f 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -723,6 +723,8 @@ public:
Location get_locus () const override final { return locus; }
+ ItemKind get_item_kind () const override { return ItemKind::Module; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -773,6 +775,8 @@ public:
Location get_locus () const override final { return locus; }
+ ItemKind get_item_kind () const override { return ItemKind::ExternCrate; }
+
void accept_vis (HIRFullVisitor &vis) override;
void accept_vis (HIRStmtVisitor &vis) override;
void accept_vis (HIRVisItemVisitor &vis) override;
@@ -1039,6 +1043,7 @@ public:
UseDeclaration &operator= (UseDeclaration &&other) = default;
Location get_locus () const override final { return locus; }
+ ItemKind get_item_kind () const override { return ItemKind::UseDeclaration; }
void accept_vis (HIRFullVisitor &vis) override;
void accept_vis (HIRStmtVisitor &vis) override;
@@ -1094,6 +1099,8 @@ public:
return ImplItem::ImplItemType::FUNCTION;
}
+ ItemKind get_item_kind () const override { return ItemKind::Function; }
+
// Mega-constructor with all possible fields
Function (Analysis::NodeMapping mappings, Identifier function_name,
FunctionQualifiers qualifiers,
@@ -1329,6 +1336,8 @@ public:
Identifier get_new_type_name () const { return new_type_name; }
+ ItemKind get_item_kind () const override { return ItemKind::TypeAlias; }
+
Analysis::NodeMapping get_impl_mappings () const override
{
return get_mappings ();
@@ -1373,6 +1382,7 @@ public:
bool has_where_clause () const { return !where_clause.is_empty (); }
Location get_locus () const override final { return locus; }
+ ItemKind get_item_kind () const override { return ItemKind::Struct; }
std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
{
@@ -1709,6 +1719,8 @@ public:
Identifier get_identifier () const { return variant_name; }
+ ItemKind get_item_kind () const override { return ItemKind::EnumItem; }
+
protected:
EnumItem *clone_item_impl () const override { return new EnumItem (*this); }
};
@@ -1930,6 +1942,7 @@ public:
void accept_vis (HIRVisItemVisitor &vis) override;
Identifier get_identifier () const { return enum_name; }
+ ItemKind get_item_kind () const override { return ItemKind::Enum; }
std::vector<std::unique_ptr<GenericParam>> &get_generic_params ()
{
@@ -2037,6 +2050,8 @@ public:
WhereClause &get_where_clause () { return where_clause; }
+ ItemKind get_item_kind () const override { return ItemKind::Union; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -2111,6 +2126,8 @@ public:
return ImplItem::ImplItemType::CONSTANT;
}
+ ItemKind get_item_kind () const override { return ItemKind::Constant; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -2188,6 +2205,8 @@ public:
Type *get_type () { return type.get (); }
+ ItemKind get_item_kind () const override { return ItemKind::Static; }
+
protected:
StaticItem *clone_item_impl () const override
{
@@ -2677,6 +2696,8 @@ public:
return type_param_bounds;
}
+ ItemKind get_item_kind () const override { return ItemKind::Trait; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -2797,6 +2818,8 @@ public:
WhereClause &get_where_clause () { return where_clause; }
+ ItemKind get_item_kind () const override { return ItemKind::Impl; }
+
protected:
ImplBlock *clone_item_impl () const override { return new ImplBlock (*this); }
};
@@ -2811,10 +2834,18 @@ class ExternalItem : public Node
Location locus;
public:
+ enum class ExternKind
+ {
+ Static,
+ Function,
+ };
+
virtual ~ExternalItem () {}
BaseKind get_hir_kind () override final { return EXTERNAL; }
+ virtual ExternKind get_extern_kind () = 0;
+
// Returns whether item has outer attributes.
bool has_outer_attrs () const { return !outer_attrs.empty (); }
@@ -2921,6 +2952,8 @@ public:
std::unique_ptr<Type> &get_item_type () { return item_type; }
+ ExternKind get_extern_kind () override { return ExternKind::Static; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -3072,6 +3105,8 @@ public:
bool is_variadic () const { return has_variadics; }
+ ExternKind get_extern_kind () override { return ExternKind::Function; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -3149,6 +3184,8 @@ public:
return extern_items;
}
+ ItemKind get_item_kind () const override { return ItemKind::ExternBlock; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h
index 58f4db2..c2f6fef 100644
--- a/gcc/rust/hir/tree/rust-hir.h
+++ b/gcc/rust/hir/tree/rust-hir.h
@@ -175,6 +175,26 @@ class Item : public Stmt
// TODO: should outer attrs be defined here or in each derived class?
public:
+ enum class ItemKind
+ {
+ Static,
+ Constant,
+ TypeAlias,
+ Function,
+ UseDeclaration,
+ ExternBlock,
+ ExternCrate,
+ Struct,
+ Union,
+ Enum,
+ EnumItem, // FIXME: ARTHUR: Do we need that?
+ Trait,
+ Impl,
+ Module,
+ };
+
+ virtual ItemKind get_item_kind () const = 0;
+
// Unique pointer custom clone function
std::unique_ptr<Item> clone_item () const
{
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 6a2c1b6..e3c211e 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -17,8 +17,8 @@
// <http://www.gnu.org/licenses/>.
#include "rust-session-manager.h"
-#include "rust-unsafe-checker.h"
#include "rust-diagnostics.h"
+#include "rust-unsafe-checker.h"
#include "rust-lex.h"
#include "rust-parse.h"
#include "rust-macro-expand.h"
@@ -26,6 +26,7 @@
#include "rust-ast-lower.h"
#include "rust-hir-type-check.h"
#include "rust-privacy-check.h"
+#include "rust-const-checker.h"
#include "rust-tycheck-dump.h"
#include "rust-compile.h"
#include "rust-cfg-parser.h"
@@ -796,6 +797,8 @@ Session::parse_file (const char *filename)
return;
HIR::UnsafeChecker ().go (hir);
+ HIR::ConstChecker ().go (hir);
+
if (saw_errors ())
return;
diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h
new file mode 100644
index 0000000..c34eb90
--- /dev/null
+++ b/gcc/rust/util/rust-stacked-contexts.h
@@ -0,0 +1,86 @@
+// 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_CONTEXT_STACK_H
+#define RUST_CONTEXT_STACK_H
+
+#include "rust-system.h"
+
+namespace Rust {
+
+/**
+ * Context stack util class. This class is useful for situations where you can
+ * enter the same kind of context multiple times. For example, when dealing with
+ * unsafe contexts, you might be tempted to simply keep a boolean value.
+ *
+ * ```rust
+ * let a = 15;
+ * unsafe { // we set the boolean to true
+ * // Now unsafe operations are allowed!
+ * let b = *(&a as *const i32);
+ * let c = std::mem::transmute<i32, f32>(b); // Urgh!
+ * } // we set it to false
+ * ```
+ *
+ * However, since the language allows nested unsafe blocks, you may run into
+ * this situation:
+ *
+ * ```rust
+ * unsafe { // we set the boolean to true
+ * unsafe { // we set the boolean to true
+ * } // we set it to false
+ *
+ * // Now unsafe operations are forbidden again, the boolean is false
+ * let f = std::mem::transmute<i32, f32>(15); // Error!
+ * } // we set it to false
+ * ```
+ */
+template <typename T> class StackedContexts
+{
+public:
+ /**
+ * Enter a special context
+ */
+ void enter (T value) { stack.emplace_back (value); }
+
+ /**
+ * Exit a special context
+ */
+ T exit ()
+ {
+ rust_assert (!stack.empty ());
+
+ auto last = stack.back ();
+ stack.pop_back ();
+
+ return last;
+ }
+
+ /**
+ * Are we currently inside of a special context?
+ */
+ bool is_in_context () const { return !stack.empty (); }
+
+private:
+ /* Actual data */
+ std::vector<T> stack;
+};
+
+} // namespace Rust
+
+#endif /* !RUST_CONTEXT_STACK_H */
diff --git a/gcc/testsuite/rust/compile/const1.rs b/gcc/testsuite/rust/compile/const1.rs
new file mode 100644
index 0000000..5f19c67
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const1.rs
@@ -0,0 +1,6 @@
+fn bar() {}
+
+const fn foo() {
+ bar(); // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" }
+}
+
diff --git a/gcc/testsuite/rust/compile/const2.rs b/gcc/testsuite/rust/compile/const2.rs
new file mode 100644
index 0000000..17b6de5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const2.rs
@@ -0,0 +1,7 @@
+// { dg-additional-options "-w" }
+
+const fn foo() {
+ const fn bar() {}
+
+ bar();
+}
diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs
new file mode 100644
index 0000000..22dc3d3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/const3.rs
@@ -0,0 +1,7 @@
+fn size() -> usize {
+ 15
+}
+
+fn main() {
+ let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" }
+}
diff --git a/gcc/testsuite/rust/compile/unsafe1.rs b/gcc/testsuite/rust/compile/unsafe1.rs
new file mode 100644
index 0000000..9cd3f6b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe1.rs
@@ -0,0 +1,14 @@
+fn foo(_a: &i32) {}
+fn bar(_a: i32) {}
+
+static mut a: i32 = 15;
+
+fn main() {
+ foo(&a); // { dg-error "use of mutable static" }
+ bar(a); // { dg-error "use of mutable static" }
+
+ unsafe {
+ foo(&a);
+ bar(a);
+ }
+}
diff --git a/gcc/testsuite/rust/compile/unsafe2.rs b/gcc/testsuite/rust/compile/unsafe2.rs
new file mode 100644
index 0000000..e03e4bc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe2.rs
@@ -0,0 +1,16 @@
+fn foo(_a: &i32) {}
+fn bar(_a: i32) {}
+
+mod inner {
+ pub static mut a: i32 = 15;
+}
+
+fn main() {
+ foo(&inner::a); // { dg-error "use of mutable static" }
+ bar(inner::a); // { dg-error "use of mutable static" }
+
+ unsafe {
+ foo(&inner::a);
+ bar(inner::a);
+ }
+}
diff --git a/gcc/testsuite/rust/compile/unsafe3.rs b/gcc/testsuite/rust/compile/unsafe3.rs
new file mode 100644
index 0000000..56aec76
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe3.rs
@@ -0,0 +1,10 @@
+extern "C" {
+ static VALUE: char;
+}
+
+fn main() {
+ let _ = VALUE; // { dg-error "use of extern static" }
+ unsafe {
+ let _ = VALUE;
+ }
+}
diff --git a/gcc/testsuite/rust/compile/unsafe9.rs b/gcc/testsuite/rust/compile/unsafe9.rs
new file mode 100644
index 0000000..fb46c8f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe9.rs
@@ -0,0 +1,10 @@
+union U {
+ a: i32,
+ b: f32,
+ c: u8,
+}
+
+fn main() {
+ let u = U { a: 14 };
+ let _ = u.a; // { dg-error "access to union" }
+}