diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc | 578 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h | 150 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h | 416 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h | 243 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h | 290 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h | 270 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-bir-builder.h | 88 | ||||
-rw-r--r-- | gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc | 8 | ||||
-rw-r--r-- | gcc/rust/rust-session-manager.cc | 1402 |
10 files changed, 2815 insertions, 631 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 5be223e..d99d25c 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -149,6 +149,7 @@ GRS_OBJS = \ rust/rust-hir-type-check-enumitem.o \ rust/rust-hir-type-check-implitem.o \ rust/rust-borrow-checker.o \ + rust/rust-bir-builder-expr-stmt.o \ rust/rust-hir-dot-operator.o \ rust/rust-hir-path-probe.o \ rust/rust-type-util.o \ diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc new file mode 100644 index 0000000..1487c85 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -0,0 +1,578 @@ +// 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-bir-builder-expr-stmt.h" +#include "rust-bir-builder-lazyboolexpr.h" +#include "rust-bir-builder-pattern.h" +#include "rust-bir-builder-struct.h" + +namespace Rust { +namespace BIR { + +void +ExprStmtBuilder::visit (HIR::ClosureExpr &expr) +{ + auto closure_ty = lookup_type (expr)->as<TyTy::ClosureType> (); + std::vector<PlaceId> captures; + for (auto &capture : closure_ty->get_captures ()) + { + captures.push_back (ctx.place_db.lookup_variable (capture)); + } + + // Not a coercion site. + return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::StructExprStructFields &fields) +{ + auto struct_ty + = lookup_type (fields)->as<TyTy::ADTType> ()->get_variants ().at (0); + auto init_values = StructBuilder (ctx, struct_ty).build (fields); + return_expr (new InitializerExpr (std::move (init_values)), + lookup_type (fields)); +} + +void +ExprStmtBuilder::visit (HIR::StructExprStruct &expr) +{ + // There is no way to modify empty struct, which makes them constant. + return_place (ctx.place_db.get_constant (lookup_type (expr))); +} + +void +ExprStmtBuilder::visit (HIR::LiteralExpr &expr) +{ + // Different literal values of the same type are not distinguished. + return_place (ctx.place_db.get_constant (lookup_type (expr))); +} + +void +ExprStmtBuilder::visit (HIR::BorrowExpr &expr) +{ + auto operand = visit_expr (*expr.get_expr ()); + return_expr (new BorrowExpr (operand), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::DereferenceExpr &expr) +{ + auto operand = visit_expr (*expr.get_expr ()); + return_place (operand); +} + +void +ExprStmtBuilder::visit (HIR::ErrorPropagationExpr &expr) +{ + rust_sorry_at (expr.get_locus (), "error propagation is not supported"); +} + +void +ExprStmtBuilder::visit (HIR::NegationExpr &expr) +{ + PlaceId operand = visit_expr (*expr.get_expr ()); + return_expr (new Operator<1> ({operand}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::ArithmeticOrLogicalExpr &expr) +{ + PlaceId lhs = visit_expr (*expr.get_lhs ()); + PlaceId rhs = visit_expr (*expr.get_rhs ()); + return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::ComparisonExpr &expr) +{ + PlaceId lhs = visit_expr (*expr.get_lhs ()); + PlaceId rhs = visit_expr (*expr.get_rhs ()); + return_expr (new Operator<2> ({lhs, rhs}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr) +{ + return_place (LazyBooleanExprBuilder (ctx).build (expr)); +} + +void +ExprStmtBuilder::visit (HIR::TypeCastExpr &expr) +{ + return_place (visit_expr (*expr.get_expr ())); +} + +void +ExprStmtBuilder::visit (HIR::AssignmentExpr &expr) +{ + auto lhs = visit_expr (*expr.get_lhs ()); + auto rhs = visit_expr (*expr.get_rhs ()); + push_assignment (lhs, rhs); +} + +void +ExprStmtBuilder::visit (HIR::CompoundAssignmentExpr &expr) +{ + auto lhs = visit_expr (*expr.get_lhs ()); + auto rhs = visit_expr (*expr.get_rhs ()); + push_assignment (lhs, new Operator<2> ({lhs, rhs})); + // TODO: (philip) nicer unit? + return_place (ctx.place_db.get_constant (lookup_type (expr))); +} + +void +ExprStmtBuilder::visit (HIR::GroupedExpr &expr) +{ + // Uses accept_vis directly to avoid creating n new temporary. + expr.get_expr_in_parens ()->accept_vis (*this); +} + +void +ExprStmtBuilder::visit (HIR::ArrayExpr &expr) +{ + switch (expr.get_internal_elements ()->get_array_expr_type ()) + { + case HIR::ArrayElems::VALUES: { + auto init_values = visit_list ((static_cast<HIR::ArrayElemsValues *> ( + expr.get_internal_elements ().get ())) + ->get_values ()); + return_expr (new InitializerExpr (std::move (init_values)), + lookup_type (expr)); + break; + } + case HIR::ArrayElems::COPIED: { + auto init = visit_expr (*(static_cast<HIR::ArrayElemsCopied *> ( + expr.get_internal_elements ().get ())) + ->get_elem_to_copy ()); + return_expr (new InitializerExpr ({init}), lookup_type (expr)); + break; + } + } +} + +void +ExprStmtBuilder::visit (HIR::ArrayIndexExpr &expr) +{ + auto lhs = visit_expr (*expr.get_array_expr ()); + auto rhs = visit_expr (*expr.get_index_expr ()); + // The Index is not tracked in BIR. + (void) rhs; + return_place ( + ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs)); +} + +void +ExprStmtBuilder::visit (HIR::TupleExpr &expr) +{ + std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ()); + if (std::any_of (init_values.begin (), init_values.end (), + [this] (PlaceId id) { + return ctx.place_db[id].lifetime.has_lifetime (); + })) + { + ctx.place_db[expr_return_place].lifetime + = {ctx.lifetime_interner.get_anonymous ()}; + } + return_expr (new InitializerExpr (std::move (init_values)), + lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::TupleIndexExpr &expr) +{ + auto tuple = visit_expr (*expr.get_tuple_expr ()); + return_place (ctx.place_db.lookup_or_add_path (Place::FIELD, + lookup_type (expr), tuple, + expr.get_tuple_index ())); +} + +void +ExprStmtBuilder::visit (HIR::CallExpr &expr) +{ + PlaceId fn = visit_expr (*expr.get_fnexpr ()); + std::vector<PlaceId> arguments = visit_list (expr.get_arguments ()); + + TyTy::BaseType *call_type = ctx.place_db[fn].tyty; + if (auto fn_type = call_type->try_as<TyTy::FnType> ()) + { + for (size_t i = 0; i < fn_type->get_params ().size (); ++i) + { + coercion_site (arguments[i], fn_type->get_params ()[i].second); + } + } + else if (auto fn_ptr_type = call_type->try_as<TyTy::FnPtr> ()) + { + for (size_t i = 0; i < fn_ptr_type->get_params ().size (); ++i) + { + coercion_site (arguments[i], + fn_ptr_type->get_params ()[i].get_tyty ()); + } + } + else + { + rust_unreachable (); + } + + return_expr (new CallExpr (fn, std::move (arguments)), lookup_type (expr), + true); +} + +void +ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr) +{ + auto receiver = visit_expr (*expr.get_receiver_expr ()); + auto type = autoderef (receiver); + rust_assert (type->get_kind () == TyTy::ADT); + auto adt = type->as<TyTy::ADTType> (); + rust_assert (!adt->is_enum ()); + rust_assert (adt->number_of_variants () == 1); + TyTy::VariantDef *variant = adt->get_variants ().at (0); + + TyTy::StructFieldType *field_ty = nullptr; + size_t field_index = 0; + bool ok = variant->lookup_field (expr.get_field_name ().as_string (), + &field_ty, &field_index); + rust_assert (ok); + + return_place (ctx.place_db.lookup_or_add_path (Place::FIELD, + field_ty->get_field_type (), + receiver, field_index)); +} + +void +ExprStmtBuilder::visit (HIR::BlockExpr &block) +{ + for (auto &stmt : block.get_statements ()) + { + stmt->accept_vis (*this); + } + if (block.has_expr ()) + { + return_place (visit_expr (*block.get_final_expr ())); + } +} + +void +ExprStmtBuilder::visit (HIR::ContinueExpr &cont) +{ + // BuilderContext::LabelledBlockCtx loop_ctx; + // NodeId label = UNKNOWN_NODEID; + // if (cont.has_label ()) + // { + // if (!resolve_label (cont.get_label (), label)) + // return; + // } + // + // if (!find_block_ctx (label, loop_ctx)) + // { + // rust_error_at (cont.get_locus (), "unresolved loop label"); + // } + // + // add_jump_to (loop_ctx.continue_bb); +} + +void +ExprStmtBuilder::visit (HIR::BreakExpr &brk) +{ + // BuilderContext::LabelledBlockCtx block_ctx{}; + // NodeId label = UNKNOWN_NODEID; + // if (brk.has_label ()) + // { + // if (!resolve_label (brk.get_label (), label)) + // return; + // } + // if (!find_block_ctx (label, block_ctx)) + // { + // rust_error_at (brk.get_locus (), "unresolved labelled block"); + // } + // + // if (brk.has_break_expr ()) + // { + // brk.get_expr ()->accept_vis (*this); + // push_assignment (block_ctx.label_var, new Operator<1> ({translated})); + // } + // + // add_jump_to (block_ctx.break_bb); +} + +void +ExprStmtBuilder::visit (HIR::RangeFromToExpr &range) +{ + auto from = visit_expr (*range.get_from_expr ()); + auto to = visit_expr (*range.get_to_expr ()); + return_expr (new InitializerExpr ({from, to}), lookup_type (range)); +} + +void +ExprStmtBuilder::visit (HIR::RangeFromExpr &expr) +{ + auto from = visit_expr (*expr.get_from_expr ()); + return_expr (new InitializerExpr ({from}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::RangeToExpr &expr) +{ + auto to = visit_expr (*expr.get_to_expr ()); + return_expr (new InitializerExpr ({to}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::RangeFullExpr &expr) +{ + return_expr (new InitializerExpr ({}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::RangeFromToInclExpr &expr) +{ + auto from = visit_expr (*expr.get_from_expr ()); + auto to = visit_expr (*expr.get_to_expr ()); + return_expr (new InitializerExpr ({from, to}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr) +{ + auto to = visit_expr (*expr.get_to_expr ()); + return_expr (new InitializerExpr ({to}), lookup_type (expr)); +} + +void +ExprStmtBuilder::visit (HIR::ReturnExpr &ret) +{ + if (ret.has_return_expr ()) + { + push_assignment (RETURN_VALUE_PLACE, visit_expr (*ret.get_expr ())); + } + ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN); +} + +void +ExprStmtBuilder::visit (HIR::UnsafeBlockExpr &expr) +{ + rust_sorry_at (expr.get_locus (), "unsafe blocks are not supported"); +} + +void +ExprStmtBuilder::visit (HIR::LoopExpr &expr) +{ + // PlaceId label_var = ctx.place_db.add_temporary (nullptr); + // NodeId label; + // if (!resolve_label (expr.get_loop_label (), label)) + // return; + // ctx.label_place_map.emplace (label, label_var); + // + // expr.get_loop_block ()->accept_vis (*this); + // + // translated = label_var; +} +void +ExprStmtBuilder::visit (HIR::WhileLoopExpr &expr) +{ + // // TODO: Desugar in AST->HIR ??? + // PlaceId label_var = ctx.place_db.add_temporary (nullptr); + // NodeId label; + // if (!resolve_label (expr.get_loop_label (), label)) + // return; + // ctx.label_place_map.emplace (label, label_var); + // + // expr.get_predicate_expr ()->accept_vis (*this); + // + // expr.get_loop_block ()->accept_vis (*this); + // + // translated = label_var; +} +void +ExprStmtBuilder::visit (HIR::WhileLetLoopExpr &expr) +{ + // TODO: Desugar in AST->HIR +} +void +ExprStmtBuilder::visit (HIR::IfExpr &expr) +{ + // If without else cannot return a non-unit value (see [E0317]). + + push_switch (visit_expr (*expr.get_if_condition ())); + BasicBlockId if_block = ctx.current_bb; + + ctx.current_bb = new_bb (); + (void) visit_expr (*expr.get_if_block ()); + BasicBlockId then_block = ctx.current_bb; + + ctx.current_bb = new_bb (); + BasicBlockId final_block = ctx.current_bb; + return_unit (expr); + + // Jumps are added at the end to match rustc MIR order for easier comparison. + add_jump (if_block, then_block); + add_jump (if_block, final_block); + add_jump (then_block, final_block); +} + +void +ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr) +{ + PlaceId result = ctx.place_db.add_temporary (lookup_type (expr)); + + push_switch (visit_expr (*expr.get_if_condition ())); + BasicBlockId if_block = ctx.current_bb; + + ctx.current_bb = new_bb (); + auto then_res = visit_expr (*expr.get_if_block ()); + push_assignment (result, then_res); + BasicBlockId then_block = ctx.current_bb; + + ctx.current_bb = new_bb (); + auto else_res = visit_expr (*expr.get_else_block ()); + push_assignment (result, else_res); + BasicBlockId else_block = ctx.current_bb; + + ctx.current_bb = new_bb (); + BasicBlockId final_block = ctx.current_bb; + return_place (result); + + // Jumps are added at the end to match rustc MIR order for easier comparison. + add_jump (if_block, then_block); + add_jump (if_block, else_block); + add_jump (then_block, final_block); + add_jump (else_block, final_block); +} +void +ExprStmtBuilder::visit (HIR::IfLetExpr &expr) +{ + rust_sorry_at (expr.get_locus (), "if let expressions are not supported"); +} +void +ExprStmtBuilder::visit (HIR::IfLetExprConseqElse &expr) +{ + rust_sorry_at (expr.get_locus (), "if let expressions are not supported"); +} +void +ExprStmtBuilder::visit (HIR::MatchExpr &expr) +{ + // // TODO + // expr.get_scrutinee_expr ()->accept_vis (*this); + // PlaceId scrutinee = translated; + // + // BasicBlockId final_bb = new_bb (); + // + // BasicBlockId next_case_bb = new_bb (); + // for (auto &match_case : expr.get_match_cases ()) + // { + // BasicBlockId body_bb = new_bb (); + // + // BasicBlockId next_pattern_bb = new_bb (); + // for (auto &pat : match_case.get_arm ().get_patterns ()) + // { + // compile_pattern_validation (*pat, scrutinee); + // push_switch (translated); + // add_jump_to (next_pattern_bb); + // start_new_subsequent_bb (); + // compile_pattern_bindings (*pat, scrutinee); + // add_jump_to (body_bb); + // + // ctx.current_bb = next_pattern_bb; + // next_pattern_bb = new_bb (); + // } + // ctx.current_bb = next_pattern_bb; + // // No pattern matched, go to the next case. + // add_jump_to (next_case_bb); + // + // ctx.current_bb = body_bb; + // match_case.get_expr ()->accept_vis (*this); + // add_jump_to (final_bb); + // + // ctx.current_bb = next_case_bb; + // next_case_bb = new_bb (); + // } + // add_jump_to (final_bb); + // + // ctx.current_bb = final_bb; +} + +void +ExprStmtBuilder::visit (HIR::AwaitExpr &expr) +{ + rust_sorry_at (expr.get_locus (), "await expressions are not supported"); +} + +void +ExprStmtBuilder::visit (HIR::AsyncBlockExpr &expr) +{ + rust_sorry_at (expr.get_locus (), "async blocks are not supported"); +} + +void +ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr) +{ + PlaceId result; + // Note: Type is only stored for the expr, not the segment. + bool ok = resolve_variable (expr.get_final_segment (), result); + rust_assert (ok); + return_place (result); +} + +void +ExprStmtBuilder::visit (HIR::PathInExpression &expr) +{ + PlaceId result; + // Note: Type is only stored for the expr, not the segment. + bool ok = resolve_variable (expr.get_final_segment (), result); + rust_assert (ok); + return_place (result); +} + +void +ExprStmtBuilder::visit (HIR::LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + { + auto init = visit_expr (*stmt.get_init_expr ()); + PatternBindingBuilder (ctx, init, stmt.get_type ().get ()) + .go (*stmt.get_pattern ()); + } + else if (stmt.get_pattern ()->get_pattern_type () == HIR::Pattern::IDENTIFIER) + { + auto var = declare_variable (stmt.get_pattern ()->get_mappings ()); + auto &var_place = ctx.place_db[var]; + if (var_place.tyty->get_kind () == TyTy::REF) + { + auto p_type = tl::optional<HIR::ReferenceType *> ( + static_cast<HIR::ReferenceType *> (stmt.get_type ().get ())); + var_place.lifetime = ctx.lookup_lifetime ( + p_type.map (&HIR::ReferenceType::get_lifetime)); + } + return; + } + else + { + // TODO + rust_sorry_at (stmt.get_locus (), "pattern matching in let statements"); + } +} + +void +ExprStmtBuilder::visit (HIR::ExprStmt &stmt) +{ + (void) visit_expr (*stmt.get_expr ()); +} + +} // namespace BIR +} // namespace Rust
\ No newline at end of file diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h new file mode 100644 index 0000000..f46cba5 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -0,0 +1,150 @@ +// Copyright (C) 2020-2023 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_BIR_BUILDER_EXPR_H +#define RUST_BIR_BUILDER_EXPR_H + +#include "rust-hir-visitor.h" +#include "rust-bir-builder-internal.h" + +namespace Rust { +namespace BIR { + +class ExprStmtBuilder : public AbstractExprBuilder, public HIR::HIRStmtVisitor +{ + PlaceId expr_return_place = INVALID_PLACE; + +public: + explicit ExprStmtBuilder (BuilderContext &ctx) : AbstractExprBuilder (ctx) {} + + PlaceId build (HIR::Expr &expr) { return visit_expr (expr); } + +private: + template <typename T> + std::vector<PlaceId> visit_list (std::vector<std::unique_ptr<T>> &list) + { + std::vector<PlaceId> result; + for (auto &elem : list) + { + result.push_back (visit_expr (*elem)); + } + return result; + } + +protected: // Expr + // TODO: test when compiles + void visit (HIR::ClosureExpr &expr) override; + void visit (HIR::StructExprStructFields &fields) override; + void visit (HIR::StructExprStruct &expr) override; + void visit (HIR::LiteralExpr &expr) override; + void visit (HIR::BorrowExpr &expr) override; + void visit (HIR::DereferenceExpr &expr) override; + // TODO: desugar in AST->HIR + void visit (HIR::ErrorPropagationExpr &expr) override; + void visit (HIR::NegationExpr &expr) override; + void visit (HIR::ArithmeticOrLogicalExpr &expr) override; + void visit (HIR::ComparisonExpr &expr) override; + void visit (HIR::LazyBooleanExpr &expr) override; + void visit (HIR::TypeCastExpr &expr) override; + void visit (HIR::AssignmentExpr &expr) override; + void visit (HIR::CompoundAssignmentExpr &expr) override; + void visit (HIR::GroupedExpr &expr) override; + void visit (HIR::ArrayExpr &expr) override; + void visit (HIR::ArrayIndexExpr &expr) override; + void visit (HIR::TupleExpr &expr) override; + void visit (HIR::TupleIndexExpr &expr) override; + void visit (HIR::CallExpr &expr) override; + void visit (HIR::MethodCallExpr &expr) override {} + void visit (HIR::FieldAccessExpr &expr) override; + void visit (HIR::BlockExpr &block) override; + void visit (HIR::ContinueExpr &cont) override; + void visit (HIR::BreakExpr &brk) override; + void visit (HIR::RangeFromToExpr &range) override; + void visit (HIR::RangeFromExpr &expr) override; + void visit (HIR::RangeToExpr &expr) override; + void visit (HIR::RangeFullExpr &expr) override; + void visit (HIR::RangeFromToInclExpr &expr) override; + void visit (HIR::RangeToInclExpr &expr) override; + void visit (HIR::ReturnExpr &ret) override; + void visit (HIR::UnsafeBlockExpr &expr) override; + void visit (HIR::LoopExpr &expr) override; + void visit (HIR::WhileLoopExpr &expr) override; + void visit (HIR::WhileLetLoopExpr &expr) override; + void visit (HIR::IfExpr &expr) override; + void visit (HIR::IfExprConseqElse &expr) override; + + void visit (HIR::IfLetExpr &expr) override; + void visit (HIR::IfLetExprConseqElse &expr) override; + void visit (HIR::MatchExpr &expr) override; + void visit (HIR::AwaitExpr &expr) override; + void visit (HIR::AsyncBlockExpr &expr) override; + + // Nodes not containing executable code. Nothing to do. + void visit (HIR::QualifiedPathInExpression &expr) override; + void visit (HIR::PathInExpression &expr) override; + +protected: // Handled by other visitors + void visit (HIR::StructExprFieldIdentifier &field) override + { + rust_unreachable (); + } + void visit (HIR::StructExprFieldIdentifierValue &field) override + { + rust_unreachable (); + } + void visit (HIR::StructExprFieldIndexValue &field) override + { + rust_unreachable (); + } + +protected: // Stmt + void visit (HIR::LetStmt &stmt) override; + + void visit (HIR::ExprStmt &stmt) override; + +protected: // Unused + // Only executable code of a single function/method is translated. + // All other items are ignored. + void visit (HIR::EnumItemTuple &tuple) override {} + void visit (HIR::EnumItemStruct &a_struct) override {} + void visit (HIR::EnumItem &item) override {} + void visit (HIR::TupleStruct &tuple_struct) override {} + void visit (HIR::EnumItemDiscriminant &discriminant) override {} + void visit (HIR::TypePathSegmentFunction &segment) override {} + void visit (HIR::TypePath &path) override {} + void visit (HIR::QualifiedPathInType &path) override {} + void visit (HIR::Module &module) override {} + void visit (HIR::ExternCrate &crate) override {} + void visit (HIR::UseDeclaration &use_decl) override {} + void visit (HIR::Function &function) override {} + void visit (HIR::TypeAlias &type_alias) override {} + void visit (HIR::StructStruct &struct_item) override {} + void visit (HIR::Enum &enum_item) override {} + void visit (HIR::Union &union_item) override {} + void visit (HIR::ConstantItem &const_item) override {} + void visit (HIR::StaticItem &static_item) override {} + void visit (HIR::Trait &trait) override {} + void visit (HIR::ImplBlock &impl) override {} + void visit (HIR::ExternBlock &block) override {} + void visit (HIR::EmptyStmt &stmt) override {} +}; + +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_EXPR_H diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h new file mode 100644 index 0000000..48116d8 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -0,0 +1,416 @@ +// Copyright (C) 2020-2023 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_BIR_BUILDER_INTERNAL_H +#define RUST_BIR_BUILDER_INTERNAL_H + +#include "rust-bir-place.h" +#include "rust-hir-expr.h" +#include "rust-hir-item.h" +#include "rust-hir-type-check.h" +#include "rust-hir-visitor.h" +#include "rust-name-resolver.h" +#include "rust-bir.h" + +namespace Rust { + +namespace BIR { + +class LifetimeResolver +{ + using Index = uint32_t; + using Value = std::string; + + Index next_index = FIRST_NORMAL_LIFETIME_ID; + std::unordered_map<Value, Index> value_to_index; + +public: + Index intern (const Value &value) + { + auto found = value_to_index.find (value); + if (found != value_to_index.end ()) + { + return found->second; + } + value_to_index.emplace (value, next_index); + return next_index++; + } + Index get_anonymous () { return next_index++; } +}; + +struct BuilderContext +{ + struct LabelledBlockCtx + { + NodeId label; // UNKNOWN_NODEID if no label + PlaceId label_var; + BasicBlockId break_bb; + BasicBlockId continue_bb; // Only valid for loops + }; + + // Context + Resolver::TypeCheckContext &tyctx; + Resolver::Resolver &resolver; + + std::vector<BasicBlock> basic_blocks; + size_t current_bb = 0; + + /** + * Allocation and lookup of places (variables, temporaries, paths, and + * constants) + */ + PlaceDB place_db; + LifetimeResolver lifetime_interner; + std::vector<PlaceId> arguments; + /** + * Since labels can be used to return values, we need to reserve a place for + * them. This map associates labels with their respective places. + */ + std::unordered_map<NodeId, PlaceId> label_place_map; + + std::vector<LabelledBlockCtx> loop_stack; + +public: + BuilderContext () + : tyctx (*Resolver::TypeCheckContext::get ()), + resolver (*Resolver::Resolver::get ()) + { + basic_blocks.emplace_back (); // StartBB + } + + BasicBlock &get_current_bb () { return basic_blocks[current_bb]; } + + Lifetime lookup_lifetime (const tl::optional<HIR::Lifetime> &lifetime) + { + if (!lifetime.has_value ()) + return {lifetime_interner.get_anonymous ()}; + switch (lifetime->get_lifetime_type ()) + { + case AST::Lifetime::NAMED: { + return {lifetime_interner.intern (lifetime->get_name ())}; + } + case AST::Lifetime::STATIC: { + return STATIC_LIFETIME; + } + case AST::Lifetime::WILDCARD: { + rust_sorry_at (lifetime->get_locus (), + "lifetime elision is not yet implemented"); + return NO_LIFETIME; + } + } + rust_unreachable (); + }; +}; + +// Common infrastructure for building BIR from HIR. +class AbstractBuilder +{ +protected: + BuilderContext &ctx; + + // This emulates the return value of the visitor, to be able to use the + // current visitor infrastructure, where the return value is forced to be + // void. + PlaceId translated = INVALID_PLACE; + +protected: + explicit AbstractBuilder (BuilderContext &ctx) : ctx (ctx) {} + + WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Expr &expr) + { + return expr.get_mappings ().get_nodeid (); + } + + WARN_UNUSED_RESULT static NodeId get_nodeid (HIR::Pattern &pattern) + { + return pattern.get_mappings ().get_nodeid (); + } + + template <typename T> + WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (T &pattern) const + { + return lookup_type (pattern.get_mappings ().get_hirid ()); + } + + WARN_UNUSED_RESULT TyTy::BaseType *lookup_type (HirId hirid) const + { + TyTy::BaseType *type = nullptr; + bool ok = ctx.tyctx.lookup_type (hirid, &type); + rust_assert (ok); + rust_assert (type != nullptr); + return type; + } + + PlaceId declare_variable (const Analysis::NodeMapping &node) + { + const NodeId nodeid = node.get_nodeid (); + const HirId hirid = node.get_hirid (); + + // In debug mode check that the variable is not already declared. + rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE); + + return ctx.place_db.add_variable (nodeid, lookup_type (hirid)); + } + + PlaceId declare_variable (const Analysis::NodeMapping &node, + TyTy::BaseType *type) + { + const NodeId nodeid = node.get_nodeid (); + + // In debug mode check that the variable is not already declared. + rust_assert (ctx.place_db.lookup_variable (nodeid) == INVALID_PLACE); + + return ctx.place_db.add_variable (nodeid, type); + } + + void push_assignment (PlaceId lhs, AbstractExpr *rhs) + { + ctx.get_current_bb ().statements.emplace_back (lhs, rhs); + translated = lhs; + } + + void push_assignment (PlaceId lhs, PlaceId rhs) + { + push_assignment (lhs, new Assignment (rhs)); + } + + void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty) + { + PlaceId tmp = ctx.place_db.add_temporary (tyty); + push_assignment (tmp, rhs); + } + + void push_switch (PlaceId switch_val) + { + ctx.get_current_bb ().statements.emplace_back (Node::Kind::SWITCH, + switch_val); + } + + void push_storage_dead (PlaceId place) + { + ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_DEAD, + place); + } + + void push_storage_live (PlaceId place) + { + ctx.get_current_bb ().statements.emplace_back (Node::Kind::STORAGE_LIVE, + place); + } + + BasicBlockId new_bb () + { + ctx.basic_blocks.emplace_back (); + return ctx.basic_blocks.size () - 1; + } + + BasicBlockId start_new_subsequent_bb () + { + BasicBlockId bb = new_bb (); + ctx.get_current_bb ().successors.emplace_back (bb); + ctx.current_bb = bb; + return bb; + } + + void add_jump (BasicBlockId from, BasicBlockId to) + { + ctx.basic_blocks[from].successors.emplace_back (to); + } + + void add_jump_to (BasicBlockId bb) { add_jump (ctx.current_bb, bb); } + +protected: + template <typename T> bool resolve_label (T &label, NodeId &resolved_label) + { + if (!ctx.resolver.lookup_resolved_label ( + label.get_mappings ().get_nodeid (), &resolved_label)) + { + rust_error_at (label.get_locus (), "unresolved label"); + return false; + } + return true; + } + + template <typename T> + bool resolve_variable (T &variable, PlaceId &resolved_variable) + { + NodeId variable_id; + if (!ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id)) + { + // TODO: should this be assert? (should be caught by typecheck) + rust_error_at (variable.get_locus (), "unresolved variable"); + return false; + } + resolved_variable = ctx.place_db.lookup_variable (variable_id); + return true; + } + + bool find_block_ctx (NodeId label, BuilderContext::LabelledBlockCtx &block) + { + if (ctx.loop_stack.empty ()) + return false; + if (label == UNKNOWN_NODEID) + { + block = ctx.loop_stack.back (); + return true; + } + auto found + = std::find_if (ctx.loop_stack.rbegin (), ctx.loop_stack.rend (), + [&label] (const BuilderContext::LabelledBlockCtx &block) { + return block.label == label; + }); + if (found == ctx.loop_stack.rend ()) + return false; + block = *found; + return true; + } + + /** + * Performs implicit coercions on the `translated` place defined for a + * coercion site. + * + * Reference: https://doc.rust-lang.org/reference/type-coercions.html + * + * The only coercion relevant to BIR is the autoderef. All other coercions + * will be taken in account because the type is extracted from each node and + * not derived from operations in HIR/BIR. The borrowck does not care about + * type transitions. Lifetimes are not coerced, rather new are created with + * defined bounds to the original ones. + */ + void coercion_site (PlaceId &place, TyTy::BaseType *expected_ty) + { + auto count_ref_levels = [] (TyTy::BaseType *ty) { + size_t count = 0; + while (auto r = ty->try_as<TyTy::ReferenceType> ()) + { + ty = r->get_base (); + count++; + } + return count; + }; + + auto actual_ty = ctx.place_db[place].tyty; + + auto deref_count + = count_ref_levels (actual_ty) - count_ref_levels (expected_ty); + + for (size_t i = 0; i < deref_count; ++i) + { + actual_ty = actual_ty->as<TyTy::ReferenceType> ()->get_base (); + place + = ctx.place_db.lookup_or_add_path (Place::DEREF, actual_ty, place); + } + } + + /** Dereferences the `translated` place until it is at most one reference and + * return the base type. */ + TyTy::BaseType *autoderef (PlaceId &place) + { + auto ty = ctx.place_db[place].tyty; + while (auto ref_ty = ty->try_as<TyTy::ReferenceType> ()) + { + ty = ref_ty->get_base (); + place = ctx.place_db.lookup_or_add_path (Place::DEREF, ty, place); + } + return ty; + } + + /** For operator */ + void autoref () + { + if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF) + { + auto ty = ctx.place_db[translated].tyty; + push_tmp_assignment ( + new BorrowExpr (translated), + new TyTy::ReferenceType (ty->get_ref (), TyTy::TyVar (ty->get_ref ()), + Mutability::Imm)); + } + } +}; + +class AbstractExprBuilder : public AbstractBuilder, + public HIR::HIRExpressionVisitor +{ +protected: + // Exactly one of this and `translated` is used by each visitor. + AbstractExpr *expr_return_expr = nullptr; + +protected: + explicit AbstractExprBuilder (BuilderContext &ctx) : AbstractBuilder (ctx) {} + + PlaceId visit_expr (HIR::Expr &expr) + { + // Reset return places. + translated = INVALID_PLACE; + expr_return_expr = nullptr; + expr.accept_vis (*this); + if (translated != INVALID_PLACE) + { + auto result = translated; + translated = INVALID_PLACE; + return result; + } + else if (expr_return_expr != nullptr) + { + // Only allocate temporary, if needed. + push_tmp_assignment (expr_return_expr, lookup_type (expr)); + expr_return_expr = nullptr; + return translated; + } + else + { + return ctx.place_db.get_constant (lookup_type (expr)); + } + } + + void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, + bool can_panic = false) + { + rust_assert (expr_return_expr == nullptr); + if (can_panic) + { + push_tmp_assignment (expr, ty); + // TODO, cleanup? + start_new_subsequent_bb (); + } + else + { + translated = INVALID_PLACE; + expr_return_expr = expr; + } + } + + void return_place (PlaceId place) + { + expr_return_expr = nullptr; + translated = place; + } + + void return_unit (HIR::Expr &expr) + { + expr_return_expr = nullptr; + translated = ctx.place_db.get_constant (lookup_type (expr)); + } +}; + +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_INTERNAL_H diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h new file mode 100644 index 0000000..4ec87d9 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -0,0 +1,243 @@ +// 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_BIR_BUILDER_LAZYBOOLEXPR_H +#define RUST_BIR_BUILDER_LAZYBOOLEXPR_H + +#include "rust-bir-builder-internal.h" +#include "rust-bir-builder-expr-stmt.h" +#include "rust-hir-expr.h" + +namespace Rust { +namespace BIR { + +/** + * Special builder is needed to store short-circuiting context for directly + * nested lazy boolean expressions. + */ +class LazyBooleanExprBuilder : public AbstractBuilder, + public HIR::HIRExpressionVisitor +{ + BasicBlockId short_circuit_bb; + +public: + explicit LazyBooleanExprBuilder (BuilderContext &ctx) + : AbstractBuilder (ctx), short_circuit_bb (0) + {} + + PlaceId build (HIR::LazyBooleanExpr &expr) + { + PlaceId return_place = ctx.place_db.add_temporary (lookup_type (expr)); + + short_circuit_bb = new_bb (); + visit (expr); + push_assignment (return_place, translated); + auto final_bb = new_bb (); + add_jump_to (final_bb); + + ctx.current_bb = short_circuit_bb; + translated = ctx.place_db.get_constant (lookup_type (expr)); + push_assignment (return_place, translated); + add_jump_to (final_bb); + + ctx.current_bb = final_bb; + return return_place; + } + +protected: + void visit (HIR::LazyBooleanExpr &expr) override + { + expr.get_lhs ()->accept_vis (*this); + push_switch (translated); + add_jump_to (short_circuit_bb); + + start_new_subsequent_bb (); + expr.get_rhs ()->accept_vis (*this); + } + void visit (HIR::GroupedExpr &expr) override + { + expr.get_expr_in_parens ()->accept_vis (*this); + } + +protected: +public: + void visit (HIR::QualifiedPathInExpression &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::PathInExpression &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ClosureExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::StructExprStructFields &fields) override + { + ExprStmtBuilder (ctx).build (fields); + } + void visit (HIR::StructExprStruct &a_struct) override + { + ExprStmtBuilder (ctx).build (a_struct); + } + void visit (HIR::LiteralExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::BorrowExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::DereferenceExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ErrorPropagationExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::NegationExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ArithmeticOrLogicalExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ComparisonExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::TypeCastExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::AssignmentExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::CompoundAssignmentExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ArrayExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::ArrayIndexExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::TupleExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::TupleIndexExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::CallExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::MethodCallExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::FieldAccessExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::BlockExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::UnsafeBlockExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::LoopExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::WhileLoopExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::WhileLetLoopExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::IfExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::IfExprConseqElse &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::IfLetExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::IfLetExprConseqElse &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::MatchExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::AwaitExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + void visit (HIR::AsyncBlockExpr &expr) override + { + translated = ExprStmtBuilder (ctx).build (expr); + } + +protected: // Illegal at this position. + void visit (HIR::StructExprFieldIdentifier &field) override + { + rust_unreachable (); + } + void visit (HIR::StructExprFieldIdentifierValue &field) override + { + rust_unreachable (); + } + void visit (HIR::StructExprFieldIndexValue &field) override + { + rust_unreachable (); + } + void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); } + void visit (HIR::BreakExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromToExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeToExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFullExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); } + void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); } +}; + +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_LAZYBOOLEXPR_H diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h new file mode 100644 index 0000000..0b4c83e --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h @@ -0,0 +1,290 @@ +// Copyright (C) 2020-2023 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_BIR_BUILDER_PATTERN_H +#define RUST_BIR_BUILDER_PATTERN_H + +#include "rust-bir-builder-internal.h" + +namespace Rust { +namespace BIR { +// Compiles binding of values into newly created variables. +// Used in let, match arm, and function parameter patterns. +class PatternBindingBuilder : protected AbstractBuilder, + public HIR::HIRPatternVisitor +{ + PlaceId init; + // This is where lifetime annotations are stored. + tl::optional<HIR::Type *> type; + + // Emulates recursive stack saving and restoring inside a visitor. + class SavedState + { + PatternBindingBuilder *builder; + + public: + const PlaceId init; + const tl::optional<HIR::Type *> type; + + public: + explicit SavedState (PatternBindingBuilder *builder) + : builder (builder), init (builder->init), type (builder->type) + {} + + ~SavedState () + { + builder->init = init; + builder->type = type; + } + }; + +public: + PatternBindingBuilder (BuilderContext &ctx, PlaceId init, HIR::Type *type) + : AbstractBuilder (ctx), init (init), + type (type ? tl::optional<HIR::Type *> (type) : tl::nullopt) + {} + + void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); } + + void visit_identifier (const Analysis::NodeMapping &node, bool is_ref) + { + translated = declare_variable (node); + if (is_ref) + { + push_assignment (translated, new BorrowExpr (init)); + } + else + { + push_assignment (translated, init); + } + auto &init_place = ctx.place_db[init]; + auto &translated_place = ctx.place_db[translated]; + if (init_place.tyty->get_kind () == TyTy::REF) + { + init_place.lifetime = ctx.lookup_lifetime (type.map ([] (HIR::Type *t) { + return static_cast<HIR::ReferenceType *> (t)->get_lifetime (); + })); + translated_place.lifetime = init_place.lifetime; + } + } + + void visit (HIR::IdentifierPattern &pattern) override + { + // Top-level identifiers are resolved directly to avoid useless temporary + // (for cleaner BIR). + visit_identifier (pattern.get_mappings (), pattern.get_is_ref ()); + } + void visit (HIR::ReferencePattern &pattern) override + { + SavedState saved (this); + + auto ref_type = type.map ( + [] (HIR::Type *t) { return static_cast<HIR::ReferenceType *> (t); }); + + type = ref_type.map ( + [] (HIR::ReferenceType *r) { return r->get_base_type ().get (); }); + init = ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern), + saved.init); + ctx.place_db[init].lifetime + = ctx.lookup_lifetime (ref_type.map (&HIR::ReferenceType::get_lifetime)); + pattern.get_referenced_pattern ()->accept_vis (*this); + } + void visit (HIR::SlicePattern &pattern) override + { + SavedState saved (this); + + type = type.map ([] (HIR::Type *t) { + return static_cast<HIR::SliceType *> (t)->get_element_type ().get (); + }); + // All indexes are supposed to point to the same place for borrow-checking. + init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern), + saved.init); + for (auto &item : pattern.get_items ()) + { + item->accept_vis (*this); + } + } + void visit (HIR::AltPattern &pattern) override + { + rust_sorry_at (pattern.get_locus (), + "borrow-checking of alt patterns is not yet implemented"); + } + void visit (HIR::StructPattern &pattern) override + { + SavedState saved (this); + + auto tyty = ctx.place_db[init].tyty; + rust_assert (tyty->get_kind () == TyTy::ADT); + auto adt_ty = static_cast<TyTy::ADTType *> (tyty); + rust_assert (adt_ty->is_struct_struct ()); + auto struct_ty = adt_ty->get_variants ().at (0); + + auto struct_type = type.map ([] (HIR::Type *t) { + return static_cast<HIR::TypePath *> (t)->get_final_segment ().get (); + }); + for (auto &field : + pattern.get_struct_pattern_elems ().get_struct_pattern_fields ()) + { + switch (field->get_item_type ()) + { + case HIR::StructPatternField::TUPLE_PAT: { + auto tuple + = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ()); + init = ctx.place_db.lookup_or_add_path ( + Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), + saved.init, tuple->get_index ()); + tuple->get_tuple_pattern ()->accept_vis (*this); + break; + } + case HIR::StructPatternField::IDENT_PAT: { + auto ident_field + = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ()); + TyTy::StructFieldType *field_ty = nullptr; + size_t field_index = 0; + auto ok = struct_ty->lookup_field ( + ident_field->get_identifier ().as_string (), &field_ty, + &field_index); + rust_assert (ok); + init + = ctx.place_db.lookup_or_add_path (Place::FIELD, + field_ty->get_field_type (), + saved.init, field_index); + ident_field->get_pattern ()->accept_vis (*this); + break; + } + case HIR::StructPatternField::IDENT: { + auto ident_field + = static_cast<HIR::StructPatternFieldIdent *> (field.get ()); + TyTy::StructFieldType *field_ty = nullptr; + size_t field_index = 0; + auto ok = struct_ty->lookup_field ( + ident_field->get_identifier ().as_string (), &field_ty, + &field_index); + rust_assert (ok); + init + = ctx.place_db.lookup_or_add_path (Place::FIELD, + field_ty->get_field_type (), + saved.init, field_index); + visit_identifier (ident_field->get_mappings (), + ident_field->get_has_ref ()); + break; + } + } + } + } + void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields, + SavedState &saved, size_t &index) + { + for (auto &item : fields) + { + type = saved.type.map ([&] (HIR::Type *t) { + return static_cast<HIR::TupleType *> (t) + ->get_elems () + .at (index) + .get (); + }); + init + = ctx.place_db.lookup_or_add_path (Place::FIELD, lookup_type (*item), + saved.init, index); + item->accept_vis (*this); + index++; + } + } + void visit (HIR::TuplePattern &pattern) override + { + SavedState saved (this); + + size_t index = 0; + switch (pattern.get_items ()->get_item_type ()) + { + case HIR::TuplePatternItems::MULTIPLE: { + auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( + *pattern.get_items ()); + visit_tuple_fields (items.get_patterns (), saved, index); + break; + } + case HIR::TuplePatternItems::RANGED: { + auto &items = static_cast<HIR::TuplePatternItemsRanged &> ( + *pattern.get_items ()); + + auto tyty = ctx.place_db[init].tyty; + rust_assert (tyty->get_kind () == TyTy::TUPLE); + + auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields () + - items.get_lower_patterns ().size () + - items.get_upper_patterns ().size (); + + visit_tuple_fields (items.get_lower_patterns (), saved, index); + index += skipped; + visit_tuple_fields (items.get_upper_patterns (), saved, index); + break; + } + } + init = saved.init; + } + void visit (HIR::TupleStructPattern &pattern) override + { + SavedState saved (this); + + size_t index = 0; + switch (pattern.get_items ()->get_item_type ()) + { + case HIR::TupleStructItems::RANGE: { + auto &items + = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ()); + + auto tyty = ctx.place_db[init].tyty; + rust_assert (tyty->get_kind () == TyTy::ADT); + auto adt_ty = static_cast<TyTy::ADTType *> (tyty); + rust_assert (adt_ty->is_tuple_struct ()); + + auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size () + - items.get_lower_patterns ().size () + - items.get_upper_patterns ().size (); + + visit_tuple_fields (items.get_lower_patterns (), saved, index); + index += skipped; + visit_tuple_fields (items.get_upper_patterns (), saved, index); + break; + } + case HIR::TupleStructItems::NO_RANGE: { + auto &items = static_cast<HIR::TupleStructItemsNoRange &> ( + *pattern.get_items ()); + visit_tuple_fields (items.get_patterns (), saved, index); + break; + } + } + } + void visit (HIR::WildcardPattern &pattern) override {} + + // Unused for binding. + void visit (HIR::LiteralPattern &pattern) override {} + void visit (HIR::PathInExpression &expression) override {} + void visit (HIR::QualifiedPathInExpression &expression) override {} + void visit (HIR::RangePattern &pattern) override {} + +private: + template <typename T> tl::optional<T> *get_type () + { + return static_cast<T *> (type); + } +}; +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_PATTERN_H diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h new file mode 100644 index 0000000..fa2f596 --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -0,0 +1,270 @@ +// Copyright (C) 2020-2023 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_BIR_BUILDER_STRUCT_H +#define RUST_BIR_BUILDER_STRUCT_H + +#include "rust-bir-builder-internal.h" +#include "rust-bir-builder-expr-stmt.h" + +namespace Rust { +namespace BIR { + +// Separated because it needs the struct type as a context. +class StructBuilder : public AbstractBuilder, public HIR::HIRFullVisitor +{ + TyTy::VariantDef *struct_ty; + std::vector<PlaceId> init_values; + +public: + StructBuilder (BuilderContext &ctx, TyTy::VariantDef *struct_ty) + : AbstractBuilder (ctx), struct_ty (struct_ty) + { + init_values.reserve (struct_ty->get_fields ().size ()); + } + + std::vector<PlaceId> &&build (HIR::StructExprStructFields &struct_expr) + { + for (auto &field : struct_expr.get_fields ()) + field->accept_vis (*this); + return std::move (init_values); + } + + void visit (HIR::StructExprFieldIdentifier &field) override + { + resolve_variable (field, translated); + handle_named_field (field); + } + void visit (HIR::StructExprFieldIdentifierValue &field) override + { + translated = ExprStmtBuilder (ctx).build (*field.get_value ()); + handle_named_field (field); + } + void visit (HIR::StructExprFieldIndexValue &field) override + { + translated = ExprStmtBuilder (ctx).build (*field.get_value ()); + coercion_site (translated, + struct_ty->get_field_at_index (field.get_tuple_index ()) + ->get_field_type ()); + init_values.push_back (translated); + } + +private: + template <typename T> void handle_named_field (T &field) + { + size_t field_index; + TyTy::StructFieldType *field_type; + bool ok = struct_ty->lookup_field (field.get_field_name ().as_string (), + &field_type, &field_index); + rust_assert (ok); + rust_assert (translated != INVALID_PLACE); + coercion_site (translated, field_type->get_field_type ()); + init_values.push_back (translated); + } + +protected: + void visit (HIR::Lifetime &lifetime) override { rust_unreachable (); } + void visit (HIR::LifetimeParam &lifetime_param) override + { + rust_unreachable (); + } + void visit (HIR::PathInExpression &path) override { rust_unreachable (); } + void visit (HIR::TypePathSegment &segment) override { rust_unreachable (); } + void visit (HIR::TypePathSegmentGeneric &segment) override + { + rust_unreachable (); + } + void visit (HIR::TypePathSegmentFunction &segment) override + { + rust_unreachable (); + } + void visit (HIR::TypePath &path) override { rust_unreachable (); } + void visit (HIR::QualifiedPathInExpression &path) override + { + rust_unreachable (); + } + void visit (HIR::QualifiedPathInType &path) override { rust_unreachable (); } + void visit (HIR::LiteralExpr &expr) override { rust_unreachable (); } + void visit (HIR::BorrowExpr &expr) override { rust_unreachable (); } + void visit (HIR::DereferenceExpr &expr) override { rust_unreachable (); } + void visit (HIR::ErrorPropagationExpr &expr) override { rust_unreachable (); } + void visit (HIR::NegationExpr &expr) override { rust_unreachable (); } + void visit (HIR::ArithmeticOrLogicalExpr &expr) override + { + rust_unreachable (); + } + void visit (HIR::ComparisonExpr &expr) override { rust_unreachable (); } + void visit (HIR::LazyBooleanExpr &expr) override { rust_unreachable (); } + void visit (HIR::TypeCastExpr &expr) override { rust_unreachable (); } + void visit (HIR::AssignmentExpr &expr) override { rust_unreachable (); } + void visit (HIR::CompoundAssignmentExpr &expr) override + { + rust_unreachable (); + } + void visit (HIR::GroupedExpr &expr) override { rust_unreachable (); } + void visit (HIR::ArrayElemsValues &elems) override { rust_unreachable (); } + void visit (HIR::ArrayElemsCopied &elems) override { rust_unreachable (); } + void visit (HIR::ArrayExpr &expr) override { rust_unreachable (); } + void visit (HIR::ArrayIndexExpr &expr) override { rust_unreachable (); } + void visit (HIR::TupleExpr &expr) override { rust_unreachable (); } + void visit (HIR::TupleIndexExpr &expr) override { rust_unreachable (); } + void visit (HIR::StructExprStruct &expr) override { rust_unreachable (); } + void visit (HIR::StructExprStructFields &expr) override + { + rust_unreachable (); + } + void visit (HIR::StructExprStructBase &expr) override { rust_unreachable (); } + void visit (HIR::CallExpr &expr) override { rust_unreachable (); } + void visit (HIR::MethodCallExpr &expr) override { rust_unreachable (); } + void visit (HIR::FieldAccessExpr &expr) override { rust_unreachable (); } + void visit (HIR::BlockExpr &expr) override { rust_unreachable (); } + void visit (HIR::ClosureExpr &expr) override { rust_unreachable (); } + void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); } + void visit (HIR::BreakExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromToExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeToExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFullExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeFromToInclExpr &expr) override { rust_unreachable (); } + void visit (HIR::RangeToInclExpr &expr) override { rust_unreachable (); } + void visit (HIR::ReturnExpr &expr) override { rust_unreachable (); } + void visit (HIR::UnsafeBlockExpr &expr) override { rust_unreachable (); } + void visit (HIR::LoopExpr &expr) override { rust_unreachable (); } + void visit (HIR::WhileLoopExpr &expr) override { rust_unreachable (); } + void visit (HIR::WhileLetLoopExpr &expr) override { rust_unreachable (); } + void visit (HIR::IfExpr &expr) override { rust_unreachable (); } + void visit (HIR::IfExprConseqElse &expr) override { rust_unreachable (); } + void visit (HIR::IfLetExpr &expr) override { rust_unreachable (); } + void visit (HIR::IfLetExprConseqElse &expr) override { rust_unreachable (); } + void visit (HIR::MatchExpr &expr) override { rust_unreachable (); } + void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); } + void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); } + void visit (HIR::TypeParam ¶m) override { rust_unreachable (); } + void visit (HIR::ConstGenericParam ¶m) override { rust_unreachable (); } + void visit (HIR::LifetimeWhereClauseItem &item) override + { + rust_unreachable (); + } + void visit (HIR::TypeBoundWhereClauseItem &item) override + { + rust_unreachable (); + } + void visit (HIR::Module &module) override { rust_unreachable (); } + void visit (HIR::ExternCrate &crate) override { rust_unreachable (); } + void visit (HIR::UseTreeGlob &use_tree) override { rust_unreachable (); } + void visit (HIR::UseTreeList &use_tree) override { rust_unreachable (); } + void visit (HIR::UseTreeRebind &use_tree) override { rust_unreachable (); } + void visit (HIR::UseDeclaration &use_decl) override { rust_unreachable (); } + void visit (HIR::Function &function) override { rust_unreachable (); } + void visit (HIR::TypeAlias &type_alias) override { rust_unreachable (); } + void visit (HIR::StructStruct &struct_item) override { rust_unreachable (); } + void visit (HIR::TupleStruct &tuple_struct) override { rust_unreachable (); } + void visit (HIR::EnumItem &item) override { rust_unreachable (); } + void visit (HIR::EnumItemTuple &item) override { rust_unreachable (); } + void visit (HIR::EnumItemStruct &item) override { rust_unreachable (); } + void visit (HIR::EnumItemDiscriminant &item) override { rust_unreachable (); } + void visit (HIR::Enum &enum_item) override { rust_unreachable (); } + void visit (HIR::Union &union_item) override { rust_unreachable (); } + void visit (HIR::ConstantItem &const_item) override { rust_unreachable (); } + void visit (HIR::StaticItem &static_item) override { rust_unreachable (); } + void visit (HIR::TraitItemFunc &item) override { rust_unreachable (); } + void visit (HIR::TraitItemConst &item) override { rust_unreachable (); } + void visit (HIR::TraitItemType &item) override { rust_unreachable (); } + void visit (HIR::Trait &trait) override { rust_unreachable (); } + void visit (HIR::ImplBlock &impl) override { rust_unreachable (); } + void visit (HIR::ExternalStaticItem &item) override { rust_unreachable (); } + void visit (HIR::ExternalFunctionItem &item) override { rust_unreachable (); } + void visit (HIR::ExternBlock &block) override { rust_unreachable (); } + void visit (HIR::LiteralPattern &pattern) override { rust_unreachable (); } + void visit (HIR::IdentifierPattern &pattern) override { rust_unreachable (); } + void visit (HIR::WildcardPattern &pattern) override { rust_unreachable (); } + void visit (HIR::RangePatternBoundLiteral &bound) override + { + rust_unreachable (); + } + void visit (HIR::RangePatternBoundPath &bound) override + { + rust_unreachable (); + } + void visit (HIR::RangePatternBoundQualPath &bound) override + { + rust_unreachable (); + } + void visit (HIR::RangePattern &pattern) override { rust_unreachable (); } + void visit (HIR::ReferencePattern &pattern) override { rust_unreachable (); } + void visit (HIR::StructPatternFieldTuplePat &field) override + { + rust_unreachable (); + } + void visit (HIR::StructPatternFieldIdentPat &field) override + { + rust_unreachable (); + } + void visit (HIR::StructPatternFieldIdent &field) override + { + rust_unreachable (); + } + void visit (HIR::StructPattern &pattern) override { rust_unreachable (); } + void visit (HIR::TupleStructItemsNoRange &tuple_items) override + { + rust_unreachable (); + } + void visit (HIR::TupleStructItemsRange &tuple_items) override + { + rust_unreachable (); + } + void visit (HIR::TupleStructPattern &pattern) override + { + rust_unreachable (); + } + void visit (HIR::TuplePatternItemsMultiple &tuple_items) override + { + rust_unreachable (); + } + void visit (HIR::TuplePatternItemsRanged &tuple_items) override + { + rust_unreachable (); + } + void visit (HIR::TuplePattern &pattern) override { rust_unreachable (); } + void visit (HIR::SlicePattern &pattern) override { rust_unreachable (); } + void visit (HIR::AltPattern &pattern) override { rust_unreachable (); } + void visit (HIR::EmptyStmt &stmt) override { rust_unreachable (); } + void visit (HIR::LetStmt &stmt) override { rust_unreachable (); } + void visit (HIR::ExprStmt &stmt) override { rust_unreachable (); } + void visit (HIR::TraitBound &bound) override { rust_unreachable (); } + void visit (HIR::ImplTraitType &type) override { rust_unreachable (); } + void visit (HIR::TraitObjectType &type) override { rust_unreachable (); } + void visit (HIR::ParenthesisedType &type) override { rust_unreachable (); } + void visit (HIR::ImplTraitTypeOneBound &type) override + { + rust_unreachable (); + } + void visit (HIR::TupleType &type) override { rust_unreachable (); } + void visit (HIR::NeverType &type) override { rust_unreachable (); } + void visit (HIR::RawPointerType &type) override { rust_unreachable (); } + void visit (HIR::ReferenceType &type) override { rust_unreachable (); } + void visit (HIR::ArrayType &type) override { rust_unreachable (); } + void visit (HIR::SliceType &type) override { rust_unreachable (); } + void visit (HIR::InferredType &type) override { rust_unreachable (); } + void visit (HIR::BareFunctionType &type) override { rust_unreachable (); } +}; + +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_STRUCT_H diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h new file mode 100644 index 0000000..322d00d --- /dev/null +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h @@ -0,0 +1,88 @@ +// Copyright (C) 2020-2023 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_BIR_BUILDER_H +#define RUST_BIR_BUILDER_H + +#include "rust-bir-builder-internal.h" +#include "rust-hir-visitor.h" +#include "rust-bir-builder-pattern.h" +#include "rust-bir-builder-struct.h" +#include "rust-bir-builder-expr-stmt.h" + +namespace Rust { +namespace BIR { + +/** Top-level builder, which compiles a HIR function into a BIR function. */ +class Builder : public AbstractBuilder +{ +public: + explicit Builder (BuilderContext &ctx) : AbstractBuilder (ctx) {} + + Function build (HIR::Function &function) + { + PlaceId return_place + = ctx.place_db.add_temporary (lookup_type (*function.get_definition ())); + rust_assert (return_place == RETURN_VALUE_PLACE); + + for (auto ¶m : function.get_function_params ()) + { + handle_param (param); + } + + handle_body (*function.get_definition ()); + + return Function{std::move (ctx.place_db), std::move (ctx.arguments), + std::move (ctx.basic_blocks)}; + }; + +private: + void handle_param (HIR::FunctionParam ¶m) + { + auto &pattern = param.get_param_name (); + if (pattern->get_pattern_type () == HIR::Pattern::IDENTIFIER + && !static_cast<HIR::IdentifierPattern &> (*pattern).get_is_ref ()) + { + // Avoid useless temporary variable for parameter. + translated = declare_variable (pattern->get_mappings ()); + ctx.arguments.push_back (translated); + } + else + { + translated = ctx.place_db.add_temporary (lookup_type (*pattern)); + ctx.arguments.push_back (translated); + PatternBindingBuilder (ctx, translated, param.get_type ().get ()) + .go (*param.get_param_name ()); + } + } + + void handle_body (HIR::BlockExpr &body) + { + translated = ExprStmtBuilder (ctx).build (body); + if (body.has_expr ()) + { + push_assignment (RETURN_VALUE_PLACE, translated); + ctx.get_current_bb ().statements.emplace_back (Node::Kind::RETURN); + } + } +}; + +} // namespace BIR +} // namespace Rust + +#endif // RUST_BIR_BUILDER_H diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc index 44d33c5..4b97125 100644 --- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc +++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker.cc @@ -18,8 +18,7 @@ #include "rust-borrow-checker.h" #include "rust-function-collector.h" -#include "rust-bir.h" -#include "rust-bir-visitor.h" +#include "rust-bir-builder.h" namespace Rust { namespace HIR { @@ -30,8 +29,11 @@ BorrowChecker::go (HIR::Crate &crate) FunctionCollector collector; collector.go (crate); - for (auto func ATTRIBUTE_UNUSED : collector.get_functions ()) + for (auto func : collector.get_functions ()) { + BIR::BuilderContext ctx; + BIR::Builder builder (ctx); + builder.build (*func); } for (auto closure ATTRIBUTE_UNUSED : collector.get_closures ()) diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 1d95291..b1ecb8c 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -16,46 +16,48 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#include "rust-ast-dump.h" -#include "rust-ast-lower.h" +#include "rust-session-manager.h" +#include "rust-diagnostics.h" +#include "rust-unsafe-checker.h" +#include "rust-lex.h" +#include "rust-parse.h" +#include "rust-macro-expand.h" #include "rust-ast-resolve.h" -#include "rust-attribute-values.h" -#include "rust-attributes.h" -#include "rust-cfg-parser.h" -#include "rust-cfg-strip.h" -#include "rust-compile.h" +#include "rust-ast-lower.h" +#include "rust-hir-type-check.h" +#include "rust-privacy-check.h" #include "rust-const-checker.h" -#include "rust-diagnostics.h" -#include "rust-early-name-resolver-2.0.h" -#include "rust-early-name-resolver.h" -#include "rust-expand-visitor.h" -#include "rust-export-metadata.h" -#include "rust-extern-crate.h" #include "rust-feature-gate.h" -#include "rust-hir-dump.h" -#include "rust-hir-type-check.h" -#include "rust-imports.h" -#include "rust-lex.h" +#include "rust-compile.h" +#include "rust-cfg-parser.h" #include "rust-lint-scan-deadcode.h" #include "rust-lint-unused-var.h" -#include "rust-macro-expand.h" -#include "rust-name-resolution-context.h" -#include "rust-parse.h" -#include "rust-privacy-check.h" #include "rust-readonly-check.h" -#include "rust-session-manager.h" +#include "rust-hir-dump.h" +#include "rust-ast-dump.h" +#include "rust-export-metadata.h" +#include "rust-imports.h" +#include "rust-extern-crate.h" +#include "rust-attributes.h" +#include "rust-early-name-resolver.h" +#include "rust-name-resolution-context.h" +#include "rust-early-name-resolver-2.0.h" +#include "rust-cfg-strip.h" +#include "rust-expand-visitor.h" #include "rust-unicode.h" -#include "rust-unsafe-checker.h" +#include "rust-attribute-values.h" +#include "rust-borrow-checker.h" #include "input.h" -#include "rust-borrow-checker.h" -#include "rust-target.h" #include "selftest.h" #include "tm.h" +#include "rust-target.h" -extern bool saw_errors(void); +extern bool +saw_errors (void); -extern Linemap *rust_get_linemap(); +extern Linemap * +rust_get_linemap (); namespace Rust { @@ -72,63 +74,75 @@ const char *kTargetOptionsDumpFile = "gccrs.target-options.dump"; const std::string kDefaultCrateName = "rust_out"; const size_t kMaxNameLength = 64; -Session &Session::get_instance() { +Session & +Session::get_instance () +{ static Session instance; return instance; } -static std::string infer_crate_name(const std::string &filename) { +static std::string +infer_crate_name (const std::string &filename) +{ if (filename == "-") return kDefaultCrateName; - std::string crate = std::string(filename); - size_t path_sep = crate.find_last_of(file_separator); + std::string crate = std::string (filename); + size_t path_sep = crate.find_last_of (file_separator); // find the base filename if (path_sep != std::string::npos) - crate.erase(0, path_sep + 1); + crate.erase (0, path_sep + 1); // find the file stem name (remove file extension) - size_t ext_position = crate.find_last_of('.'); + size_t ext_position = crate.find_last_of ('.'); if (ext_position != std::string::npos) - crate.erase(ext_position); + crate.erase (ext_position); // Replace all the '-' symbols with '_' per Rust rules - for (auto &c : crate) { - if (c == '-') - c = '_'; - } + for (auto &c : crate) + { + if (c == '-') + c = '_'; + } return crate; } /* Validate the crate name using the ASCII rules */ -static bool validate_crate_name(const std::string &crate_name, Error &error) { - tl::optional<Utf8String> utf8_name_opt = - Utf8String::make_utf8_string(crate_name); - if (!utf8_name_opt.has_value()) { - error = Error(UNDEF_LOCATION, "crate name is not a valid UTF-8 string"); - return false; - } +static bool +validate_crate_name (const std::string &crate_name, Error &error) +{ + tl::optional<Utf8String> utf8_name_opt + = Utf8String::make_utf8_string (crate_name); + if (!utf8_name_opt.has_value ()) + { + error = Error (UNDEF_LOCATION, "crate name is not a valid UTF-8 string"); + return false; + } - std::vector<Codepoint> uchars = utf8_name_opt->get_chars(); - if (uchars.empty()) { - error = Error(UNDEF_LOCATION, "crate name cannot be empty"); - return false; - } - if (uchars.size() > kMaxNameLength) { - error = Error(UNDEF_LOCATION, "crate name cannot exceed %lu characters", - (unsigned long)kMaxNameLength); - return false; - } - for (Codepoint &c : uchars) { - if (!(is_alphabetic(c.value) || is_numeric(c.value) || c.value == '_')) { - error = Error(UNDEF_LOCATION, - "invalid character %<%s%> in crate name: %<%s%>", - c.as_string().c_str(), crate_name.c_str()); + std::vector<Codepoint> uchars = utf8_name_opt->get_chars (); + if (uchars.empty ()) + { + error = Error (UNDEF_LOCATION, "crate name cannot be empty"); + return false; + } + if (uchars.size () > kMaxNameLength) + { + error = Error (UNDEF_LOCATION, "crate name cannot exceed %lu characters", + (unsigned long) kMaxNameLength); return false; } - } + for (Codepoint &c : uchars) + { + if (!(is_alphabetic (c.value) || is_numeric (c.value) || c.value == '_')) + { + error = Error (UNDEF_LOCATION, + "invalid character %<%s%> in crate name: %<%s%>", + c.as_string ().c_str (), crate_name.c_str ()); + return false; + } + } return true; } @@ -139,333 +153,396 @@ Session::init () targetrustm.rust_cpu_info (); targetrustm.rust_os_info (); - options.target_data.insert_key_value_pair("target_pointer_width", - std::to_string(POINTER_SIZE)); - options.target_data.insert_key_value_pair( - "target_endian", BYTES_BIG_ENDIAN ? "big" : "little"); + // target-independent values that should exist in all targets + options.target_data.insert_key_value_pair ("target_pointer_width", + std::to_string (POINTER_SIZE)); + options.target_data.insert_key_value_pair ("target_endian", BYTES_BIG_ENDIAN + ? "big" + : "little"); // setup singleton linemap - linemap = rust_get_linemap(); + linemap = rust_get_linemap (); // setup backend to GCC GIMPLE - Backend::init(); + Backend::init (); // setup mappings class - mappings = Analysis::Mappings::get(); + mappings = Analysis::Mappings::get (); } /* Initialise default options. Actually called before handle_option, unlike init * itself. */ -void Session::init_options() {} +void +Session::init_options () +{} // Handle option selection. -bool Session::handle_option( - enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED, - int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED, - const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) { +bool +Session::handle_option ( + enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED, + int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED, + const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) +{ // used to store whether results of various stuff are successful bool ret = true; // Handles options as listed in lang.opt. - switch (code) { - case OPT_I: - case OPT_L: { - // TODO: add search path - const std::string p = std::string(arg); - add_search_path(p); - } break; - - case OPT_frust_extern_: { - std::string input(arg); - ret = handle_extern_option(input); - } break; - case OPT_frust_crate_: - // set the crate name - if (arg != nullptr) { - auto error = Error(UNDEF_LOCATION, std::string()); - if ((ret = validate_crate_name(arg, error))) { - options.set_crate_name(arg); - options.crate_name_set_manually = true; - } else { - rust_assert(!error.message.empty()); - error.emit(); + switch (code) + { + case OPT_I: + case OPT_L: { + // TODO: add search path + const std::string p = std::string (arg); + add_search_path (p); + } + break; + + case OPT_frust_extern_: { + std::string input (arg); + ret = handle_extern_option (input); + } + break; + case OPT_frust_crate_: + // set the crate name + if (arg != nullptr) + { + auto error = Error (UNDEF_LOCATION, std::string ()); + if ((ret = validate_crate_name (arg, error))) + { + options.set_crate_name (arg); + options.crate_name_set_manually = true; + } + else + { + rust_assert (!error.message.empty ()); + error.emit (); + } + } + else + ret = false; + break; + + case OPT_frust_dump_: + // enable dump and return whether this was successful + if (arg != nullptr) + { + ret = enable_dump (std::string (arg)); + } + else + { + ret = false; + } + break; + + case OPT_frust_mangling_: + Compile::Mangler::set_mangling (flag_rust_mangling); + break; + + case OPT_frust_cfg_: { + auto string_arg = std::string (arg); + ret = handle_cfg_option (string_arg); + break; } - } else - ret = false; - break; - - case OPT_frust_dump_: - // enable dump and return whether this was successful - if (arg != nullptr) { - ret = enable_dump(std::string(arg)); - } else { - ret = false; + case OPT_frust_crate_type_: + options.set_crate_type (flag_rust_crate_type); + break; + case OPT_frust_edition_: + options.set_edition (flag_rust_edition); + break; + case OPT_frust_compile_until_: + options.set_compile_step (flag_rust_compile_until); + break; + case OPT_frust_metadata_output_: + options.set_metadata_output (arg); + break; + + default: + break; } - break; - - case OPT_frust_mangling_: - Compile::Mangler::set_mangling(flag_rust_mangling); - break; - - case OPT_frust_cfg_: { - auto string_arg = std::string(arg); - ret = handle_cfg_option(string_arg); - break; - } - case OPT_frust_crate_type_: - options.set_crate_type(flag_rust_crate_type); - break; - case OPT_frust_edition_: - options.set_edition(flag_rust_edition); - break; - case OPT_frust_compile_until_: - options.set_compile_step(flag_rust_compile_until); - break; - case OPT_frust_metadata_output_: - options.set_metadata_output(arg); - break; - - default: - break; - } return ret; } -bool Session::handle_extern_option(std::string &input) { - auto pos = input.find('='); +bool +Session::handle_extern_option (std::string &input) +{ + auto pos = input.find ('='); if (std::string::npos == pos) return false; - std::string libname = input.substr(0, pos); - std::string path = input.substr(pos + 1); + std::string libname = input.substr (0, pos); + std::string path = input.substr (pos + 1); - extern_crates.insert({libname, path}); + extern_crates.insert ({libname, path}); return true; } -bool Session::handle_cfg_option(std::string &input) { +bool +Session::handle_cfg_option (std::string &input) +{ std::string key; std::string value; // Refactor this if needed - if (!parse_cfg_option(input, key, value)) { - rust_error_at( - UNDEF_LOCATION, - "invalid argument to %<-frust-cfg%>: Accepted formats are " - "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)"); - return false; - } + if (!parse_cfg_option (input, key, value)) + { + rust_error_at ( + UNDEF_LOCATION, + "invalid argument to %<-frust-cfg%>: Accepted formats are " + "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)"); + return false; + } - if (value.empty()) + if (value.empty ()) // rustc does not seem to error on dup key - options.target_data.insert_key(key); + options.target_data.insert_key (key); else - options.target_data.insert_key_value_pair(key, value); + options.target_data.insert_key_value_pair (key, value); return true; } /* Enables a certain dump depending on the name passed in. Returns true if * name is valid, false otherwise. */ -bool Session::enable_dump(std::string arg) { - if (arg.empty()) { - rust_error_at( - UNDEF_LOCATION, - "dump option was not given a name. choose %<lex%>, %<ast-pretty%>, " - "%<register_plugins%>, %<injection%>, " - "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, " - "%<hir-pretty%>, %<bir%> or %<all%>"); - return false; - } - - if (arg == "all") { - options.enable_all_dump_options(); - } else if (arg == "lex") { - options.enable_dump_option(CompileOptions::LEXER_DUMP); - } else if (arg == "ast-pretty") { - options.enable_dump_option(CompileOptions::AST_DUMP_PRETTY); - } else if (arg == "register_plugins") { - options.enable_dump_option(CompileOptions::REGISTER_PLUGINS_DUMP); - } else if (arg == "injection") { - options.enable_dump_option(CompileOptions::INJECTION_DUMP); - } else if (arg == "expansion") { - options.enable_dump_option(CompileOptions::EXPANSION_DUMP); - } else if (arg == "resolution") { - options.enable_dump_option(CompileOptions::RESOLUTION_DUMP); - } else if (arg == "target_options") { - options.enable_dump_option(CompileOptions::TARGET_OPTION_DUMP); - } else if (arg == "hir") { - options.enable_dump_option(CompileOptions::HIR_DUMP); - } else if (arg == "hir-pretty") { - options.enable_dump_option(CompileOptions::HIR_DUMP_PRETTY); - } else if (arg == "bir") { - options.enable_dump_option(CompileOptions::BIR_DUMP); - } else { - rust_error_at( - UNDEF_LOCATION, - "dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, " - "%<register_plugins%>, %<injection%>, " - "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, " - "%<hir-pretty%>, or %<all%>", - arg.c_str()); - return false; - } +bool +Session::enable_dump (std::string arg) +{ + if (arg.empty ()) + { + rust_error_at ( + UNDEF_LOCATION, + "dump option was not given a name. choose %<lex%>, %<ast-pretty%>, " + "%<register_plugins%>, %<injection%>, " + "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, " + "%<hir-pretty%>, %<bir%> or %<all%>"); + return false; + } + + if (arg == "all") + { + options.enable_all_dump_options (); + } + else if (arg == "lex") + { + options.enable_dump_option (CompileOptions::LEXER_DUMP); + } + else if (arg == "ast-pretty") + { + options.enable_dump_option (CompileOptions::AST_DUMP_PRETTY); + } + else if (arg == "register_plugins") + { + options.enable_dump_option (CompileOptions::REGISTER_PLUGINS_DUMP); + } + else if (arg == "injection") + { + options.enable_dump_option (CompileOptions::INJECTION_DUMP); + } + else if (arg == "expansion") + { + options.enable_dump_option (CompileOptions::EXPANSION_DUMP); + } + else if (arg == "resolution") + { + options.enable_dump_option (CompileOptions::RESOLUTION_DUMP); + } + else if (arg == "target_options") + { + options.enable_dump_option (CompileOptions::TARGET_OPTION_DUMP); + } + else if (arg == "hir") + { + options.enable_dump_option (CompileOptions::HIR_DUMP); + } + else if (arg == "hir-pretty") + { + options.enable_dump_option (CompileOptions::HIR_DUMP_PRETTY); + } + else if (arg == "bir") + { + options.enable_dump_option (CompileOptions::BIR_DUMP); + } + else + { + rust_error_at ( + UNDEF_LOCATION, + "dump option %qs was unrecognised. choose %<lex%>, %<ast-pretty%>, " + "%<register_plugins%>, %<injection%>, " + "%<expansion%>, %<resolution%>, %<target_options%>, %<hir%>, " + "%<hir-pretty%>, or %<all%>", + arg.c_str ()); + return false; + } return true; } /* Actual main entry point for front-end. Called from langhook to parse files. */ -void Session::handle_input_files(int num_files, const char **files) { +void +Session::handle_input_files (int num_files, const char **files) +{ if (num_files != 1) - rust_fatal_error(UNDEF_LOCATION, - "only one file may be specified on the command line"); + rust_fatal_error (UNDEF_LOCATION, + "only one file may be specified on the command line"); const auto &file = files[0]; - if (options.crate_name.empty()) { - auto filename = "-"; - if (num_files > 0) - filename = files[0]; - - auto crate_name = infer_crate_name(filename); - rust_debug("inferred crate name: %s", crate_name.c_str()); - // set the preliminary crate name here - // we will figure out the real crate name in `handle_crate_name` - options.set_crate_name(crate_name); - } + if (options.crate_name.empty ()) + { + auto filename = "-"; + if (num_files > 0) + filename = files[0]; + + auto crate_name = infer_crate_name (filename); + rust_debug ("inferred crate name: %s", crate_name.c_str ()); + // set the preliminary crate name here + // we will figure out the real crate name in `handle_crate_name` + options.set_crate_name (crate_name); + } - CrateNum crate_num = mappings->get_next_crate_num(options.get_crate_name()); - mappings->set_current_crate(crate_num); + CrateNum crate_num = mappings->get_next_crate_num (options.get_crate_name ()); + mappings->set_current_crate (crate_num); - rust_debug("Attempting to parse file: %s", file); - compile_crate(file); + rust_debug ("Attempting to parse file: %s", file); + compile_crate (file); } -void Session::handle_crate_name(const AST::Crate &parsed_crate) { - auto mappings = Analysis::Mappings::get(); +void +Session::handle_crate_name (const AST::Crate &parsed_crate) +{ + auto mappings = Analysis::Mappings::get (); auto crate_name_changed = false; - auto error = Error(UNDEF_LOCATION, std::string()); - - for (const auto &attr : parsed_crate.inner_attrs) { - if (attr.get_path() != "crate_name") - continue; - if (!attr.has_attr_input()) { - rust_error_at(attr.get_locus(), "%<crate_name%> accepts one argument"); - continue; - } - - auto &literal = static_cast<AST::AttrInputLiteral &>(attr.get_attr_input()); - const auto &msg_str = literal.get_literal().as_string(); - if (!validate_crate_name(msg_str, error)) { - error.locus = attr.get_locus(); - error.emit(); - continue; - } - - auto options = Session::get_instance().options; - if (options.crate_name_set_manually && (options.crate_name != msg_str)) { - rust_error_at(attr.get_locus(), - "%<-frust-crate-name%> and %<#[crate_name]%> are " - "required to match, but %qs does not match %qs", - options.crate_name.c_str(), msg_str.c_str()); + auto error = Error (UNDEF_LOCATION, std::string ()); + + for (const auto &attr : parsed_crate.inner_attrs) + { + if (attr.get_path () != "crate_name") + continue; + if (!attr.has_attr_input ()) + { + rust_error_at (attr.get_locus (), + "%<crate_name%> accepts one argument"); + continue; + } + + auto &literal + = static_cast<AST::AttrInputLiteral &> (attr.get_attr_input ()); + const auto &msg_str = literal.get_literal ().as_string (); + if (!validate_crate_name (msg_str, error)) + { + error.locus = attr.get_locus (); + error.emit (); + continue; + } + + auto options = Session::get_instance ().options; + if (options.crate_name_set_manually && (options.crate_name != msg_str)) + { + rust_error_at (attr.get_locus (), + "%<-frust-crate-name%> and %<#[crate_name]%> are " + "required to match, but %qs does not match %qs", + options.crate_name.c_str (), msg_str.c_str ()); + } + crate_name_changed = true; + options.set_crate_name (msg_str); + mappings->set_crate_name (mappings->get_current_crate (), msg_str); } - crate_name_changed = true; - options.set_crate_name(msg_str); - mappings->set_crate_name(mappings->get_current_crate(), msg_str); - } options.crate_name_set_manually |= crate_name_changed; - if (!options.crate_name_set_manually && - !validate_crate_name(options.crate_name, error)) { - error.emit(); - rust_inform(linemap_position_for_column(line_table, 0), - "crate name inferred from this file"); - } + if (!options.crate_name_set_manually + && !validate_crate_name (options.crate_name, error)) + { + error.emit (); + rust_inform (linemap_position_for_column (line_table, 0), + "crate name inferred from this file"); + } } // Parses a single file with filename filename. -void Session::compile_crate(const char *filename) { - if (!flag_rust_experimental && - !std::getenv("GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE")) - rust_fatal_error( - UNDEF_LOCATION, "%s", - "gccrs is not yet able to compile Rust code " - "properly. Most of the errors produced will be gccrs' fault and not " - "the " - "crate you are trying to compile. Because of this, please reports " - "issues " - "to us directly instead of opening issues on said crate's " - "repository.\n\nOur github repository: " - "https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: " - "https://gcc.gnu.org/bugzilla/" - "buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n" - "If you understand this, and understand that the binaries produced " - "might " - "not behave accordingly, you may attempt to use gccrs in an " - "experimental " - "manner by passing the following flag:\n\n" - "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by " - "defining the following environment variable (any value will " - "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor " - "cargo-gccrs, this means passing\n\n" - "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-" - "use\"\n\nas an environment variable."); - - RAIIFile file_wrap(filename); - if (!file_wrap.ok()) { - rust_error_at(UNDEF_LOCATION, "cannot open filename %s: %m", filename); - return; - } +void +Session::compile_crate (const char *filename) +{ + if (!flag_rust_experimental + && !std::getenv ("GCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE")) + rust_fatal_error ( + UNDEF_LOCATION, "%s", + "gccrs is not yet able to compile Rust code " + "properly. Most of the errors produced will be gccrs' fault and not the " + "crate you are trying to compile. Because of this, please reports issues " + "to us directly instead of opening issues on said crate's " + "repository.\n\nOur github repository: " + "https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: " + "https://gcc.gnu.org/bugzilla/" + "buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n" + "If you understand this, and understand that the binaries produced might " + "not behave accordingly, you may attempt to use gccrs in an experimental " + "manner by passing the following flag:\n\n" + "`-frust-incomplete-and-experimental-compiler-do-not-use`\n\nor by " + "defining the following environment variable (any value will " + "do)\n\nGCCRS_INCOMPLETE_AND_EXPERIMENTAL_COMPILER_DO_NOT_USE\n\nFor " + "cargo-gccrs, this means passing\n\n" + "GCCRS_EXTRA_ARGS=\"-frust-incomplete-and-experimental-compiler-do-not-" + "use\"\n\nas an environment variable."); + + RAIIFile file_wrap (filename); + if (!file_wrap.ok ()) + { + rust_error_at (UNDEF_LOCATION, "cannot open filename %s: %m", filename); + return; + } - auto last_step = options.get_compile_until(); + auto last_step = options.get_compile_until (); // parse file here /* create lexer and parser - these are file-specific and so aren't instance * variables */ tl::optional<std::ofstream &> dump_lex_opt = tl::nullopt; std::ofstream dump_lex_stream; - if (options.dump_option_enabled(CompileOptions::LEXER_DUMP)) { - dump_lex_stream.open(kLexDumpFile); - if (dump_lex_stream.fail()) - rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", - kLexDumpFile); - - dump_lex_opt = dump_lex_stream; - } + if (options.dump_option_enabled (CompileOptions::LEXER_DUMP)) + { + dump_lex_stream.open (kLexDumpFile); + if (dump_lex_stream.fail ()) + rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored", + kLexDumpFile); + + dump_lex_opt = dump_lex_stream; + } - Lexer lex(filename, std::move(file_wrap), linemap, dump_lex_opt); + Lexer lex (filename, std::move (file_wrap), linemap, dump_lex_opt); - if (!lex.input_source_is_valid_utf8()) { - rust_error_at(UNKNOWN_LOCATION, - "cannot read %s; stream did not contain valid UTF-8", - filename); - return; - } + if (!lex.input_source_is_valid_utf8 ()) + { + rust_error_at (UNKNOWN_LOCATION, + "cannot read %s; stream did not contain valid UTF-8", + filename); + return; + } - Parser<Lexer> parser(lex); + Parser<Lexer> parser (lex); // generate crate from parser - std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate(); + std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate (); // handle crate name - handle_crate_name(*ast_crate.get()); + handle_crate_name (*ast_crate.get ()); // dump options except lexer dump - if (options.dump_option_enabled(CompileOptions::AST_DUMP_PRETTY)) { - dump_ast_pretty(*ast_crate.get()); - } - if (options.dump_option_enabled(CompileOptions::TARGET_OPTION_DUMP)) { - options.target_data.dump_target_options(); - } - - if (saw_errors()) + if (options.dump_option_enabled (CompileOptions::AST_DUMP_PRETTY)) + { + dump_ast_pretty (*ast_crate.get ()); + } + if (options.dump_option_enabled (CompileOptions::TARGET_OPTION_DUMP)) + { + options.target_data.dump_target_options (); + } + + if (saw_errors ()) return; // setup the mappings for this AST - CrateNum current_crate = mappings->get_current_crate(); - AST::Crate &parsed_crate = - mappings->insert_ast_crate(std::move(ast_crate), current_crate); + CrateNum current_crate = mappings->get_current_crate (); + AST::Crate &parsed_crate + = mappings->insert_ast_crate (std::move (ast_crate), current_crate); /* basic pipeline: * - lex @@ -481,7 +558,7 @@ void Session::compile_crate(const char *filename) { * maybe buffered lints) * TODO not done */ - rust_debug("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m"); + rust_debug ("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m"); // If -fsyntax-only was passed, we can just skip the remaining passes. // Parsing errors are already emitted in `parse_crate()` @@ -489,107 +566,115 @@ void Session::compile_crate(const char *filename) { return; // register plugins pipeline stage - register_plugins(parsed_crate); - rust_debug("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m"); - if (options.dump_option_enabled(CompileOptions::REGISTER_PLUGINS_DUMP)) { - // TODO: what do I dump here? - } + register_plugins (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m"); + if (options.dump_option_enabled (CompileOptions::REGISTER_PLUGINS_DUMP)) + { + // TODO: what do I dump here? + } // injection pipeline stage - injection(parsed_crate); - rust_debug("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m"); - if (options.dump_option_enabled(CompileOptions::INJECTION_DUMP)) { - // TODO: what do I dump here? injected crate names? - } + injection (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m"); + if (options.dump_option_enabled (CompileOptions::INJECTION_DUMP)) + { + // TODO: what do I dump here? injected crate names? + } if (last_step == CompileOptions::CompileStep::AttributeCheck) return; - Analysis::AttributeChecker().go(parsed_crate); + Analysis::AttributeChecker ().go (parsed_crate); if (last_step == CompileOptions::CompileStep::Expansion) return; // expansion pipeline stage - expansion(parsed_crate); - rust_debug("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); - if (options.dump_option_enabled(CompileOptions::EXPANSION_DUMP)) { - // dump AST with expanded stuff - rust_debug("BEGIN POST-EXPANSION AST DUMP"); - dump_ast_pretty(parsed_crate, true); - rust_debug("END POST-EXPANSION AST DUMP"); - } + expansion (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); + if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) + { + // dump AST with expanded stuff + rust_debug ("BEGIN POST-EXPANSION AST DUMP"); + dump_ast_pretty (parsed_crate, true); + rust_debug ("END POST-EXPANSION AST DUMP"); + } // feature gating - FeatureGate().check(parsed_crate); + FeatureGate ().check (parsed_crate); if (last_step == CompileOptions::CompileStep::NameResolution) return; // resolution pipeline stage - Resolver::NameResolution::Resolve(parsed_crate); + Resolver::NameResolution::Resolve (parsed_crate); - if (options.dump_option_enabled(CompileOptions::RESOLUTION_DUMP)) { - // TODO: what do I dump here? resolved names? AST with resolved names? - } + if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP)) + { + // TODO: what do I dump here? resolved names? AST with resolved names? + } - if (saw_errors()) + if (saw_errors ()) return; if (last_step == CompileOptions::CompileStep::Lowering) return; // lower AST to HIR - std::unique_ptr<HIR::Crate> lowered = HIR::ASTLowering::Resolve(parsed_crate); - if (saw_errors()) + std::unique_ptr<HIR::Crate> lowered + = HIR::ASTLowering::Resolve (parsed_crate); + if (saw_errors ()) return; // add the mappings to it - HIR::Crate &hir = mappings->insert_hir_crate(std::move(lowered)); - if (options.dump_option_enabled(CompileOptions::HIR_DUMP)) { - dump_hir(hir); - } - if (options.dump_option_enabled(CompileOptions::HIR_DUMP_PRETTY)) { - dump_hir_pretty(hir); - } + HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered)); + if (options.dump_option_enabled (CompileOptions::HIR_DUMP)) + { + dump_hir (hir); + } + if (options.dump_option_enabled (CompileOptions::HIR_DUMP_PRETTY)) + { + dump_hir_pretty (hir); + } if (last_step == CompileOptions::CompileStep::TypeCheck) return; // type resolve - Resolver::TypeResolution::Resolve(hir); + Resolver::TypeResolution::Resolve (hir); - if (saw_errors()) + if (saw_errors ()) return; if (last_step == CompileOptions::CompileStep::Privacy) return; // Various HIR error passes. The privacy pass happens before the unsafe checks - Privacy::Resolver::resolve(hir); - if (saw_errors()) + Privacy::Resolver::resolve (hir); + if (saw_errors ()) return; if (last_step == CompileOptions::CompileStep::Unsafety) return; - HIR::UnsafeChecker().go(hir); + HIR::UnsafeChecker ().go (hir); if (last_step == CompileOptions::CompileStep::Const) return; - HIR::ConstChecker().go(hir); + HIR::ConstChecker ().go (hir); if (last_step == CompileOptions::CompileStep::BorrowCheck) return; - if (flag_borrowcheck) { - const bool dump_bir = - options.dump_option_enabled(CompileOptions::DumpOption::BIR_DUMP); - HIR::BorrowChecker(dump_bir).go(hir); - } + if (flag_borrowcheck) + { + const bool dump_bir + = options.dump_option_enabled (CompileOptions::DumpOption::BIR_DUMP); + HIR::BorrowChecker (dump_bir).go (hir); + } - if (saw_errors()) + if (saw_errors ()) return; if (last_step == CompileOptions::CompileStep::Compilation) @@ -597,49 +682,61 @@ void Session::compile_crate(const char *filename) { // do compile to gcc generic Compile::Context ctx; - Compile::CompileCrate::Compile(hir, &ctx); + Compile::CompileCrate::Compile (hir, &ctx); // we can't do static analysis if there are errors to worry about - if (!saw_errors()) { - // lints - Analysis::ScanDeadcode::Scan(hir); - Analysis::UnusedVariables::Lint(ctx); - Analysis::ReadonlyCheck::Lint(ctx); - - // metadata - bool specified_emit_metadata = - flag_rust_embed_metadata || options.metadata_output_path_set(); - if (!specified_emit_metadata) { - Metadata::PublicInterface::ExportTo( - hir, Metadata::PublicInterface::expected_metadata_filename()); - } else { - if (flag_rust_embed_metadata) - Metadata::PublicInterface::Export(hir); - if (options.metadata_output_path_set()) - Metadata::PublicInterface::ExportTo(hir, options.get_metadata_output()); + if (!saw_errors ()) + { + // lints + Analysis::ScanDeadcode::Scan (hir); + Analysis::UnusedVariables::Lint (ctx); + Analysis::ReadonlyCheck::Lint (ctx); + + // metadata + bool specified_emit_metadata + = flag_rust_embed_metadata || options.metadata_output_path_set (); + if (!specified_emit_metadata) + { + Metadata::PublicInterface::ExportTo ( + hir, Metadata::PublicInterface::expected_metadata_filename ()); + } + else + { + if (flag_rust_embed_metadata) + Metadata::PublicInterface::Export (hir); + if (options.metadata_output_path_set ()) + Metadata::PublicInterface::ExportTo ( + hir, options.get_metadata_output ()); + } } - } // pass to GCC middle-end - ctx.write_to_backend(); + ctx.write_to_backend (); } -void Session::register_plugins(AST::Crate &crate ATTRIBUTE_UNUSED) { - rust_debug("ran register_plugins (with no body)"); +void +Session::register_plugins (AST::Crate &crate ATTRIBUTE_UNUSED) +{ + rust_debug ("ran register_plugins (with no body)"); } // TODO: move somewhere else -bool contains_name(const AST::AttrVec &attrs, std::string name) { - for (const auto &attr : attrs) { - if (attr.get_path() == name) - return true; - } +bool +contains_name (const AST::AttrVec &attrs, std::string name) +{ + for (const auto &attr : attrs) + { + if (attr.get_path () == name) + return true; + } return false; } -void Session::injection(AST::Crate &crate) { - rust_debug("started injection"); +void +Session::injection (AST::Crate &crate) +{ + rust_debug ("started injection"); // lint checks in future maybe? @@ -694,40 +791,47 @@ void Session::injection(AST::Crate &crate) { // crate injection std::vector<std::string> names; - if (contains_name(crate.inner_attrs, "no_core")) { - // no prelude - injected_crate_name = ""; - } else if (contains_name(crate.inner_attrs, "no_std")) { - names.push_back("core"); - - if (!contains_name(crate.inner_attrs, "compiler_builtins")) { - names.push_back("compiler_builtins"); + if (contains_name (crate.inner_attrs, "no_core")) + { + // no prelude + injected_crate_name = ""; } + else if (contains_name (crate.inner_attrs, "no_std")) + { + names.push_back ("core"); + + if (!contains_name (crate.inner_attrs, "compiler_builtins")) + { + names.push_back ("compiler_builtins"); + } - injected_crate_name = "core"; - } else { - names.push_back("std"); + injected_crate_name = "core"; + } + else + { + names.push_back ("std"); - injected_crate_name = "std"; - } + injected_crate_name = "std"; + } // reverse iterate through names to insert crate items in "forward" order at // beginning of crate - for (auto it = names.rbegin(); it != names.rend(); ++it) { - // create "macro use" attribute for use on extern crate item to enable - // loading macros from it - AST::Attribute attr(AST::SimplePath::from_str(Values::Attributes::MACRO_USE, - UNDEF_LOCATION), - nullptr); - - // create "extern crate" item with the name - std::unique_ptr<AST::ExternCrate> extern_crate( - new AST::ExternCrate(*it, AST::Visibility::create_error(), - {std::move(attr)}, UNKNOWN_LOCATION)); - - // insert at beginning - // crate.items.insert (crate.items.begin (), std::move (extern_crate)); - } + for (auto it = names.rbegin (); it != names.rend (); ++it) + { + // create "macro use" attribute for use on extern crate item to enable + // loading macros from it + AST::Attribute attr (AST::SimplePath::from_str ( + Values::Attributes::MACRO_USE, UNDEF_LOCATION), + nullptr); + + // create "extern crate" item with the name + std::unique_ptr<AST::ExternCrate> extern_crate ( + new AST::ExternCrate (*it, AST::Visibility::create_error (), + {std::move (attr)}, UNKNOWN_LOCATION)); + + // insert at beginning + // crate.items.insert (crate.items.begin (), std::move (extern_crate)); + } // create use tree path // prelude is injected_crate_name @@ -761,11 +865,13 @@ void Session::injection(AST::Crate &crate) { // this crate type will have options affecting the metadata ouput - rust_debug("finished injection"); + rust_debug ("finished injection"); } -void Session::expansion(AST::Crate &crate) { - rust_debug("started expansion"); +void +Session::expansion (AST::Crate &crate) +{ + rust_debug ("started expansion"); /* rustc has a modification to windows PATH temporarily here, which may end * up being required */ @@ -780,49 +886,53 @@ void Session::expansion(AST::Crate &crate) { // create extctxt? from parse session, cfg, and resolver? /* expand by calling cxtctxt object's monotonic_expander's expand_crate * method. */ - MacroExpander expander(crate, cfg, *this); + MacroExpander expander (crate, cfg, *this); std::vector<Error> macro_errors; - while (!fixed_point_reached && iterations < cfg.recursion_limit) { - CfgStrip().go(crate); - // Errors might happen during cfg strip pass - if (saw_errors()) - break; - - auto ctx = Resolver2_0::NameResolutionContext(); - - if (flag_name_resolution_2_0) { - Resolver2_0::Early early(ctx); - early.go(crate); - macro_errors = early.get_macro_resolve_errors(); - } else - Resolver::EarlyNameResolver().go(crate); + while (!fixed_point_reached && iterations < cfg.recursion_limit) + { + CfgStrip ().go (crate); + // Errors might happen during cfg strip pass + if (saw_errors ()) + break; + + auto ctx = Resolver2_0::NameResolutionContext (); + + if (flag_name_resolution_2_0) + { + Resolver2_0::Early early (ctx); + early.go (crate); + macro_errors = early.get_macro_resolve_errors (); + } + else + Resolver::EarlyNameResolver ().go (crate); - ExpandVisitor(expander).go(crate); + ExpandVisitor (expander).go (crate); - fixed_point_reached = !expander.has_changed(); - expander.reset_changed_state(); - iterations++; + fixed_point_reached = !expander.has_changed (); + expander.reset_changed_state (); + iterations++; - if (saw_errors()) - break; - } + if (saw_errors ()) + break; + } // Fixed point reached: Emit unresolved macros error for (auto &error : macro_errors) - error.emit(); + error.emit (); - if (iterations == cfg.recursion_limit) { - auto &last_invoc = expander.get_last_invocation(); - auto &last_def = expander.get_last_definition(); + if (iterations == cfg.recursion_limit) + { + auto &last_invoc = expander.get_last_invocation (); + auto &last_def = expander.get_last_definition (); - rust_assert(last_def.has_value() && last_invoc.has_value()); + rust_assert (last_def.has_value () && last_invoc.has_value ()); - rich_location range(line_table, last_invoc->get_locus()); - range.add_range(last_def->get_locus()); + rich_location range (line_table, last_invoc->get_locus ()); + range.add_range (last_def->get_locus ()); - rust_error_at(range, "reached recursion limit"); - } + rust_error_at (range, "reached recursion limit"); + } // error reporting - check unused macros, get missing fragment specifiers @@ -832,254 +942,288 @@ void Session::expansion(AST::Crate &crate) { // maybe create macro crate if not rustdoc - rust_debug("finished expansion"); + rust_debug ("finished expansion"); } -void Session::dump_ast_pretty(AST::Crate &crate, bool expanded) const { +void +Session::dump_ast_pretty (AST::Crate &crate, bool expanded) const +{ std::ofstream out; if (expanded) - out.open(kASTPrettyDumpFileExpanded); + out.open (kASTPrettyDumpFileExpanded); else - out.open(kASTPrettyDumpFile); + out.open (kASTPrettyDumpFile); - if (out.fail()) { - rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", kASTDumpFile); - return; - } + if (out.fail ()) + { + rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored", + kASTDumpFile); + return; + } - AST::Dump(out).go(crate); + AST::Dump (out).go (crate); - out.close(); + out.close (); } -void Session::dump_hir(HIR::Crate &crate) const { +void +Session::dump_hir (HIR::Crate &crate) const +{ std::ofstream out; - out.open(kHIRDumpFile); - if (out.fail()) { - rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", kHIRDumpFile); - return; - } + out.open (kHIRDumpFile); + if (out.fail ()) + { + rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored", + kHIRDumpFile); + return; + } - out << crate.as_string(); - out.close(); + out << crate.as_string (); + out.close (); } -void Session::dump_hir_pretty(HIR::Crate &crate) const { +void +Session::dump_hir_pretty (HIR::Crate &crate) const +{ std::ofstream out; - out.open(kHIRPrettyDumpFile); - if (out.fail()) { - rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", - kHIRPrettyDumpFile); - return; - } + out.open (kHIRPrettyDumpFile); + if (out.fail ()) + { + rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored", + kHIRPrettyDumpFile); + return; + } - HIR::Dump(out).go(crate); - out.close(); + HIR::Dump (out).go (crate); + out.close (); } // imports -NodeId Session::load_extern_crate(const std::string &crate_name, - location_t locus) { +NodeId +Session::load_extern_crate (const std::string &crate_name, location_t locus) +{ // has it already been loaded? CrateNum found_crate_num = UNKNOWN_CRATENUM; - bool found = mappings->lookup_crate_name(crate_name, found_crate_num); - if (found) { - NodeId resolved_node_id = UNKNOWN_NODEID; - bool resolved = - mappings->crate_num_to_nodeid(found_crate_num, resolved_node_id); - rust_assert(resolved); - - return resolved_node_id; - } + bool found = mappings->lookup_crate_name (crate_name, found_crate_num); + if (found) + { + NodeId resolved_node_id = UNKNOWN_NODEID; + bool resolved + = mappings->crate_num_to_nodeid (found_crate_num, resolved_node_id); + rust_assert (resolved); + + return resolved_node_id; + } std::string relative_import_path = ""; std::string import_name = crate_name; // The path to the extern crate might have been specified by the user using // -frust-extern - auto cli_extern_crate = extern_crates.find(crate_name); + auto cli_extern_crate = extern_crates.find (crate_name); std::pair<std::unique_ptr<Import::Stream>, std::vector<ProcMacro::Procmacro>> - package_result; - if (cli_extern_crate != extern_crates.end()) { - auto path = cli_extern_crate->second; - package_result = Import::try_package_in_directory(path, locus); - } else { - package_result = - Import::open_package(import_name, locus, relative_import_path); - } - - auto stream = std::move(package_result.first); - auto proc_macros = std::move(package_result.second); - - if (stream == NULL // No stream and - && proc_macros.empty()) // no proc macros - { - rust_error_at(locus, "failed to locate crate %<%s%>", import_name.c_str()); - return UNKNOWN_NODEID; - } - - auto extern_crate = - stream == nullptr - ? Imports::ExternCrate(crate_name, - proc_macros) // Import proc macros - : Imports::ExternCrate(*stream); // Import from stream - if (stream != nullptr) { - bool ok = extern_crate.load(locus); - if (!ok) { - rust_error_at(locus, "failed to load crate metadata"); + package_result; + if (cli_extern_crate != extern_crates.end ()) + { + auto path = cli_extern_crate->second; + package_result = Import::try_package_in_directory (path, locus); + } + else + { + package_result + = Import::open_package (import_name, locus, relative_import_path); + } + + auto stream = std::move (package_result.first); + auto proc_macros = std::move (package_result.second); + + if (stream == NULL // No stream and + && proc_macros.empty ()) // no proc macros + { + rust_error_at (locus, "failed to locate crate %<%s%>", + import_name.c_str ()); return UNKNOWN_NODEID; } - } + + auto extern_crate + = stream == nullptr + ? Imports::ExternCrate (crate_name, + proc_macros) // Import proc macros + : Imports::ExternCrate (*stream); // Import from stream + if (stream != nullptr) + { + bool ok = extern_crate.load (locus); + if (!ok) + { + rust_error_at (locus, "failed to load crate metadata"); + return UNKNOWN_NODEID; + } + } // ensure the current vs this crate name don't collide - const std::string current_crate_name = mappings->get_current_crate_name(); - if (current_crate_name.compare(extern_crate.get_crate_name()) == 0) { - rust_error_at(locus, "current crate name %<%s%> collides with this", - current_crate_name.c_str()); - return UNKNOWN_NODEID; - } + const std::string current_crate_name = mappings->get_current_crate_name (); + if (current_crate_name.compare (extern_crate.get_crate_name ()) == 0) + { + rust_error_at (locus, "current crate name %<%s%> collides with this", + current_crate_name.c_str ()); + return UNKNOWN_NODEID; + } // setup mappings - CrateNum saved_crate_num = mappings->get_current_crate(); - CrateNum crate_num = - mappings->get_next_crate_num(extern_crate.get_crate_name()); - mappings->set_current_crate(crate_num); + CrateNum saved_crate_num = mappings->get_current_crate (); + CrateNum crate_num + = mappings->get_next_crate_num (extern_crate.get_crate_name ()); + mappings->set_current_crate (crate_num); // then lets parse this as a 2nd crate - Lexer lex(extern_crate.get_metadata(), linemap); - Parser<Lexer> parser(lex); - std::unique_ptr<AST::Crate> metadata_crate = parser.parse_crate(); + Lexer lex (extern_crate.get_metadata (), linemap); + Parser<Lexer> parser (lex); + std::unique_ptr<AST::Crate> metadata_crate = parser.parse_crate (); - AST::Crate &parsed_crate = - mappings->insert_ast_crate(std::move(metadata_crate), crate_num); + AST::Crate &parsed_crate + = mappings->insert_ast_crate (std::move (metadata_crate), crate_num); std::vector<AttributeProcMacro> attribute_macros; std::vector<CustomDeriveProcMacro> derive_macros; std::vector<BangProcMacro> bang_macros; - for (auto ¯o : extern_crate.get_proc_macros()) { - switch (macro.tag) { - case ProcMacro::CUSTOM_DERIVE: - derive_macros.push_back(macro.payload.custom_derive); - break; - case ProcMacro::ATTR: - attribute_macros.push_back(macro.payload.attribute); - break; - case ProcMacro::BANG: - bang_macros.push_back(macro.payload.bang); - break; - default: - gcc_unreachable(); + for (auto ¯o : extern_crate.get_proc_macros ()) + { + switch (macro.tag) + { + case ProcMacro::CUSTOM_DERIVE: + derive_macros.push_back (macro.payload.custom_derive); + break; + case ProcMacro::ATTR: + attribute_macros.push_back (macro.payload.attribute); + break; + case ProcMacro::BANG: + bang_macros.push_back (macro.payload.bang); + break; + default: + gcc_unreachable (); + } } - } - mappings->insert_attribute_proc_macros(crate_num, attribute_macros); - mappings->insert_bang_proc_macros(crate_num, bang_macros); - mappings->insert_derive_proc_macros(crate_num, derive_macros); + mappings->insert_attribute_proc_macros (crate_num, attribute_macros); + mappings->insert_bang_proc_macros (crate_num, bang_macros); + mappings->insert_derive_proc_macros (crate_num, derive_macros); // name resolve it - Resolver::NameResolution::Resolve(parsed_crate); + Resolver::NameResolution::Resolve (parsed_crate); // perform hir lowering - std::unique_ptr<HIR::Crate> lowered = HIR::ASTLowering::Resolve(parsed_crate); - HIR::Crate &hir = mappings->insert_hir_crate(std::move(lowered)); + std::unique_ptr<HIR::Crate> lowered + = HIR::ASTLowering::Resolve (parsed_crate); + HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered)); // perform type resolution - Resolver::TypeResolution::Resolve(hir); + Resolver::TypeResolution::Resolve (hir); // always restore the crate_num - mappings->set_current_crate(saved_crate_num); + mappings->set_current_crate (saved_crate_num); - return parsed_crate.get_node_id(); + return parsed_crate.get_node_id (); } // -void TargetOptions::dump_target_options() const { +void +TargetOptions::dump_target_options () const +{ std::ofstream out; - out.open(kTargetOptionsDumpFile); - if (out.fail()) { - rust_error_at(UNKNOWN_LOCATION, "cannot open %s:%m; ignored", - kTargetOptionsDumpFile); - return; - } + out.open (kTargetOptionsDumpFile); + if (out.fail ()) + { + rust_error_at (UNKNOWN_LOCATION, "cannot open %s:%m; ignored", + kTargetOptionsDumpFile); + return; + } - if (features.empty()) { - out << "No target options available!\n"; - } + if (features.empty ()) + { + out << "No target options available!\n"; + } - for (const auto &pairs : features) { - for (const auto &value : pairs.second) { - if (value.has_value()) - out << pairs.first + ": \"" + value.value() + "\"\n"; - else - out << pairs.first + "\n"; + for (const auto &pairs : features) + { + for (const auto &value : pairs.second) + { + if (value.has_value ()) + out << pairs.first + ": \"" + value.value () + "\"\n"; + else + out << pairs.first + "\n"; + } } - } - out.close(); + out.close (); } -void TargetOptions::init_derived_values() { +void +TargetOptions::init_derived_values () +{ // enable derived values based on target families - if (has_key_value_pair("target_family", "unix")) - insert_key("unix"); - if (has_key_value_pair("target_family", "windows")) - insert_key("windows"); + if (has_key_value_pair ("target_family", "unix")) + insert_key ("unix"); + if (has_key_value_pair ("target_family", "windows")) + insert_key ("windows"); // implicitly enable features - this should not be required in general - if (has_key_value_pair("target_feature", "aes")) - enable_implicit_feature_reqs("aes"); - if (has_key_value_pair("target_feature", "avx")) - enable_implicit_feature_reqs("sse4.2"); - if (has_key_value_pair("target_feature", "avx2")) - enable_implicit_feature_reqs("avx"); - if (has_key_value_pair("target_feature", "pclmulqdq")) - enable_implicit_feature_reqs("sse2"); - if (has_key_value_pair("target_feature", "sha")) - enable_implicit_feature_reqs("sse2"); - if (has_key_value_pair("target_feature", "sse2")) - enable_implicit_feature_reqs("sse"); - if (has_key_value_pair("target_feature", "sse3")) - enable_implicit_feature_reqs("sse2"); - if (has_key_value_pair("target_feature", "sse4.1")) - enable_implicit_feature_reqs("sse3"); - if (has_key_value_pair("target_feature", "sse4.2")) - enable_implicit_feature_reqs("sse4.1"); - if (has_key_value_pair("target_feature", "ssse3")) - enable_implicit_feature_reqs("sse3"); + if (has_key_value_pair ("target_feature", "aes")) + enable_implicit_feature_reqs ("aes"); + if (has_key_value_pair ("target_feature", "avx")) + enable_implicit_feature_reqs ("sse4.2"); + if (has_key_value_pair ("target_feature", "avx2")) + enable_implicit_feature_reqs ("avx"); + if (has_key_value_pair ("target_feature", "pclmulqdq")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sha")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sse2")) + enable_implicit_feature_reqs ("sse"); + if (has_key_value_pair ("target_feature", "sse3")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sse4.1")) + enable_implicit_feature_reqs ("sse3"); + if (has_key_value_pair ("target_feature", "sse4.2")) + enable_implicit_feature_reqs ("sse4.1"); + if (has_key_value_pair ("target_feature", "ssse3")) + enable_implicit_feature_reqs ("sse3"); } -void TargetOptions::enable_implicit_feature_reqs(std::string feature) { +void +TargetOptions::enable_implicit_feature_reqs (std::string feature) +{ if (feature == "aes") - enable_implicit_feature_reqs("sse2"); + enable_implicit_feature_reqs ("sse2"); else if (feature == "avx") - enable_implicit_feature_reqs("sse4.2"); + enable_implicit_feature_reqs ("sse4.2"); else if (feature == "avx2") - enable_implicit_feature_reqs("avx"); + enable_implicit_feature_reqs ("avx"); else if (feature == "fma") - enable_implicit_feature_reqs("avx"); + enable_implicit_feature_reqs ("avx"); else if (feature == "pclmulqdq") - enable_implicit_feature_reqs("sse2"); + enable_implicit_feature_reqs ("sse2"); else if (feature == "sha") - enable_implicit_feature_reqs("sse2"); + enable_implicit_feature_reqs ("sse2"); else if (feature == "sse2") - enable_implicit_feature_reqs("sse"); + enable_implicit_feature_reqs ("sse"); else if (feature == "sse3") - enable_implicit_feature_reqs("sse2"); + enable_implicit_feature_reqs ("sse2"); else if (feature == "sse4.1") - enable_implicit_feature_reqs("sse3"); + enable_implicit_feature_reqs ("sse3"); else if (feature == "sse4.2") - enable_implicit_feature_reqs("sse4.1"); + enable_implicit_feature_reqs ("sse4.1"); else if (feature == "ssse3") - enable_implicit_feature_reqs("sse3"); + enable_implicit_feature_reqs ("sse3"); - if (!has_key_value_pair("target_feature", feature)) { - insert_key_value_pair("target_feature", feature); + if (!has_key_value_pair ("target_feature", feature)) + { + insert_key_value_pair ("target_feature", feature); - rust_debug("had to implicitly enable feature '%s'!", feature.c_str()); - } + rust_debug ("had to implicitly enable feature '%s'!", feature.c_str ()); + } } // NOTEs: @@ -1180,32 +1324,34 @@ void TargetOptions::enable_implicit_feature_reqs(std::string feature) { #if CHECKING_P namespace selftest { -void rust_crate_name_validation_test(void) { - auto error = Rust::Error(UNDEF_LOCATION, std::string()); - ASSERT_TRUE(Rust::validate_crate_name("example", error)); - ASSERT_TRUE(Rust::validate_crate_name("abcdefg_1234", error)); - ASSERT_TRUE(Rust::validate_crate_name("1", error)); - ASSERT_TRUE(Rust::validate_crate_name("クレート", error)); - ASSERT_TRUE(Rust::validate_crate_name("Sōkrátēs", error)); - ASSERT_TRUE(Rust::validate_crate_name("惊吓", error)); +void +rust_crate_name_validation_test (void) +{ + auto error = Rust::Error (UNDEF_LOCATION, std::string ()); + ASSERT_TRUE (Rust::validate_crate_name ("example", error)); + ASSERT_TRUE (Rust::validate_crate_name ("abcdefg_1234", error)); + ASSERT_TRUE (Rust::validate_crate_name ("1", error)); + ASSERT_TRUE (Rust::validate_crate_name ("クレート", error)); + ASSERT_TRUE (Rust::validate_crate_name ("Sōkrátēs", error)); + ASSERT_TRUE (Rust::validate_crate_name ("惊吓", error)); // NOTE: - is not allowed in the crate name ... - ASSERT_FALSE(Rust::validate_crate_name("abcdefg-1234", error)); - ASSERT_FALSE(Rust::validate_crate_name("a+b", error)); - ASSERT_FALSE(Rust::validate_crate_name("/a+b/", error)); - ASSERT_FALSE(Rust::validate_crate_name("😸++", error)); - ASSERT_FALSE(Rust::validate_crate_name("∀", error)); + ASSERT_FALSE (Rust::validate_crate_name ("abcdefg-1234", error)); + ASSERT_FALSE (Rust::validate_crate_name ("a+b", error)); + ASSERT_FALSE (Rust::validate_crate_name ("/a+b/", error)); + ASSERT_FALSE (Rust::validate_crate_name ("😸++", error)); + ASSERT_FALSE (Rust::validate_crate_name ("∀", error)); /* Tests for crate name inference */ - ASSERT_EQ(Rust::infer_crate_name("c.rs"), "c"); + ASSERT_EQ (Rust::infer_crate_name ("c.rs"), "c"); // NOTE: ... but - is allowed when in the filename - ASSERT_EQ(Rust::infer_crate_name("a-b.rs"), "a_b"); - ASSERT_EQ(Rust::infer_crate_name("book.rs.txt"), "book.rs"); + ASSERT_EQ (Rust::infer_crate_name ("a-b.rs"), "a_b"); + ASSERT_EQ (Rust::infer_crate_name ("book.rs.txt"), "book.rs"); #if defined(HAVE_DOS_BASED_FILE_SYSTEM) - ASSERT_EQ(Rust::infer_crate_name("a\\c\\a-b.rs"), "a_b"); + ASSERT_EQ (Rust::infer_crate_name ("a\\c\\a-b.rs"), "a_b"); #else - ASSERT_EQ(Rust::infer_crate_name("a/c/a-b.rs"), "a_b"); + ASSERT_EQ (Rust::infer_crate_name ("a/c/a-b.rs"), "a_b"); #endif } } // namespace selftest |